reworked pass1->pass2 scheduling
[swftools.git] / lib / as3 / compiler.c
1 /* compiler.h
2
3    Compiler for parsing Flash2 AVM2 ABC Actionscript
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2008/2009 Matthias Kramm <kramm@quiss.org>
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23
24 #include "tokenizer.h"
25 #include "files.h"
26 #include "parser.h"
27 #include "parser.tab.h"
28 #include "compiler.h"
29 #include "../os.h"
30 #ifdef HAVE_SYS_STAT_H
31 #include <sys/stat.h>
32 #endif
33 #ifdef HAVE_DIRENT_H
34 #include <dirent.h>
35 #endif
36
37 /* flex/bison definitions */
38 extern int a3_parse();
39 extern int as3_lex();
40 extern int as3_lex_destroy();
41
42 void as3_setverbosity(int level)
43 {
44     as3_verbosity=level;
45 }
46 void as3_add_include_dir(char*dir)
47 {
48     add_include_dir(dir);
49 }
50
51 static char registry_initialized = 0;
52 static char parser_initialized = 0;
53
54 //#define STORE_TOKENS
55
56 //#define DEBUG
57 #define DEBUG if(0)
58
59 #ifdef STORE_TOKENS
60 static mem_t tokens;
61 #endif
62
63 int a3_lex()
64 {
65     as3_tokencount++;
66 #ifdef STORE_TOKENS
67     if(as3_pass==1) {
68         int token = as3_lex();
69         /* FIXME: current_file needs to be stored, too */
70         mem_put(&tokens, &token, sizeof(token));
71         mem_put(&tokens, &a3_lval, sizeof(a3_lval));
72         mem_put(&tokens, &current_line, sizeof(current_line));
73         mem_put(&tokens, &current_column, sizeof(current_column));
74         return token;
75     } else {
76         int token;
77         mem_get(&tokens, &token, sizeof(token));
78         mem_get(&tokens, &a3_lval, sizeof(a3_lval));
79         mem_get(&tokens, &current_line, sizeof(current_line));
80         mem_get(&tokens, &current_column, sizeof(current_column));
81         return token;
82     }
83 #else
84     return as3_lex();
85 #endif
86 }
87
88 typedef struct _compile_list {
89     const char*name;
90     const char*filename;
91     struct _compile_list*next;
92 } compile_list_t;
93 static compile_list_t*compile_list=0;
94
95 static void as3_parse_file_or_array(int pass, const char*name, const char*filename, const void*mem, int length)
96 {
97     if(!registry_initialized) {
98         registry_initialized = 1;
99         registry_init();
100     }
101     if(!parser_initialized) {
102         parser_initialized = 1;
103         initialize_parser();
104 #if defined(STORE_TOKENS)
105         mem_init(&tokens);
106 #endif
107     }
108     as3_pass=pass;
109
110     FILE*fi = 0;
111     if(filename) {
112         if(as3_pass==1 && !mem) {
113             compile_list_t*c = rfx_calloc(sizeof(compile_list_t));
114             c->next = compile_list;
115             c->name = strdup(name);
116             c->filename = strdup(filename);
117             compile_list = c;
118         }
119         DEBUG printf("[pass %d] parse file %s %s\n", pass, name, filename);
120         fi = enter_file2(name, filename, 0);
121         as3_file_input(fi);
122     } else {
123         DEBUG printf("[pass %d] parse bytearray %s (%d bytes)\n", pass, name, length);
124         enter_file(name, name, 0);
125         as3_buffer_input((void*)mem, length);
126     }
127
128     as3_tokencount=0;
129     initialize_file(name, filename);
130     a3_parse();
131     as3_lex_destroy();
132     finish_file();
133 }
134
135 typedef struct _scheduled_file {
136     char*name;
137     char*filename;
138     struct _scheduled_file*next;
139 } scheduled_file_t;
140
141 static scheduled_file_t*scheduled=0;
142 dict_t*scheduled_dict=0;
143
144 void as3_parse_scheduled(int pass)
145 {
146     DEBUG printf("[pass %d] parse scheduled\n", pass);
147
148     while(scheduled) {
149         scheduled_file_t*s = scheduled;
150         scheduled = 0;
151         while(s) {
152             scheduled_file_t*old = s;
153             as3_parse_file_or_array(pass, s->name, s->filename, 0,0);
154             s = s->next;
155
156             free(old->filename);
157             free(old->name);
158             old->filename = old->name = 0;
159             free(old);
160         }
161     }
162     if(scheduled_dict) {
163         dict_destroy(scheduled_dict);
164         scheduled_dict=0;
165     }
166 }
167
168 void as3_schedule_file(const char*name, const char*filename) 
169 {
170     if(!scheduled_dict) {
171         scheduled_dict = dict_new();
172     }
173
174     filename = normalize_path(filename);
175     
176     if(dict_contains(scheduled_dict, filename)) {
177         return; //already processed
178     } else {
179         dict_put(scheduled_dict, filename, 0);
180     }
181     DEBUG printf("[pass %d] schedule %s %s\n", as3_pass, name, filename);
182
183     NEW(scheduled_file_t, f);
184     f->name = strdup(name);
185     f->filename = strdup(filename);
186     f->next = scheduled; // dfs
187     scheduled = f;
188 }
189
190 void as3_parse_list()
191 {
192     while(compile_list) {
193         as3_parse_file_or_array(2, compile_list->name, compile_list->filename, 0,0);
194         compile_list = compile_list->next;
195     }
196 }
197
198 void as3_parse_bytearray(const char*name, const void*mem, int length)
199 {
200     as3_pass = 1;
201     as3_parse_file_or_array(1, name, 0, mem, length);
202     as3_parse_scheduled(1);
203     
204     as3_pass = 2;
205     as3_parse_file_or_array(2, name, 0, mem, length);
206     as3_parse_list();
207 }
208
209 void as3_parse_file(const char*filename) 
210 {
211     char*fullfilename = find_file(filename, 1);
212     if(!fullfilename)
213         return; // not found
214
215     compile_list = 0;
216     as3_pass = 1;
217     as3_parse_file_or_array(1, filename, fullfilename, 0,0);
218     as3_parse_scheduled(1);
219
220     as3_pass = 2;
221     as3_parse_list();
222
223     free(fullfilename);
224 }
225
226 void as3_parse_directory(const char*dir)
227 {
228     compile_list = 0;
229     as3_pass=1;
230     as3_schedule_directory(dir);
231     if(!scheduled)
232         as3_warning("Directory %s doesn't contain any ActionScript files", dir);
233     as3_parse_scheduled(1);
234
235     as3_pass=2;
236     as3_parse_list();
237 }
238
239 char as3_schedule_directory(const char*dirname)
240 {
241     DEBUG printf("[pass %d] schedule directory %s\n", as3_pass, dirname);
242     char ok=0;
243 #ifdef HAVE_DIRENT_H
244     include_dir_t*i = current_include_dirs;
245     while(i) {
246         char*fulldirname = concat_paths(i->path, dirname);
247         DEBUG printf("[pass %d] ... %s\n", as3_pass, fulldirname);
248         DIR*dir = opendir(fulldirname);
249         if(dir) {
250             ok = 1;
251             struct dirent*ent;
252             while(1) {
253                 ent = readdir(dir);
254                 if (!ent) 
255                     break;
256                 char*name = ent->d_name;
257                 char type = 0;
258                 if(!name) continue;
259                 int l=strlen(name);
260                 if(l<4)
261                     continue;
262                 if(strncasecmp(&name[l-3], ".as", 3)) 
263                     continue;
264                 char*fullfilename = concatPaths(fulldirname, name);
265                 as3_schedule_file(name, fullfilename);
266                 free(fullfilename);
267             }
268         }
269         free(fulldirname);
270         i = i->next;
271     }
272 #endif
273     return ok;
274 }
275
276 void as3_schedule_package(const char*package)
277 {
278     DEBUG printf("[pass %d] schedule package %s\n", as3_pass, package);
279     char*dirname = strdup(package);
280     int s=0;
281     while(dirname[s]) {
282         if(dirname[s]=='.') dirname[s]='/';
283         s++;
284     };
285     if(!as3_schedule_directory(dirname))
286         as3_softwarning("Could not find package %s in file system", package);
287 }
288
289 static void schedule_class(const char*package, const char*cls, char error)
290 {
291     if(error) {
292         DEBUG printf("[pass %d] schedule class %s.%s\n",  as3_pass, package, cls);
293     }
294     if(!cls) {
295         as3_schedule_package(package);
296         return;
297     }
298     int l1 = package?strlen(package):0;
299     int l2 = cls?strlen(cls):0;
300     char*filename = malloc(l1+l2+5);
301     int s=0,t=0;
302     while(package[s]) {
303         if(package[s]=='.')
304             filename[t++]='/';
305         else
306             filename[t++] = package[s];
307         s++;
308     }
309     if(t)
310         filename[t++] = '/';
311
312     strcpy(filename+t, cls);
313     strcpy(filename+t+l2, ".as");
314     char*f=0;
315     if(!(f=find_file(filename, error))) {
316         int i;
317         /* try lower case filename (not packagename!), too */
318         for(i=t;i<t+l2;i++) {
319             if(filename[i]>='A' && filename[i]<='Z')
320                 filename[i] += 'a'-'A';
321         }
322         if(!(f=find_file(filename, error))) {
323             if(error) {
324                 strcpy(filename+t, cls);
325                 strcpy(filename+t+l2, ".as");
326                 as3_warning("Could not open file %s", filename);
327             }
328             return;
329         }
330     }
331     as3_schedule_file(filename, f);
332 }
333
334 void as3_schedule_class(const char*package, const char*cls)
335 {
336     schedule_class(package, cls, 1);
337 }
338
339 void as3_schedule_class_noerror(const char*package, const char*cls)
340 {
341     schedule_class(package, cls, 0);
342 }
343
344
345 static void*as3code = 0;
346 void* as3_getcode()
347 {
348     if(parser_initialized) {
349         parser_initialized = 0;
350         as3code = finish_parser();
351     }
352     return as3code;
353 }
354 char* as3_getglobalclass()
355 {
356     return as3_globalclass;
357 }
358
359 void as3_destroy() 
360 {
361     if(parser_initialized) {
362         parser_initialized = 0;
363         swf_FreeABC(finish_parser());
364 #ifdef STORE_TOKENS
365         mem_clear(&tokens);
366 #endif
367     }
368     if(as3_globalclass) {
369         free(as3_globalclass);as3_globalclass=0;
370     }
371 }
372