added rollbacking functionality to trier (for namespaces)
[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 int a3_lex()
60 {
61     as3_tokencount++;
62     return as3_lex();
63 }
64
65 typedef struct _compile_list {
66     const char*name;
67     const char*filename;
68     struct _compile_list*next;
69 } compile_list_t;
70 static compile_list_t*compile_list=0;
71
72 static void as3_parse_file_or_array(const char*name, const char*filename, const void*mem, int length)
73 {
74     if(!registry_initialized) {
75         registry_initialized = 1;
76         registry_init();
77     }
78     if(!parser_initialized) {
79         parser_initialized = 1;
80         initialize_parser();
81     }
82
83     FILE*fi = 0;
84     if(filename) {
85         if(as3_pass==1 && !mem) {
86             // record the fact that we compiled this file
87             compile_list_t*c = rfx_calloc(sizeof(compile_list_t));
88             c->next = compile_list;
89             c->name = strdup(name);
90             c->filename = strdup(filename);
91             compile_list = c;
92         }
93         DEBUG printf("[pass %d] parse file %s %s\n", as3_pass, name, filename);
94         fi = enter_file2(name, filename, 0);
95         as3_file_input(fi);
96     } else {
97         DEBUG printf("[pass %d] parse bytearray %s (%d bytes)\n", as3_pass, name, length);
98         enter_file(name, name, 0);
99         as3_buffer_input((void*)mem, length);
100     }
101
102     as3_tokencount=0;
103     initialize_file(name, filename);
104     a3_parse();
105     as3_lex_destroy();
106     finish_file();
107 }
108
109 typedef struct _scheduled_file {
110     char*name;
111     char*filename;
112     struct _scheduled_file*next;
113 } scheduled_file_t;
114
115 static scheduled_file_t*scheduled=0;
116 dict_t*scheduled_dict=0;
117
118 void as3_parse_scheduled()
119 {
120     DEBUG printf("[pass %d] parse scheduled\n", as3_pass);
121
122     while(scheduled) {
123         scheduled_file_t*s = scheduled;
124         scheduled = 0;
125         while(s) {
126             scheduled_file_t*old = s;
127             as3_parse_file_or_array(s->name, s->filename, 0,0);
128             s = s->next;
129
130             free(old->filename);
131             free(old->name);
132             old->filename = old->name = 0;
133             free(old);
134         }
135     }
136     if(scheduled_dict) {
137         dict_destroy(scheduled_dict);
138         scheduled_dict=0;
139     }
140 }
141
142 void as3_schedule_file(const char*name, const char*filename) 
143 {
144     if(!scheduled_dict) {
145         scheduled_dict = dict_new();
146     }
147
148     filename = normalize_path(filename);
149     
150     if(dict_contains(scheduled_dict, filename)) {
151         return; //already processed
152     } else {
153         dict_put(scheduled_dict, filename, 0);
154     }
155     DEBUG printf("[pass %d] schedule %s %s\n", as3_pass, name, filename);
156
157     NEW(scheduled_file_t, f);
158     f->name = strdup(name);
159     f->filename = strdup(filename);
160     f->next = scheduled; // dfs
161     scheduled = f;
162 }
163
164 void as3_parse_list()
165 {
166     while(compile_list) {
167         as3_parse_file_or_array(compile_list->name, compile_list->filename, 0,0);
168         compile_list = compile_list->next;
169     }
170 }
171
172 void as3_parse_bytearray(const char*name, const void*mem, int length)
173 {
174     as3_pass = 1;
175     as3_parse_file_or_array(name, 0, mem, length);
176     as3_parse_scheduled();
177     
178     registry_resolve_all();
179     
180     as3_pass = 2;
181     as3_parse_file_or_array(name, 0, mem, length);
182     as3_parse_list();
183 }
184
185 void as3_parse_file(const char*filename) 
186 {
187     char*fullfilename = find_file(filename, 1);
188     if(!fullfilename)
189         return; // not found
190
191     compile_list = 0;
192     as3_pass = 1;
193     as3_parse_file_or_array(filename, fullfilename, 0,0);
194     as3_parse_scheduled();
195     
196     registry_resolve_all();
197
198     as3_pass = 2;
199     as3_parse_list();
200
201     free(fullfilename);
202 }
203
204 void as3_parse_directory(const char*dir)
205 {
206     compile_list = 0;
207
208     as3_pass = 1;
209     as3_schedule_directory(dir);
210     if(!scheduled)
211         as3_warning("Directory %s doesn't contain any ActionScript files", dir);
212     as3_parse_scheduled();
213
214     registry_resolve_all();
215
216     as3_pass = 2;
217     as3_parse_list();
218 }
219
220 char as3_schedule_directory(const char*dirname)
221 {
222     DEBUG printf("[pass %d] schedule directory %s\n", as3_pass, dirname);
223     char ok=0;
224 #ifdef HAVE_DIRENT_H
225     include_dir_t*i = current_include_dirs;
226     while(i) {
227         char*fulldirname = concat_paths(i->path, dirname);
228         DEBUG printf("[pass %d] ... %s\n", as3_pass, fulldirname);
229         DIR*dir = opendir(fulldirname);
230         if(dir) {
231             ok = 1;
232             struct dirent*ent;
233             while(1) {
234                 ent = readdir(dir);
235                 if (!ent) 
236                     break;
237                 char*name = ent->d_name;
238                 char type = 0;
239                 if(!name) continue;
240                 int l=strlen(name);
241                 if(l<4)
242                     continue;
243                 if(strncasecmp(&name[l-3], ".as", 3)) 
244                     continue;
245                 char*fullfilename = concatPaths(fulldirname, name);
246                 as3_schedule_file(name, fullfilename);
247                 free(fullfilename);
248             }
249         }
250         free(fulldirname);
251         i = i->next;
252     }
253 #endif
254     return ok;
255 }
256
257 void as3_schedule_package(const char*package)
258 {
259     DEBUG printf("[pass %d] schedule package %s\n", as3_pass, package);
260     char*dirname = strdup(package);
261     int s=0;
262     while(dirname[s]) {
263         if(dirname[s]=='.') dirname[s]='/';
264         s++;
265     };
266     if(!as3_schedule_directory(dirname))
267         as3_softwarning("Could not find package %s in file system", package);
268 }
269
270 static void schedule_class(const char*package, const char*cls, char error)
271 {
272     if(error) {
273         DEBUG printf("[pass %d] schedule class %s.%s\n",  as3_pass, package, cls);
274     }
275     if(!cls) {
276         as3_schedule_package(package);
277         return;
278     }
279     int l1 = package?strlen(package):0;
280     int l2 = cls?strlen(cls):0;
281     char*filename = malloc(l1+l2+5);
282     int s=0,t=0;
283     while(package[s]) {
284         if(package[s]=='.')
285             filename[t++]='/';
286         else
287             filename[t++] = package[s];
288         s++;
289     }
290     if(t)
291         filename[t++] = '/';
292
293     strcpy(filename+t, cls);
294     strcpy(filename+t+l2, ".as");
295     char*f=0;
296     if(!(f=find_file(filename, error))) {
297         int i;
298         /* try lower case filename (not packagename!), too */
299         for(i=t;i<t+l2;i++) {
300             if(filename[i]>='A' && filename[i]<='Z')
301                 filename[i] += 'a'-'A';
302         }
303         if(!(f=find_file(filename, error))) {
304             if(error) {
305                 strcpy(filename+t, cls);
306                 strcpy(filename+t+l2, ".as");
307                 as3_warning("Could not open file %s", filename);
308             }
309             return;
310         }
311     }
312     as3_schedule_file(filename, f);
313 }
314
315 void as3_schedule_class(const char*package, const char*cls)
316 {
317     schedule_class(package, cls, 1);
318 }
319
320 void as3_schedule_class_noerror(const char*package, const char*cls)
321 {
322     schedule_class(package, cls, 0);
323 }
324
325
326 static void*as3code = 0;
327 void* as3_getcode()
328 {
329     if(parser_initialized) {
330         parser_initialized = 0;
331         as3code = finish_parser();
332     }
333     return as3code;
334 }
335 char* as3_getglobalclass()
336 {
337     return as3_globalclass;
338 }
339
340 void as3_destroy() 
341 {
342     if(parser_initialized) {
343         parser_initialized = 0;
344         swf_FreeABC(finish_parser());
345 #ifdef STORE_TOKENS
346         mem_clear(&tokens);
347 #endif
348     }
349     if(as3_globalclass) {
350         free(as3_globalclass);as3_globalclass=0;
351     }
352 }
353