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