fixed bug in recursive 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_DIRENT_H
31 #include <dirent.h>
32 #endif
33
34 /* flex/bison definitions */
35 extern int a3_parse();
36 extern int as3_lex();
37 extern int as3_lex_destroy();
38
39 void as3_setverbosity(int level)
40 {
41     as3_verbosity=level;
42 }
43 void as3_add_include_dir(char*dir)
44 {
45     add_include_dir(dir);
46 }
47
48 static char registry_initialized = 0;
49 static char parser_initialized = 0;
50
51 //#define STORE_TOKENS
52
53 #ifdef STORE_TOKENS
54 static mem_t tokens;
55 #endif
56
57 int a3_lex()
58 {
59     as3_tokencount++;
60 #ifdef STORE_TOKENS
61     if(as3_pass==1) {
62         int token = as3_lex();
63         /* FIXME: current_file needs to be stored, too */
64         mem_put(&tokens, &token, sizeof(token));
65         mem_put(&tokens, &a3_lval, sizeof(a3_lval));
66         mem_put(&tokens, &current_line, sizeof(current_line));
67         mem_put(&tokens, &current_column, sizeof(current_column));
68         return token;
69     } else {
70         int token;
71         mem_get(&tokens, &token, sizeof(token));
72         mem_get(&tokens, &a3_lval, sizeof(a3_lval));
73         mem_get(&tokens, &current_line, sizeof(current_line));
74         mem_get(&tokens, &current_column, sizeof(current_column));
75         return token;
76     }
77 #else
78     return as3_lex();
79 #endif
80 }
81
82 static void as3_parse_file_or_array(int pass, const char*name, const char*filename, void*mem, int length)
83 {
84     if(!registry_initialized) {
85         registry_initialized = 1;
86         registry_init();
87     }
88     if(!parser_initialized) {
89         parser_initialized = 1;
90         initialize_parser();
91 #if defined(STORE_TOKENS)
92         mem_init(&tokens);
93 #endif
94     }
95     as3_pass=pass;
96
97     FILE*fi = 0;
98     if(filename) {
99         //printf("[pass %d] parse file %s %s\n", pass, name, filename);
100         fi = enter_file2(name, filename, 0);
101         as3_file_input(fi);
102     } else {
103         //printf("[pass %d] parse bytearray %s (%d bytes)\n", pass, name, length);
104         enter_file(name, name, 0);
105         as3_buffer_input(mem, length);
106     }
107
108     as3_tokencount=0;
109     initialize_file(name, filename);
110     a3_parse();
111     as3_lex_destroy();
112     finish_file();
113 }
114
115 typedef struct _scheduled_file {
116     char*name;
117     char*filename;
118     struct _scheduled_file*next;
119 } scheduled_file_t;
120
121 static scheduled_file_t*scheduled=0;
122 dict_t*scheduled_dict=0;
123
124 void as3_parse_scheduled(int pass)
125 {
126     //printf("[pass %d] parse scheduled\n", pass);
127
128     while(scheduled) {
129         scheduled_file_t*s = scheduled;
130         scheduled = 0;
131         while(s) {
132             scheduled_file_t*old = s;
133             as3_parse_file_or_array(pass, s->name, s->filename, 0,0);
134             s = s->next;
135
136             free(old->filename);
137             free(old->name);
138             old->filename = old->name = 0;
139             free(old);
140         }
141     }
142     if(scheduled_dict) {
143         dict_destroy(scheduled_dict);
144         scheduled_dict=0;
145     }
146 }
147 void as3_schedule_file(const char*name, const char*filename) 
148 {
149     if(!scheduled_dict) 
150         scheduled_dict = dict_new();
151     
152     if(dict_contains(scheduled_dict, filename)) {
153         return; //already processed
154     } else {
155         dict_put(scheduled_dict, filename, 0);
156     }
157     //printf("[pass %d] schedule %s %s\n", as3_pass, name, filename);
158
159     NEW(scheduled_file_t, f);
160     f->name = strdup(name);
161     f->filename = strdup(filename);
162     f->next = scheduled; // dfs
163     scheduled = f;
164 }
165
166 void as3_parse_bytearray(const char*name, void*mem, int length)
167 {
168     as3_parse_file_or_array(1, name, 0, mem, length);
169     as3_parse_scheduled(1);
170     
171     as3_parse_file_or_array(2, name, 0, mem, length);
172     as3_parse_scheduled(2);
173 }
174
175 void as3_parse_file(const char*filename) 
176 {
177     char*fullfilename = find_file(filename);
178     if(!fullfilename)
179         return; // not found
180     
181     as3_parse_file_or_array(1, filename, fullfilename, 0,0);
182     as3_parse_scheduled(1);
183
184     as3_parse_file_or_array(2, filename, fullfilename, 0,0);
185     as3_parse_scheduled(2);
186
187     free(fullfilename);
188 }
189
190 void as3_parse_directory(const char*dir)
191 {
192     as3_pass=1;
193     as3_schedule_directory(dir);
194     as3_parse_scheduled(1);
195     as3_pass=2;
196     as3_schedule_directory(dir);
197     as3_parse_scheduled(2);
198 }
199
200 char as3_schedule_directory(const char*dirname)
201 {
202     char ok=0;
203 #ifdef HAVE_DIRENT_H
204     include_dir_t*i = current_include_dirs;
205     while(i) {
206         char*fulldirname = concatPaths(i->path, dirname);
207         DIR*dir = opendir(dirname);
208         if(dir) {
209             ok = 1;
210             struct dirent*ent;
211             while(1) {
212                 ent = readdir(dir);
213                 if (!ent) 
214                     break;
215                 char*name = ent->d_name;
216                 char type = 0;
217                 if(!name) continue;
218                 int l=strlen(name);
219                 if(l<4)
220                     continue;
221                 if(strncasecmp(&name[l-3], ".as", 3)) 
222                     continue;
223                 char*fullfilename = concatPaths(dirname, name);
224                 as3_schedule_file(name, fullfilename);
225                 free(fullfilename);
226             }
227         }
228         free(fulldirname);
229         i = i->next;
230     }
231 #endif
232     return ok;
233 }
234
235 void as3_schedule_package(const char*package)
236 {
237     char*dirname = strdup(package);
238     int s=0;
239     while(dirname[s]) {
240         if(dirname[s]=='.') dirname[s]='/';
241         s++;
242     };
243     if(!as3_schedule_directory(package))
244         as3_softwarning("Could not find package %s in file system", package);
245 }
246
247 void as3_schedule_class(const char*package, const char*cls)
248 {
249     if(!cls) {
250         as3_schedule_package(package);
251         return;
252     }
253     int l1 = package?strlen(package):0;
254     int l2 = cls?strlen(cls):0;
255     char*filename = malloc(l1+l2+5);
256     int s=0,t=0;
257     while(package[s]) {
258         if(package[s]=='.')
259             filename[t++]='/';
260         else
261             filename[t++] = package[s];
262         s++;
263     }
264     if(t)
265         filename[t++] = '/';
266
267     strcpy(filename+t, cls);
268     strcpy(filename+t+l2, ".as");
269     char*f=0;
270     if(!(f=find_file(filename))) {
271         int i;
272         /* try lower case filename (not packagename!), too */
273         for(i=t;i<t+l2;i++) {
274             if(filename[i]>='A' && filename[i]<='Z')
275                 filename[i] += 'a'-'A';
276         }
277         if(!(f=find_file(filename))) {
278             strcpy(filename+t, cls);
279             strcpy(filename+t+l2, ".as");
280             as3_warning("Could not open file %s", filename);
281             return;
282         }
283     }
284     as3_schedule_file(filename, f);
285 }
286
287 static void*as3code = 0;
288 void* as3_getcode()
289 {
290     if(parser_initialized) {
291         parser_initialized = 0;
292         as3code = finish_parser();
293     }
294     return as3code;
295 }
296 char* as3_getglobalclass()
297 {
298     return as3_globalclass;
299 }
300
301 void as3_destroy() 
302 {
303     if(parser_initialized) {
304         parser_initialized = 0;
305         swf_FreeABC(finish_parser());
306 #ifdef STORE_TOKENS
307         mem_clear(&tokens);
308 #endif
309     }
310     if(as3_globalclass) {
311         free(as3_globalclass);as3_globalclass=0;
312     }
313 }
314