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