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