701d49b5f4dd2e7daac86cf5118d7feb35c09380
[swftools.git] / lib / as3 / parser.y
1 /* parser.lex
2
3    Routines for compiling Flash2 AVM2 ABC Actionscript
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2008 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 <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
27 #include "abc.h"
28 #include "pool.h"
29 #include "files.h"
30 #include "tokenizer.h"
31 #include "registry.h"
32 #include "code.h"
33 #include "opcodes.h"
34 #include "compiler.h"
35
36 extern int a3_lex();
37
38 %}
39
40 //%glr-parser
41 //%expect-rr 1
42 %error-verbose
43
44 %union tokenunion {
45     enum yytokentype token;
46
47     classinfo_t*classinfo;
48     classinfo_list_t*classinfo_list;
49     slotinfo_t*slotinfo;
50     slotinfo_list_t*slotinfo_list;
51
52     int number_int;
53     unsigned int number_uint;
54     double number_float;
55     code_t*code;
56     typedcode_t value;
57     //typedcode_list_t*value_list;
58     codeandnumber_t value_list;
59     param_t* param;
60     params_t params;
61     string_t str;
62     char*id;
63     constant_t*constant;
64     for_start_t for_start;
65     abc_exception_t *exception;
66     regexp_t regexp;
67     modifiers_t flags;
68     namespace_decl_t* namespace_decl;
69     struct {
70         abc_exception_list_t *l;
71         code_t*finally;
72     } catch_list;
73 }
74
75
76 %token<id> T_IDENTIFIER T_NAMESPACE
77 %token<str> T_STRING
78 %token<regexp> T_REGEXP
79 %token<token> T_EMPTY
80 %token<number_int> T_INT
81 %token<number_uint> T_UINT
82 %token<number_uint> T_BYTE
83 %token<number_uint> T_SHORT
84 %token<number_float> T_FLOAT
85
86 %token<id> T_FOR "for"
87 %token<id> T_WHILE "while"
88 %token<id> T_DO "do"
89 %token<id> T_SWITCH "switch"
90
91 %token<token> KW_IMPLEMENTS "implements"
92 %token<token> KW_NAMESPACE "namespace"
93 %token<token> KW_PACKAGE "package"
94 %token<token> KW_PROTECTED "protected"
95 %token<token> KW_PUBLIC "public"
96 %token<token> KW_PRIVATE "private"
97 %token<token> KW_USE "use"
98 %token<token> KW_INTERNAL "internal"
99 %token<token> KW_NEW "new"
100 %token<token> KW_NATIVE "native"
101 %token<token> KW_FUNCTION "function"
102 %token<token> KW_FINALLY "finally"
103 %token<token> KW_UNDEFINED "undefined"
104 %token<token> KW_CONTINUE "continue"
105 %token<token> KW_CLASS "class"
106 %token<token> KW_CONST "const"
107 %token<token> KW_CATCH "catch"
108 %token<token> KW_CASE "case"
109 %token<token> KW_SET "set"
110 %token<token> KW_VOID "void"
111 %token<token> KW_THROW "throw"
112 %token<token> KW_STATIC "static"
113 %token<token> KW_WITH "with"
114 %token<token> KW_INSTANCEOF "instanceof"
115 %token<token> KW_IMPORT "import"
116 %token<token> KW_RETURN "return"
117 %token<token> KW_TYPEOF "typeof"
118 %token<token> KW_INTERFACE "interface"
119 %token<token> KW_NULL "null"
120 %token<token> KW_VAR "var"
121 %token<token> KW_DYNAMIC "dynamic"
122 %token<token> KW_OVERRIDE "override"
123 %token<token> KW_FINAL "final"
124 %token<token> KW_EACH "each"
125 %token<token> KW_GET "get"
126 %token<token> KW_TRY "try"
127 %token<token> KW_SUPER "super"
128 %token<token> KW_EXTENDS "extends"
129 %token<token> KW_FALSE "false"
130 %token<token> KW_TRUE "true"
131 %token<token> KW_BOOLEAN "Boolean"
132 %token<token> KW_UINT "uint"
133 %token<token> KW_INT "int"
134 %token<token> KW_NUMBER "Number"
135 %token<token> KW_STRING "String"
136 %token<token> KW_DEFAULT "default"
137 %token<token> KW_DELETE "delete"
138 %token<token> KW_IF "if"
139 %token<token> KW_ELSE  "else"
140 %token<token> KW_BREAK   "break"
141 %token<token> KW_IS "is"
142 %token<token> KW_IN "in"
143 %token<token> KW_AS "as"
144
145 %token<token> T_DICTSTART "{ (dictionary)"
146 %token<token> T_EQEQ "=="
147 %token<token> T_EQEQEQ "==="
148 %token<token> T_NE "!="
149 %token<token> T_NEE "!=="
150 %token<token> T_LE "<="
151 %token<token> T_GE ">="
152 %token<token> T_ORBY "|=" 
153 %token<token> T_DIVBY "/=" 
154 %token<token> T_MODBY "%="
155 %token<token> T_MULBY "*="
156 %token<token> T_PLUSBY "+=" 
157 %token<token> T_MINUSBY "-="
158 %token<token> T_XORBY "^="
159 %token<token> T_SHRBY ">>="
160 %token<token> T_SHLBY "<<="
161 %token<token> T_USHRBY ">>>="
162 %token<token> T_OROR "||"
163 %token<token> T_ANDAND "&&"
164 %token<token> T_COLONCOLON "::"
165 %token<token> T_MINUSMINUS "--"
166 %token<token> T_PLUSPLUS "++"
167 %token<token> T_DOTDOT ".."
168 %token<token> T_DOTDOTDOT "..."
169 %token<token> T_SHL "<<"
170 %token<token> T_USHR ">>>"
171 %token<token> T_SHR ">>"
172
173 %type <for_start> FOR_START
174 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
175 %type <namespace_decl>  NAMESPACE_ID
176 %type <token> VARCONST
177 %type <code> CODE
178 %type <code> CODEPIECE CODE_STATEMENT
179 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
180 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
181 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
182 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
183 %type <exception> CATCH FINALLY
184 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
185 %type <code> CLASS_DECLARATION
186 %type <code> NAMESPACE_DECLARATION
187 %type <code> INTERFACE_DECLARATION
188 %type <code> VOIDEXPRESSION
189 %type <value> EXPRESSION NONCOMMAEXPRESSION
190 %type <value> MAYBEEXPRESSION
191 %type <value> E DELETE
192 %type <value> CONSTANT
193 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY 
194 %type <value> INNERFUNCTION
195 %type <code> USE_NAMESPACE
196 %type <code> FOR_INIT
197 %type <code> IMPORT
198 %type <classinfo> MAYBETYPE
199 %type <token> GETSET
200 %type <param> PARAM
201 %type <params> PARAM_LIST
202 %type <params> MAYBE_PARAM_LIST
203 %type <flags> MAYBE_MODIFIERS
204 %type <flags> MODIFIER_LIST
205 %type <flags> MODIFIER
206 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
207 %type <classinfo_list> IMPLEMENTS_LIST
208 %type <classinfo> EXTENDS CLASS_SPEC
209 %type <classinfo_list> EXTENDS_LIST
210
211 %type <classinfo> CLASS PACKAGEANDCLASS
212 %type <classinfo_list> CLASS_SPEC_LIST
213
214 %type <classinfo> TYPE
215 //%type <token> VARIABLE
216 %type <value> VAR_READ
217 %type <value> NEW
218 //%type <token> T_IDENTIFIER
219 %type <value> FUNCTIONCALL
220 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST WITH_HEAD
221
222 // precedence: from low to high
223
224 %left prec_none
225
226 %left below_semicolon
227 %left ';'
228 %left ','
229 %nonassoc below_assignment // for ?:, contrary to spec
230 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
231 %right '?' ':'
232 %left "||"
233 %left "&&"
234 %left '|'
235 %left '^'
236 %nonassoc '&'
237 %nonassoc "==" "!=" "===" "!=="
238 %nonassoc "is" "as" "in"
239 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
240 %left "<<" ">>" ">>>" 
241 %left below_minus
242 %left '-' '+'
243 %left '/' '*' '%'
244 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
245 %left "--" "++" 
246 %nonassoc below_curly
247
248 %left '('
249 %left new2
250 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
251
252 %left T_IDENTIFIER
253 %left above_identifier
254 %left below_else
255 %nonassoc "else"
256
257 // needed for "return" precedence:
258 %nonassoc T_STRING T_REGEXP
259 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
260 %nonassoc "false" "true" "null" "undefined" "super" "function"
261 %left above_function
262
263
264      
265 %{
266
267 static int a3_error(char*s)
268 {
269    syntaxerror("%s", s); 
270    return 0; //make gcc happy
271 }
272
273
274 static char* concat2(const char* t1, const char* t2)
275 {
276     int l1 = strlen(t1);
277     int l2 = strlen(t2);
278     char*text = malloc(l1+l2+1);
279     memcpy(text   , t1, l1);
280     memcpy(text+l1, t2, l2);
281     text[l1+l2] = 0;
282     return text;
283 }
284 static char* concat3(const char* t1, const char* t2, const char* t3)
285 {
286     int l1 = strlen(t1);
287     int l2 = strlen(t2);
288     int l3 = strlen(t3);
289     char*text = malloc(l1+l2+l3+1);
290     memcpy(text   , t1, l1);
291     memcpy(text+l1, t2, l2);
292     memcpy(text+l1+l2, t3, l3);
293     text[l1+l2+l3] = 0;
294     return text;
295 }
296
297 typedef struct _import {
298     char*package;
299 } import_t;
300
301 DECLARE_LIST(import);
302
303 DECLARE(methodstate);
304 DECLARE_LIST(methodstate);
305
306 typedef struct _classstate {
307     /* class data */
308     classinfo_t*info;
309     abc_class_t*abc;
310    
311     methodstate_t*init;
312     methodstate_t*static_init;
313     //code_t*init;
314     //code_t*static_init;
315
316     char has_constructor;
317 } classstate_t;
318
319 struct _methodstate {
320     /* method data */
321     methodinfo_t*info;
322     char has_exceptions;
323     char late_binding;
324     char is_constructor;
325     char has_super;
326     char is_global;
327     int variable_count;
328
329     dict_t*unresolved_variables;
330
331     char inner;
332     char uses_parent_function;
333     int uses_slots;
334     dict_t*slots;
335     int activation_var;
336
337     abc_method_t*abc;
338     int var_index; // for inner methods
339     int slot_index; // for inner methods
340     char is_a_slot; // for inner methods
341
342     code_t*header;
343
344     code_t*scope_code;
345     abc_exception_list_t*exceptions;
346     
347     methodstate_list_t*innerfunctions;
348 };
349
350 typedef struct _state {
351     struct _state*old;
352     int level;
353     
354     char*package;     
355     import_list_t*wildcard_imports;
356     dict_t*import_toplevel_packages;
357     dict_t*imports;
358
359     namespace_list_t*active_namespace_urls;
360     
361     char has_own_imports;
362     char new_vars; // e.g. transition between two functions
363   
364     classstate_t*cls;   
365     methodstate_t*method;
366
367     char*exception_name;
368
369     int switch_var;
370     
371     dict_t*vars;
372 } state_t;
373
374 typedef struct _global {
375     abc_file_t*file;
376     abc_script_t*init;
377     dict_t*token2info;
378     dict_t*file2token2info;
379 } global_t;
380
381 static global_t*global = 0;
382 static state_t* state = 0;
383
384 DECLARE_LIST(state);
385
386 #define MULTINAME(m,x) \
387     multiname_t m;\
388     namespace_t m##_ns;\
389     (x)->package; \
390     registry_fill_multiname(&m, &m##_ns, (slotinfo_t*)(x));
391                     
392 #define MEMBER_MULTINAME(m,f,n) \
393     multiname_t m;\
394     namespace_t m##_ns;\
395     if(f) { \
396         if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
397             m##_ns.name = ((slotinfo_t*)(f))->package; \
398         else \
399             m##_ns.name = ""; \
400         m.type = QNAME; \
401         m.ns = &m##_ns; \
402         m.namespace_set = 0; \
403         m.name = ((slotinfo_t*)(f))->name; \
404     } else { \
405         m.type = MULTINAME; \
406         m.ns =0; \
407         m.namespace_set = &nopackage_namespace_set; \
408         m.name = n; \
409     }
410
411 /* warning: list length of namespace set is undefined */
412 #define MULTINAME_LATE(m, access, package) \
413     namespace_t m##_ns = {access, package}; \
414     namespace_set_t m##_nsset; \
415     namespace_list_t m##_l;m##_l.next = 0; \
416     m##_nsset.namespaces = &m##_l; \
417     m##_nsset = m##_nsset; \
418     m##_l.namespace = &m##_ns; \
419     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
420
421 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
422 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
423 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
424 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
425 static namespace_list_t nl4 = {&ns4,0};
426 static namespace_list_t nl3 = {&ns3,&nl4};
427 static namespace_list_t nl2 = {&ns2,&nl3};
428 static namespace_list_t nl1 = {&ns1,&nl2};
429 static namespace_set_t nopackage_namespace_set = {&nl1};
430
431 static void new_state()
432 {
433     NEW(state_t, s);
434     state_t*oldstate = state;
435     if(state)
436         memcpy(s, state, sizeof(state_t)); //shallow copy
437     if(!s->imports) {
438         s->imports = dict_new();
439     }
440     if(!s->import_toplevel_packages) {
441         s->import_toplevel_packages = dict_new(); 
442     }
443     state = s;
444     state->level++;
445     state->has_own_imports = 0;    
446     state->vars = dict_new(); 
447     state->old = oldstate;
448     state->new_vars = 0;
449
450     trie_remember(active_namespaces);
451    
452     if(oldstate)
453         state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
454 }
455 static void state_has_imports()
456 {
457     state->wildcard_imports = list_clone(state->wildcard_imports);
458     state->imports = dict_clone(state->imports);
459     state->has_own_imports = 1;
460 }
461 static void import_toplevel(const char*package)
462 {
463     char* s = strdup(package);
464     while(1) {
465         dict_put(state->import_toplevel_packages, s, 0);
466         char*x = strrchr(s, '.');
467         if(!x)
468             break;
469         *x = 0;
470     }
471     free(s);
472 }
473
474 static void state_destroy(state_t*state)
475 {
476     if(state->has_own_imports) {
477         list_free(state->wildcard_imports);
478         dict_destroy(state->imports);state->imports=0;
479     }
480     if(state->imports && (!state->old || state->old->imports!=state->imports)) {
481         dict_destroy(state->imports);state->imports=0;
482     }
483     if(state->vars) {
484         int t;
485         for(t=0;t<state->vars->hashsize;t++) {
486             dictentry_t*e =state->vars->slots[t];
487             while(e) {
488                 free(e->data);e->data=0;
489                 e = e->next;
490             }
491         }
492         dict_destroy(state->vars);state->vars=0;
493     }
494     
495     list_free(state->active_namespace_urls)
496     state->active_namespace_urls = 0;
497     
498     free(state);
499 }
500
501 static void old_state()
502 {
503     trie_rollback(active_namespaces);
504
505     if(!state || !state->old)
506         syntaxerror("invalid nesting");
507     state_t*leaving = state;
508     
509     state = state->old;
510
511     if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
512         free(leaving->method);
513         leaving->method=0;
514     }
515     if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
516         free(leaving->cls);
517         leaving->cls=0;
518     }
519
520     state_destroy(leaving);
521 }
522
523 static code_t* method_header(methodstate_t*m);
524 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
525 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
526
527
528 static char* internal_filename_package = 0;
529 void initialize_file(char*filename)
530 {
531     if(state) {
532         syntaxerror("invalid call to initialize_file during parsing of another file");
533     }
534     
535     active_namespaces = trie_new();
536
537     new_state();
538     state->package = internal_filename_package = strdup(filename);
539     
540     global->token2info = dict_lookup(global->file2token2info, 
541                                      current_filename // use long version
542                                     );
543     if(!global->token2info) {
544         global->token2info = dict_new2(&ptr_type);
545         dict_put(global->file2token2info, current_filename, global->token2info);
546     }
547   
548     if(as3_pass==1) {
549         state->method = rfx_calloc(sizeof(methodstate_t));
550         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
551         state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
552     } else {
553         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
554         function_initvars(state->method, 0, 0, 1);
555         global->init = abc_initscript(global->file);
556     }
557 }
558
559 void finish_file()
560 {
561     if(!state || state->level!=1) {
562         syntaxerror("unexpected end of file in pass %d", as3_pass);
563     }
564
565     if(as3_pass==2) {
566         code_t*header = method_header(state->method);
567         code_t*c = wrap_function(header, 0, global->init->method->body->code);
568         global->init->method->body->code = c;
569         free(state->method);state->method=0;
570     }
571
572     //free(state->package);state->package=0; // used in registry
573     state_destroy(state);state=0;
574 }
575
576 void initialize_parser()
577 {
578     global = rfx_calloc(sizeof(global_t));
579     global->file = abc_file_new();
580     global->file->flags &= ~ABCFILE_LAZY;
581     global->file2token2info = dict_new();
582     global->token2info = 0;
583 }
584
585 void* finish_parser()
586 {
587     dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
588
589     global->token2info=0;
590
591     return global->file;
592 }
593
594
595 static void xx_scopetest() 
596 {
597     /* findpropstrict doesn't just return a scope object- it
598        also makes it "active" somehow. Push local_0 on the
599        scope stack and read it back with findpropstrict, it'll
600        contain properties like "trace". Trying to find the same
601        property on a "vanilla" local_0 yields only a "undefined" */
602     //c = abc_findpropstrict(c, "[package]::trace");
603     
604     /*c = abc_getlocal_0(c);
605     c = abc_findpropstrict(c, "[package]::trace");
606     c = abc_coerce_a(c);
607     c = abc_setlocal_1(c);
608
609     c = abc_pushbyte(c, 0);
610     c = abc_setlocal_2(c);
611    
612     code_t*xx = c = abc_label(c);
613     c = abc_findpropstrict(c, "[package]::trace");
614     c = abc_pushstring(c, "prop:");
615     c = abc_hasnext2(c, 1, 2);
616     c = abc_dup(c);
617     c = abc_setlocal_3(c);
618     c = abc_callpropvoid(c, "[package]::trace", 2);
619     c = abc_getlocal_3(c);
620     c = abc_kill(c, 3);
621     c = abc_iftrue(c,xx);*/
622 }
623
624 typedef struct _variable {
625     int index;
626     classinfo_t*type;
627     char init;
628     methodstate_t*is_inner_method;
629 } variable_t;
630
631 static variable_t* find_variable(state_t*s, char*name)
632 {
633     while(s) {
634         variable_t*v = 0;
635         v = dict_lookup(s->vars, name);
636         if(v) return v;
637         if(s->new_vars) break;
638         s = s->old;
639     }
640     return 0;
641 }
642 static variable_t* find_slot(state_t*s, const char*name)
643 {
644     if(s->method && s->method->slots)
645         return dict_lookup(s->method->slots, name);
646     return 0;
647 }
648
649 static variable_t* find_variable_safe(state_t*s, char*name)
650 {
651     variable_t* v = find_variable(s, name);
652     if(!v)
653         syntaxerror("undefined variable: %s", name);
654     return v;
655 }
656 static char variable_exists(char*name) 
657 {
658     return dict_contains(state->vars, name);
659 }
660 code_t*defaultvalue(code_t*c, classinfo_t*type);
661
662 static int alloc_local()
663 {
664     return state->method->variable_count++;
665 }
666
667 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
668 {
669     if(maybeslot) {
670         variable_t*v = find_slot(state, name);
671         if(v)
672             return v;
673     }
674
675     NEW(variable_t, v);
676     v->index = alloc_local();
677     v->type = type;
678     v->init = init;
679  
680     if(name) 
681         dict_put(state->vars, name, v);
682
683     return v;
684 }
685 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
686 {
687     return new_variable2(name, type, init, maybeslot)->index;
688 }
689
690 #define TEMPVARNAME "__as3_temp__"
691 static int gettempvar()
692 {
693     variable_t*v = find_variable(state, TEMPVARNAME);
694     if(v) 
695         return v->index;
696     return new_variable(TEMPVARNAME, 0, 0, 0);
697 }
698
699 code_t* var_block(code_t*body) 
700 {
701     code_t*c = 0;
702     code_t*k = 0;
703     int t;
704     int num=0;
705     for(t=0;t<state->vars->hashsize;t++) {
706         dictentry_t*e = state->vars->slots[t];
707         while(e) {
708             variable_t*v = (variable_t*)e->data;
709             if(v->type && v->init) {
710                 c = defaultvalue(c, v->type);
711                 c = abc_setlocal(c, v->index);
712                 k = abc_kill(k, v->index); 
713                 num++;
714             }
715             e = e->next;
716         }
717     }
718
719     if(k) {
720         code_t*x = body;
721         while(x) {
722             if(x->opcode== OPCODE___BREAK__ ||
723                x->opcode== OPCODE___CONTINUE__) {
724                /* link kill code before break/continue */
725                 code_t*e = code_dup(k);
726                 code_t*s = code_start(e);
727                 s->prev = x->prev;
728                 if(x->prev) {
729                     x->prev->next = s;
730                 }
731                 e->next = x;
732                 x->prev = e;
733             }
734             x = x->prev;
735         }
736     }
737     
738     c = code_append(c, body);
739     c = code_append(c, k);
740     return c;
741 }
742
743 void unknown_variable(char*name) 
744 {
745     if(!state->method->unresolved_variables)
746         state->method->unresolved_variables = dict_new();
747     if(!dict_contains(state->method->unresolved_variables, name))
748         dict_put(state->method->unresolved_variables, name, 0);
749 }
750
751 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
752
753 static void parsererror(const char*file, int line, const char*f)
754 {
755     syntaxerror("internal error in %s, %s:%d", f, file, line);
756 }
757
758    
759 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
760 {
761     if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
762         c = abc_getlocal_0(c);
763         c = abc_pushscope(c);
764     }
765     if(m->uses_slots) {
766         /* FIXME: this alloc_local() causes variable indexes to be
767            different in pass2 than in pass1 */
768         if(!m->activation_var)
769             m->activation_var = alloc_local();
770         if(init) {
771             c = abc_newactivation(c);
772             c = abc_dup(c);
773             c = abc_pushscope(c);
774             c = abc_setlocal(c, m->activation_var);
775         } else {
776             c = abc_getlocal(c, m->activation_var);
777             c = abc_pushscope(c);
778         }
779     }
780     return c;
781 }
782
783 static code_t* method_header(methodstate_t*m)
784 {
785     code_t*c = 0;
786
787     c = add_scope_code(c, m, 1);
788
789     methodstate_list_t*l = m->innerfunctions;
790     while(l) {
791         parserassert(l->methodstate->abc);
792         if(m->uses_slots && l->methodstate->is_a_slot) {
793             c = abc_getscopeobject(c, 1);
794             c = abc_newfunction(c, l->methodstate->abc);
795             c = abc_dup(c);
796             c = abc_setlocal(c, l->methodstate->var_index);
797             c = abc_setslot(c, l->methodstate->slot_index);
798         } else {
799             c = abc_newfunction(c, l->methodstate->abc);
800             c = abc_setlocal(c, l->methodstate->var_index);
801         }
802         free(l->methodstate);l->methodstate=0;
803         l = l->next;
804     }
805     if(m->header) {
806         c = code_append(c, m->header);
807         m->header = 0;
808     }
809     if(m->is_constructor && !m->has_super) {
810         // call default constructor
811         c = abc_getlocal_0(c);
812         c = abc_constructsuper(c, 0);
813     }
814     list_free(m->innerfunctions);
815     m->innerfunctions = 0;
816     return c;
817 }
818     
819
820 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
821 {
822     c = code_append(c, header);
823     c = code_append(c, var_block(body));
824     /* append return if necessary */
825     if(!c || (c->opcode != OPCODE_RETURNVOID && 
826               c->opcode != OPCODE_RETURNVALUE)) {
827         c = abc_returnvoid(c);
828     }
829     return c;
830 }
831
832
833 static void startpackage(char*name)
834 {
835     new_state();
836     /*printf("entering package \"%s\"\n", name);*/
837     state->package = strdup(name);
838 }
839 static void endpackage()
840 {
841     /*printf("leaving package \"%s\"\n", state->package);*/
842
843     //used e.g. in classinfo_register:
844     //free(state->package);state->package=0;
845
846     old_state();
847 }
848
849 #define FLAG_PUBLIC 256
850 #define FLAG_PROTECTED 512
851 #define FLAG_PRIVATE 1024
852 #define FLAG_PACKAGEINTERNAL 2048
853 #define FLAG_NAMESPACE 4096
854
855 static namespace_t modifiers2access(modifiers_t*mod)
856 {
857     namespace_t ns;
858     ns.access = 0;
859     ns.name = "";
860     if(mod->flags&FLAG_NAMESPACE)  {
861         if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
862             syntaxerror("invalid combination of access levels and namespaces");
863         ns.access = ACCESS_NAMESPACE;
864         state_t*s = state;
865         const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
866         if(!url) {
867             /* shouldn't happen- the tokenizer only reports something as a namespace
868                if it was already registered */
869             trie_dump(active_namespaces);
870             syntaxerror("unknown namespace: %s", mod->ns);
871         }
872         ns.name = url;
873     } else if(mod->flags&FLAG_PUBLIC)  {
874         if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
875             syntaxerror("invalid combination of access levels");
876         ns.access = ACCESS_PACKAGE;
877     } else if(mod->flags&FLAG_PRIVATE) {
878         if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
879             syntaxerror("invalid combination of access levels");
880         ns.access = ACCESS_PRIVATE;
881     } else if(mod->flags&FLAG_PROTECTED) {
882         if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL)) 
883             syntaxerror("invalid combination of access levels");
884         ns.access = ACCESS_PROTECTED;
885     } else {
886         ns.access = ACCESS_PACKAGEINTERNAL;
887     }
888     return ns;
889 }
890 static slotinfo_t* find_class(const char*name);
891
892 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
893 {
894     return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
895 }
896
897 void add_active_url(const char*url)
898 {
899     NEW(namespace_t,n);
900     n->name = url;
901     list_append(state->active_namespace_urls, n);
902 }
903
904 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
905 {
906     if(var0) {
907         int index = -1;
908         if(m->inner)
909             index = new_variable("this", 0, 0, 0);
910         else if(!m->is_global)
911             index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
912         else
913             index = new_variable("globalscope", 0, 0, 0);
914         if(index)
915             *(int*)0=0;
916         parserassert(!index);
917     }
918
919     if(m->uses_slots) {
920         /* as variables and slots share the same number, make sure
921            that those variable indices are reserved. It's up to the
922            optimizer to later shuffle the variables down to lower
923            indices */
924         m->variable_count = m->uses_slots;
925     }
926
927     if(params) {
928         param_list_t*p=0;
929         for(p=params->list;p;p=p->next) {
930             new_variable(p->param->name, p->param->type, 0, 1);
931         }
932     }
933
934     methodstate_list_t*l = m->innerfunctions;
935     while(l) {
936         methodstate_t*m = l->methodstate;
937         
938         variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
939         m->var_index = v->index;
940         m->slot_index = v->index;
941         v->is_inner_method = m;
942
943         l = l->next;
944     }
945     
946     if(as3_pass==2) {
947         m->scope_code = add_scope_code(m->scope_code, m, 0);
948     }
949     
950     if(as3_pass==2 && m->slots) {
951         /* exchange unresolved identifiers with the actual objects */
952         DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
953             if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
954                 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
955                 if(!type || type->kind != INFOTYPE_CLASS) {
956                     syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
957                 }
958                 v->type = type;
959             }
960         }
961     }
962 }
963
964
965 char*as3_globalclass=0;
966 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
967 {
968     if(state->cls) {
969         syntaxerror("inner classes now allowed"); 
970     }
971
972     new_state();
973     token_list_t*t=0;
974     classinfo_list_t*mlist=0;
975
976     if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
977         syntaxerror("invalid modifier(s)");
978
979     if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
980         syntaxerror("public and internal not supported at the same time.");
981     
982     //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
983     if(!(mod->flags&FLAG_INTERFACE) && !extends) {
984         // all classes extend object
985         extends = registry_getobjectclass();
986     }
987
988     /* create the class name, together with the proper attributes */
989     int access=0;
990     char*package=0;
991
992     if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
993         access = ACCESS_PRIVATE; package = internal_filename_package;
994     } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
995         access = ACCESS_PACKAGEINTERNAL; package = state->package;
996     } else if(state->package!=internal_filename_package) {
997         access = ACCESS_PACKAGE; package = state->package;
998     } else {
999         syntaxerror("public classes only allowed inside a package");
1000     }
1001
1002     if(as3_pass==1) {
1003         state->cls = rfx_calloc(sizeof(classstate_t));
1004         state->cls->init = rfx_calloc(sizeof(methodstate_t));
1005         state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1006         /* notice: we make no effort to initialize the top variable (local0) here,
1007            even though it has special meaning. We just rely on the facat
1008            that pass 1 won't do anything with variables */
1009         
1010         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1011
1012         /* set current method to constructor- all code within the class-level (except
1013            static variable initializations) will be executed during construction time */
1014         state->method = state->cls->init;
1015
1016         if(registry_find(package, classname)) {
1017             syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1018         }
1019         /* build info struct */
1020         int num_interfaces = (list_length(implements));
1021         state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1022         state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1023         
1024         int pos = 0;
1025         classinfo_list_t*l = implements;
1026         for(l=implements;l;l=l->next) {
1027             state->cls->info->interfaces[pos++] = l->classinfo;
1028         }
1029     }
1030     
1031     if(as3_pass == 2) {
1032         state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1033         
1034         state->method = state->cls->init;
1035         parserassert(state->cls && state->cls->info);
1036        
1037         function_initvars(state->cls->init, 0, 0, 1);
1038         function_initvars(state->cls->static_init, 0, 0, 0);
1039
1040         if(extends && (extends->flags & FLAG_FINAL))
1041             syntaxerror("Can't extend final class '%s'", extends->name);
1042         
1043         int pos = 0;
1044         while(state->cls->info->interfaces[pos]) {
1045             if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1046                 syntaxerror("'%s' is not an interface", 
1047                     state->cls->info->interfaces[pos]->name);
1048             pos++;
1049         }
1050
1051         /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
1052         state->cls->info->superclass = extends;
1053
1054         /* generate the abc code for this class */
1055         MULTINAME(classname2,state->cls->info);
1056         multiname_t*extends2 = sig2mname(extends);
1057
1058         state->cls->abc = abc_class_new(global->file, &classname2, extends2);
1059         if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1060         if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1061         if(state->cls->info->flags&FLAG_INTERFACE) {
1062             abc_class_interface(state->cls->abc);
1063         }
1064
1065         abc_class_protectedNS(state->cls->abc, classname);
1066
1067         for(mlist=implements;mlist;mlist=mlist->next) {
1068             MULTINAME(m, mlist->classinfo);
1069             abc_class_add_interface(state->cls->abc, &m);
1070         }
1071
1072         /* write the construction code for this class to the global init
1073            function */
1074         int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
1075
1076         abc_method_body_t*m = global->init->method->body;
1077         __ getglobalscope(m);
1078         classinfo_t*s = extends;
1079
1080         int count=0;
1081         
1082         while(s) {
1083             //TODO: take a look at the current scope stack, maybe 
1084             //      we can re-use something
1085             s = s->superclass;
1086             if(!s) 
1087             break;
1088            
1089             multiname_t*s2 = sig2mname(s);
1090             __ getlex2(m, s2);
1091             multiname_destroy(s2);
1092
1093             __ pushscope(m); count++;
1094             m->code = m->code->prev->prev; // invert
1095         }
1096         /* continue appending after last op end */
1097         while(m->code && m->code->next) m->code = m->code->next; 
1098
1099         /* TODO: if this is one of *our* classes, we can also 
1100                  do a getglobalscope/getslot <nr> (which references
1101                  the init function's slots) */
1102         if(extends2) {
1103             __ getlex2(m, extends2);
1104             __ dup(m);
1105             /* notice: we get a Verify Error #1107 if the top elemnt on the scope
1106                stack is not the superclass */
1107             __ pushscope(m);count++;
1108         } else {
1109             __ pushnull(m);
1110             /* notice: we get a verify error #1107 if the top element on the scope 
1111                stack is not the global object */
1112             __ getlocal_0(m);
1113             __ pushscope(m);count++;
1114         }
1115         __ newclass(m,state->cls->abc);
1116         while(count--) {
1117             __ popscope(m);
1118         }
1119         __ setslot(m, slotindex);
1120         multiname_destroy(extends2);
1121
1122         /* flash.display.MovieClip handling */
1123
1124         if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1125             if(state->package && state->package[0]) {
1126                 as3_globalclass = concat3(state->package, ".", classname);
1127             } else {
1128                 as3_globalclass = strdup(classname);
1129             }
1130         }
1131     }
1132 }
1133
1134 static int slotstate_varconst = 0;
1135 static modifiers_t*slotstate_flags = 0;
1136 static void setslotstate(modifiers_t* flags, int varconst)
1137 {
1138     slotstate_varconst = varconst;
1139     slotstate_flags = flags;
1140     if(state->cls) {
1141         if(flags && flags->flags&FLAG_STATIC) {
1142             state->method = state->cls->static_init;
1143         } else {
1144             state->method = state->cls->init;
1145         }
1146     } else {
1147         parserassert(state->method);
1148     }
1149 }
1150
1151 static void endclass()
1152 {
1153     if(as3_pass == 2) {
1154         if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1155             code_t*c = 0;
1156             c = abc_getlocal_0(c);
1157             c = abc_constructsuper(c, 0);
1158             state->cls->init->header = code_append(state->cls->init->header, c);
1159             state->cls->has_constructor=1;
1160         }
1161         if(state->cls->init) {
1162             if(state->cls->info->flags&FLAG_INTERFACE) {
1163                 if(state->cls->init->header) 
1164                     syntaxerror("interface can not have class-level code");
1165             } else {
1166                 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1167                 code_t*c = method_header(state->cls->init);
1168                 m->body->code = wrap_function(c, 0, m->body->code);
1169             }
1170         }
1171         if(state->cls->static_init) {
1172             abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1173             code_t*c = method_header(state->cls->static_init);
1174             m->body->code = wrap_function(c, 0, m->body->code);
1175         }
1176     }
1177
1178     old_state();
1179 }
1180
1181 void check_code_for_break(code_t*c)
1182 {
1183     while(c) {
1184         if(c->opcode == OPCODE___BREAK__) {
1185             char*name = string_cstr(c->data[0]);
1186             syntaxerror("Unresolved \"break %s\"", name);
1187         }
1188         if(c->opcode == OPCODE___CONTINUE__) {
1189             char*name = string_cstr(c->data[0]);
1190             syntaxerror("Unresolved \"continue %s\"", name);
1191         }
1192         if(c->opcode == OPCODE___PUSHPACKAGE__) {
1193             char*name = string_cstr(c->data[0]);
1194             syntaxerror("Can't reference a package (%s) as such", name);
1195         }
1196         c=c->prev;
1197     }
1198 }
1199
1200
1201 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1202 {
1203     return;
1204 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1205    if(TYPE_IS_NUMBER(t)) {
1206         xassert(c->type == CONSTANT_FLOAT
1207              || c->type == CONSTANT_INT
1208              || c->type == CONSTANT_UINT);
1209    } else if(TYPE_IS_UINT(t)) {
1210         xassert(c->type == CONSTANT_UINT ||
1211                (c->type == CONSTANT_INT && c->i>=0));
1212    } else if(TYPE_IS_INT(t)) {
1213         xassert(c->type == CONSTANT_INT);
1214    } else if(TYPE_IS_BOOLEAN(t)) {
1215         xassert(c->type == CONSTANT_TRUE
1216              || c->type == CONSTANT_FALSE);
1217    }
1218 }
1219
1220 static void check_override(memberinfo_t*m, int flags)
1221 {
1222     if(!m)
1223         return;
1224     if(m->parent == state->cls->info)
1225         syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1226     if(!m->parent)
1227         syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1228     if(m->access==ACCESS_PRIVATE)
1229         return;
1230     if(m->flags & FLAG_FINAL)
1231         syntaxerror("can't override final member %s", m->name);
1232     
1233     /* allow this. it's no issue.
1234     if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1235         syntaxerror("can't override static member %s", m->name);*/
1236
1237     if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1238         syntaxerror("can't override non-static member %s with static declaration", m->name);
1239
1240     if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1241         if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1242             if(m->kind == INFOTYPE_METHOD)
1243                 syntaxerror("can't override without explicit 'override' declaration");
1244             else
1245                 syntaxerror("can't override '%s'", m->name);
1246         }
1247     }
1248 }
1249
1250 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1251 {
1252     methodinfo_t*minfo = 0;
1253     namespace_t ns = modifiers2access(mod);
1254     if(!state->cls) {
1255         //package method
1256         minfo = methodinfo_register_global(ns.access, state->package, name);
1257         minfo->return_type = 0; // save this for pass 2
1258     } else if(getset != KW_GET && getset != KW_SET) {
1259         //class method
1260         memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1261         if(m) {
1262             printf("%s.%s | %s.%s\n", 
1263                 m->package, m->name,
1264                 ns.name, name);
1265             syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1266         }
1267         minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1268         minfo->return_type = 0; // save this for pass 2 
1269         // getslot on a member slot only returns "undefined", so no need
1270         // to actually store these
1271         //state->minfo->slot = state->method->abc->method->trait->slot_id;
1272     } else {
1273         //class getter/setter
1274         int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1275         classinfo_t*type=0;
1276         if(getset == KW_GET) {
1277             type = return_type;
1278         } else if(params->list && params->list->param && !params->list->next) {
1279             type = params->list->param->type;
1280         } else
1281             syntaxerror("setter function needs to take exactly one argument");
1282         // not sure wether to look into superclasses here, too
1283         minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1284         if(minfo) {
1285             if(minfo->kind!=INFOTYPE_SLOT)
1286                 syntaxerror("class already contains a method called '%s'", name);
1287             if(!(minfo->subtype & (SUBTYPE_GETSET)))
1288                 syntaxerror("class already contains a field called '%s'", name);
1289             if(minfo->subtype & gs)
1290                 syntaxerror("getter/setter for '%s' already defined", name);
1291             /* make a setter or getter into a getset */
1292             minfo->subtype |= gs;
1293             
1294             /*
1295             FIXME: this check needs to be done in pass 2
1296             
1297             if((!minfo->return_type != !type) ||
1298                 (minfo->return_type && type && 
1299                  !strcmp(minfo->return_type->name, type->name))) {
1300                 syntaxerror("different type in getter and setter: %s and %s", 
1301                     minfo->return_type?minfo->return_type->name:"*", 
1302                     type?type->name:"*");
1303             }*/
1304         } else {
1305             minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1306             minfo->kind = INFOTYPE_SLOT; //hack
1307             minfo->subtype = gs;
1308             minfo->return_type = 0;
1309         }
1310         /* can't assign a slot as getter and setter might have different slots */
1311         //minfo->slot = slot;
1312     }
1313     if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1314     if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1315     if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1316
1317     return minfo;
1318 }
1319
1320 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1321 {
1322     //parserassert(state->method && state->method->info);
1323
1324     methodstate_t*parent_method = state->method;
1325
1326     if(as3_pass==1) {
1327         return_type = 0; // not valid in pass 1
1328     }
1329
1330     new_state();
1331     state->new_vars = 1;
1332    
1333     if(as3_pass == 1) {
1334         state->method = rfx_calloc(sizeof(methodstate_t));
1335         state->method->inner = 1;
1336         state->method->variable_count = 0;
1337         state->method->abc = rfx_calloc(sizeof(abc_method_t));
1338
1339         NEW(methodinfo_t,minfo);
1340         minfo->kind = INFOTYPE_METHOD;
1341         minfo->access = ACCESS_PACKAGEINTERNAL;
1342         minfo->name = name;
1343         state->method->info = minfo;
1344
1345         if(parent_method)
1346             list_append(parent_method->innerfunctions, state->method);
1347
1348         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1349     
1350         function_initvars(state->method, params, 0, 1);
1351     }
1352
1353     if(as3_pass == 2) {
1354         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1355         state->method->variable_count = 0;
1356         parserassert(state->method);
1357
1358         state->method->info->return_type = return_type;
1359         function_initvars(state->method, params, 0, 1);
1360     }
1361 }
1362
1363 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1364                           params_t*params, classinfo_t*return_type)
1365 {
1366     if(state->method && state->method->info) {
1367         syntaxerror("not able to start another method scope");
1368     }
1369     new_state();
1370     state->new_vars = 1;
1371     
1372     if(as3_pass == 1) {
1373         state->method = rfx_calloc(sizeof(methodstate_t));
1374         state->method->has_super = 0;
1375
1376         if(state->cls) {
1377             state->method->is_constructor = !strcmp(state->cls->info->name,name);
1378         } else {
1379             state->method->is_global = 1;
1380             state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1381         }
1382         if(state->method->is_constructor)
1383             name = "__as3_constructor__";
1384
1385         state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1386        
1387         function_initvars(state->method, params, mod->flags, 1);
1388         
1389         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1390     }
1391
1392     if(as3_pass == 2) {
1393         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1394         state->method->variable_count = 0;
1395         parserassert(state->method);
1396                 
1397         if(state->cls) {
1398             memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1399             check_override(m, mod->flags);
1400         }
1401             
1402         if(state->cls) { 
1403             state->cls->has_constructor |= state->method->is_constructor;
1404         }
1405         
1406         state->method->info->return_type = return_type;
1407         function_initvars(state->method, params, mod->flags, 1);
1408     } 
1409 }
1410
1411 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1412                           params_t*params, classinfo_t*return_type, code_t*body)
1413 {
1414     if(as3_pass==1) {
1415         // store inner methods in variables
1416         function_initvars(state->method, 0, 0, 0);
1417
1418         methodstate_list_t*ml = state->method->innerfunctions;
1419         
1420         dict_t*xvars = dict_new();
1421
1422         while(ml) {
1423             methodstate_t*m = ml->methodstate;
1424             parserassert(m->inner);
1425             if(m->unresolved_variables) {
1426                 dict_t*d = m->unresolved_variables;
1427                 int t;
1428                 for(t=0;t<d->hashsize;t++) {
1429                     dictentry_t*l = d->slots[t]; 
1430                     while(l) {
1431                         /* check parent method's variables */
1432                         variable_t*v;
1433                         if((v=find_variable(state, l->key))) {
1434                             m->uses_parent_function = 1;
1435                             state->method->uses_slots = 1;
1436                             dict_put(xvars, l->key, 0);
1437                         }
1438                         l = l->next;
1439                     }
1440                     if(l) break;
1441                 }
1442
1443                 dict_destroy(m->unresolved_variables);
1444                 m->unresolved_variables = 0;
1445             }
1446             ml = ml->next;
1447         }
1448         
1449         if(state->method->uses_slots) {
1450             state->method->slots = dict_new();
1451             int i = 1;
1452             DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1453                 if(!name) syntaxerror("internal error");
1454                 if(v->index && dict_contains(xvars, name)) {
1455                     v->init = 0;
1456                     v->index = i++;
1457                     if(v->is_inner_method) {
1458                         v->is_inner_method->is_a_slot = 1;
1459                     }
1460                     //v->type = 0;
1461                     dict_put(state->method->slots, name, v);
1462                 }
1463             }
1464             state->method->uses_slots = i;
1465             dict_destroy(state->vars);state->vars = 0;
1466         }
1467         old_state();
1468         return 0;
1469     }
1470
1471     if(as3_pass==2) {
1472         /*if(state->method->uses_parent_function){
1473             syntaxerror("accessing variables of parent function from inner functions not supported yet");
1474         }*/
1475
1476         abc_method_t*f = 0;
1477
1478         multiname_t*type2 = sig2mname(return_type);
1479         int slot = 0;
1480         if(state->method->inner) {
1481             f = state->method->abc;
1482             abc_method_init(f, global->file, type2, 1);
1483         } else if(state->method->is_constructor) {
1484             f = abc_class_getconstructor(state->cls->abc, type2);
1485         } else if(!state->method->is_global) {
1486             namespace_t mname_ns = modifiers2access(mod);
1487             multiname_t mname = {QNAME, &mname_ns, 0, name};
1488
1489             if(mod->flags&FLAG_STATIC)
1490                 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1491             else
1492                 f = abc_class_method(state->cls->abc, type2, &mname);
1493             slot = f->trait->slot_id;
1494         } else {
1495             namespace_t mname_ns = {state->method->info->access, state->package};
1496             multiname_t mname = {QNAME, &mname_ns, 0, name};
1497
1498             f = abc_method_new(global->file, type2, 1);
1499             trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1500             //abc_code_t*c = global->init->method->body->code;
1501         }
1502         //flash doesn't seem to allow us to access function slots
1503         //state->method->info->slot = slot;
1504
1505         if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1506         if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1507         if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1508         if(params->varargs) f->flags |= METHOD_NEED_REST;
1509
1510         char opt=0;
1511         param_list_t*p=0;
1512         for(p=params->list;p;p=p->next) {
1513             if(params->varargs && !p->next) {
1514                 break; //varargs: omit last parameter in function signature
1515             }
1516             multiname_t*m = sig2mname(p->param->type);
1517             list_append(f->parameters, m);
1518             if(p->param->value) {
1519                 check_constant_against_type(p->param->type, p->param->value);
1520                 opt=1;list_append(f->optional_parameters, p->param->value);
1521             } else if(opt) {
1522                 syntaxerror("non-optional parameter not allowed after optional parameters");
1523             }
1524         }
1525         if(state->method->slots) {
1526             DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1527                 if(v->index) {
1528                     multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1529                     multiname_t*type = sig2mname(v->type);
1530                     trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1531                     t->slot_id = v->index;
1532                 }
1533             }
1534         }
1535
1536         check_code_for_break(body);
1537
1538         /* Seems this works now.
1539         if(state->method->exceptions && state->method->uses_slots) {
1540            as3_warning("try/catch and activation not supported yet within the same method");
1541         }*/
1542
1543         if(f->body) {
1544             f->body->code = body;
1545             f->body->exceptions = state->method->exceptions;
1546         } else { //interface
1547             if(body)
1548                 syntaxerror("interface methods can't have a method body");
1549         }
1550
1551         old_state();
1552         return f;
1553     }
1554         
1555     return 0;
1556 }
1557
1558 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1559 {
1560     return 1; // FIXME
1561 }
1562
1563 void breakjumpsto(code_t*c, char*name, code_t*jump) 
1564 {
1565     while(c) {
1566         if(c->opcode == OPCODE___BREAK__) {
1567             string_t*name2 = c->data[0];
1568             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1569                 c->opcode = OPCODE_JUMP;
1570                 c->branch = jump;
1571             }
1572         }
1573         c=c->prev;
1574     }
1575 }
1576 void continuejumpsto(code_t*c, char*name, code_t*jump) 
1577 {
1578     while(c) {
1579         if(c->opcode == OPCODE___CONTINUE__) {
1580             string_t*name2 = c->data[0];
1581             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1582                 c->opcode = OPCODE_JUMP;
1583                 c->branch = jump;
1584             }
1585         }
1586         c = c->prev;
1587     }
1588 }
1589
1590 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1591 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1592 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1593
1594 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1595 {
1596     if(!type1 || !type2) 
1597         return registry_getanytype();
1598     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1599         return registry_getanytype();
1600
1601     if(op=='+') {
1602         if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1603             return TYPE_NUMBER;
1604         } else {
1605             return TYPE_ANY;
1606         }
1607     }
1608
1609     if(type1 == type2)
1610         return type1;
1611     return registry_getanytype();
1612 }
1613 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1614 {
1615     if(from==to)
1616         return c;
1617     if(!to) {
1618         return abc_coerce_a(c);
1619     }
1620     MULTINAME(m, to);
1621     if(!from) {
1622         // cast an "any" type to a specific type. subject to
1623         // runtime exceptions
1624         return abc_coerce2(c, &m);
1625     }
1626     
1627     if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1628        (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1629         // allow conversion between number types
1630         return abc_coerce2(c, &m);
1631     }
1632     //printf("%s.%s\n", from.package, from.name);
1633     //printf("%s.%s\n", to.package, to.name);
1634
1635     classinfo_t*supertype = from;
1636     while(supertype) {
1637         if(supertype == to) {
1638              // target type is one of from's superclasses
1639              return abc_coerce2(c, &m);
1640         }
1641         int t=0;
1642         while(supertype->interfaces[t]) {
1643             if(supertype->interfaces[t]==to) {
1644                 // target type is one of from's interfaces
1645                 return abc_coerce2(c, &m);
1646             }
1647             t++;
1648         }
1649         supertype = supertype->superclass;
1650     }
1651     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1652         return c;
1653     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1654         return c;
1655     if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1656         return c;
1657
1658     as3_error("can't convert type %s%s%s to %s%s%s", 
1659         from->package, from->package?".":"", from->name, 
1660         to->package, to->package?".":"", to->name);
1661     return c;
1662 }
1663
1664 code_t*defaultvalue(code_t*c, classinfo_t*type)
1665 {
1666     if(TYPE_IS_INT(type)) {
1667        c = abc_pushbyte(c, 0);
1668     } else if(TYPE_IS_UINT(type)) {
1669        c = abc_pushuint(c, 0);
1670     } else if(TYPE_IS_FLOAT(type)) {
1671        c = abc_pushnan(c);
1672     } else if(TYPE_IS_BOOLEAN(type)) {
1673        c = abc_pushfalse(c);
1674     } else if(!type) {
1675        //c = abc_pushundefined(c);
1676     } else {
1677        c = abc_pushnull(c);
1678        MULTINAME(m, type);
1679        c = abc_coerce2(c, &m);
1680     }
1681     return c;
1682 }
1683
1684 char is_pushundefined(code_t*c)
1685 {
1686     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1687 }
1688
1689 static const char* get_package_from_name(const char*name)
1690 {
1691     /* try explicit imports */
1692     dictentry_t* e = dict_get_slot(state->imports, name);
1693     while(e) {
1694         if(!strcmp(e->key, name)) {
1695             slotinfo_t*c = (slotinfo_t*)e->data;
1696             if(c) return c->package;
1697         }
1698         e = e->next;
1699     }
1700     return 0;
1701 }
1702 static namespace_list_t*get_current_imports()
1703 {
1704     namespace_list_t*searchlist = 0;
1705     
1706     list_append(searchlist, namespace_new_package(state->package));
1707
1708     import_list_t*l = state->wildcard_imports;
1709     while(l) {
1710         namespace_t*ns = namespace_new_package(l->import->package);
1711         list_append(searchlist, ns);
1712         l = l->next;
1713     }
1714     list_append(searchlist, namespace_new_package(""));
1715     list_append(searchlist, namespace_new_package(internal_filename_package));
1716     return searchlist;
1717 }
1718
1719 static slotinfo_t* find_class(const char*name)
1720 {
1721     slotinfo_t*c=0;
1722
1723     c = registry_find(state->package, name);
1724     if(c) return c;
1725
1726     /* try explicit imports */
1727     dictentry_t* e = dict_get_slot(state->imports, name);
1728     if(c) return c;
1729     while(e) {
1730         if(!strcmp(e->key, name)) {
1731             c = (slotinfo_t*)e->data;
1732             if(c) return c;
1733         }
1734         e = e->next;
1735     }
1736
1737     /* try package.* imports */
1738     import_list_t*l = state->wildcard_imports;
1739     while(l) {
1740         //printf("does package %s contain a class %s?\n", l->import->package, name);
1741         c = registry_find(l->import->package, name);
1742         if(c) return c;
1743         l = l->next;
1744     }
1745
1746     /* try global package */
1747     c = registry_find("", name);
1748     if(c) return c;
1749   
1750     /* try local "filename" package */
1751     c = registry_find(internal_filename_package, name);
1752     if(c) return c;
1753
1754     return 0;
1755 }
1756 typedcode_t push_class(slotinfo_t*a)
1757 {
1758     typedcode_t x;
1759     x.c = 0;
1760     x.t = 0;
1761     if(a->access == ACCESS_PACKAGEINTERNAL &&
1762        strcmp(a->package, state->package) &&
1763        strcmp(a->package, internal_filename_package)
1764        ) {
1765        syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1766             infotypename(a), a->name, a->package, state->package);
1767     }
1768
1769     if(a->kind != INFOTYPE_CLASS) {
1770         MULTINAME(m, a);
1771         x.c = abc_findpropstrict2(x.c, &m);
1772         x.c = abc_getproperty2(x.c, &m);
1773         if(a->kind == INFOTYPE_METHOD) {
1774             methodinfo_t*f = (methodinfo_t*)a;
1775             x.t = TYPE_FUNCTION(f);
1776         } else {
1777             varinfo_t*v = (varinfo_t*)a;
1778             x.t = v->type;
1779         }
1780     } else {
1781         classinfo_t*c = (classinfo_t*)a;
1782         if(c->slot) {
1783             x.c = abc_getglobalscope(x.c);
1784             x.c = abc_getslot(x.c, c->slot);
1785         } else {
1786             MULTINAME(m, c);
1787             x.c = abc_getlex2(x.c, &m);
1788         }
1789         x.t = TYPE_CLASS(c);
1790     }
1791     return x;
1792 }
1793
1794 static char is_getlocal(code_t*c)
1795 {
1796     if(!c || c->prev || c->next)
1797         return 0;
1798     return(c->opcode == OPCODE_GETLOCAL
1799         || c->opcode == OPCODE_GETLOCAL_0
1800         || c->opcode == OPCODE_GETLOCAL_1
1801         || c->opcode == OPCODE_GETLOCAL_2
1802         || c->opcode == OPCODE_GETLOCAL_3);
1803 }
1804 static int getlocalnr(code_t*c)
1805 {
1806     if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1807     else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1808     else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1809     else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1810     else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1811     else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1812     return 0;
1813 }
1814
1815 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1816 {
1817     /* converts this:
1818
1819        [prefix code] [read instruction]
1820
1821        to this:
1822
1823        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1824     */
1825     if(in && in->opcode == OPCODE_COERCE_A) {
1826         in = code_cutlast(in);
1827     }
1828     if(in->next)
1829         syntaxerror("internal error");
1830
1831     /* chop off read instruction */
1832     code_t*prefix = in;
1833     code_t*r = in;
1834     if(r->prev) {
1835         prefix = r->prev;r->prev = 0;
1836         prefix->next=0;
1837     } else {
1838         prefix = 0;
1839     }
1840         
1841     char use_temp_var = readbefore;
1842
1843     /* generate the write instruction, and maybe append a dup to the prefix code */
1844     code_t* write = abc_nop(0);
1845     if(r->opcode == OPCODE_GETPROPERTY) {
1846         write->opcode = OPCODE_SETPROPERTY;
1847         multiname_t*m = (multiname_t*)r->data[0];
1848         write->data[0] = multiname_clone(m);
1849         if(m->type == QNAME || m->type == MULTINAME) {
1850             if(!justassign) {
1851                 prefix = abc_dup(prefix); // we need the object, too
1852             }
1853             use_temp_var = 1;
1854         } else if(m->type == MULTINAMEL) {
1855             if(!justassign) {
1856                 /* dupping two values on the stack requires 5 operations and one register- 
1857                    couldn't adobe just have given us a dup2? */
1858                 int temp = gettempvar();
1859                 prefix = abc_setlocal(prefix, temp);
1860                 prefix = abc_dup(prefix);
1861                 prefix = abc_getlocal(prefix, temp);
1862                 prefix = abc_swap(prefix);
1863                 prefix = abc_getlocal(prefix, temp);
1864                 if(!use_temp_var);
1865                     prefix = abc_kill(prefix, temp);
1866             }
1867             use_temp_var = 1;
1868         } else {
1869             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1870         }
1871     } else if(r->opcode == OPCODE_GETSLOT) {
1872         write->opcode = OPCODE_SETSLOT;
1873         write->data[0] = r->data[0];
1874         if(!justassign) {
1875             prefix = abc_dup(prefix); // we need the object, too
1876         }
1877         use_temp_var = 1;
1878     } else if(r->opcode == OPCODE_GETLOCAL) { 
1879         write->opcode = OPCODE_SETLOCAL;
1880         write->data[0] = r->data[0];
1881     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1882         write->opcode = OPCODE_SETLOCAL_0;
1883     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1884         write->opcode = OPCODE_SETLOCAL_1;
1885     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1886         write->opcode = OPCODE_SETLOCAL_2;
1887     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1888         write->opcode = OPCODE_SETLOCAL_3;
1889     } else if(r->opcode == OPCODE_GETSUPER) { 
1890         write->opcode = OPCODE_SETSUPER;
1891         multiname_t*m = (multiname_t*)r->data[0];
1892         write->data[0] = multiname_clone(m);
1893     } else {
1894         code_dump(r);
1895         syntaxerror("illegal lvalue: can't assign a value to this expression");
1896     }
1897     code_t* c = 0;
1898     
1899     int temp = -1;
1900     if(!justassign) {
1901         if(use_temp_var) {
1902             /* with getproperty/getslot, we have to be extra careful not
1903                to execute the read code twice, as it might have side-effects
1904                (e.g. if the property is in fact a setter/getter combination)
1905
1906                So read the value, modify it, and write it again,
1907                using prefix only once and making sure (by using a temporary
1908                register) that the return value is what we just wrote */
1909             temp = gettempvar();
1910             c = code_append(c, prefix);
1911             c = code_append(c, r);
1912             if(readbefore) {
1913                 c = abc_dup(c);
1914                 c = abc_setlocal(c, temp);
1915             }
1916             c = code_append(c, middlepart);
1917             if(!readbefore) {
1918                 c = abc_dup(c);
1919                 c = abc_setlocal(c, temp);
1920             }
1921             c = code_append(c, write);
1922             c = abc_getlocal(c, temp);
1923             c = abc_kill(c, temp);
1924         } else {
1925             /* if we're allowed to execute the read code twice *and*
1926                the middlepart doesn't modify the code, things are easier.
1927             */
1928             code_t* r2 = code_dup(r);
1929             //c = code_append(c, prefix);
1930             parserassert(!prefix);
1931             c = code_append(c, r);
1932             c = code_append(c, middlepart);
1933             c = code_append(c, write);
1934             c = code_append(c, r2);
1935         }
1936     } else {
1937         /* even smaller version: overwrite the value without reading
1938            it out first */
1939         if(!use_temp_var) {
1940             if(prefix) {
1941                 c = code_append(c, prefix);
1942                 c = abc_dup(c);
1943             }
1944             c = code_append(c, middlepart);
1945             c = code_append(c, write);
1946             c = code_append(c, r);
1947         } else {
1948             code_free(r);r=0;
1949             temp = gettempvar();
1950             if(prefix) {
1951                 c = code_append(c, prefix);
1952             }
1953             c = code_append(c, middlepart);
1954             c = abc_dup(c);
1955             c = abc_setlocal(c, temp);
1956             c = code_append(c, write);
1957             c = abc_getlocal(c, temp);
1958             c = abc_kill(c, temp);
1959         }
1960     }
1961     return c;
1962 }
1963
1964 char is_break_or_jump(code_t*c)
1965 {
1966     if(!c)
1967         return 0;
1968     if(c->opcode == OPCODE_JUMP ||
1969        c->opcode == OPCODE___BREAK__ ||
1970        c->opcode == OPCODE___CONTINUE__ ||
1971        c->opcode == OPCODE_THROW ||
1972        c->opcode == OPCODE_RETURNVOID ||
1973        c->opcode == OPCODE_RETURNVALUE) {
1974        return 1;
1975     }
1976     return 0;
1977 }
1978
1979 #define IS_FINALLY_TARGET(op) \
1980         ((op) == OPCODE___CONTINUE__ || \
1981          (op) == OPCODE___BREAK__ || \
1982          (op) == OPCODE_RETURNVOID || \
1983          (op) == OPCODE_RETURNVALUE || \
1984          (op) == OPCODE___RETHROW__)
1985
1986 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1987 {
1988 #define NEED_EXTRA_STACK_ARG
1989     code_t*finally_label = abc_nop(0);
1990     NEW(lookupswitch_t, l);
1991     //_lookupswitch
1992
1993     code_t*i = c;
1994     int count=0;
1995     while(i) {
1996         code_t*prev = i->prev;
1997         if(IS_FINALLY_TARGET(i->opcode)) {
1998            code_t*p = prev;
1999            char needvalue=0;
2000            if(i->opcode == OPCODE___RETHROW__ ||
2001               i->opcode == OPCODE_RETURNVALUE) {
2002                if(i->opcode == OPCODE___RETHROW__)
2003                  i->opcode = OPCODE_THROW;
2004                needvalue=1;
2005                p = abc_coerce_a(p);
2006                p = abc_setlocal(p, tempvar);
2007            }
2008            p = abc_pushbyte(p, count++);
2009            p = abc_jump(p, finally_label);
2010            code_t*target = p = abc_label(p);
2011 #ifdef NEED_EXTRA_STACK_ARG
2012            p = abc_pop(p);
2013 #endif
2014            if(needvalue) {
2015                p = abc_getlocal(p, tempvar);
2016            }
2017
2018            p->next = i;i->prev = p;
2019            list_append(l->targets, target);
2020         }
2021         i = prev;
2022     }
2023
2024     code_t*j,*f;
2025     c = abc_pushbyte(c, -1);
2026     c = code_append(c, finally_label);
2027     c = code_append(c, finally);
2028
2029 #ifdef NEED_EXTRA_STACK_ARG
2030     c = abc_dup(c);
2031 #endif
2032     c = abc_lookupswitch(c, l);
2033     c = l->def = abc_label(c);
2034 #ifdef NEED_EXTRA_STACK_ARG
2035     c = abc_pop(c);
2036 #endif
2037
2038     return c;
2039 }
2040
2041 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
2042 {
2043     code_t*i = c;
2044     while(i) {
2045         code_t*prev = i->prev;
2046         if(IS_FINALLY_TARGET(i->opcode)) {
2047            if(i->opcode == OPCODE___RETHROW__)
2048                 i->opcode = OPCODE_THROW;
2049            code_t*end = code_dup(finally);
2050            code_t*start = code_start(end);
2051            if(prev) prev->next = start;
2052            start->prev = prev;
2053            i->prev = end;
2054            end->next = i;
2055         }
2056         i = prev;
2057     }
2058     return code_append(c, finally);
2059 }
2060
2061 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
2062 {
2063     if(!finally)
2064         return c;
2065     code_t*i = c;
2066     char cantdup=0;
2067     int num_insertion_points=0;
2068     while(i) {
2069         if(IS_FINALLY_TARGET(i->opcode))
2070             num_insertion_points++;
2071         i = i->prev;
2072     }
2073     i = finally;
2074     int code_size=0;
2075     while(i) {
2076         code_size++;
2077         if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
2078             cantdup=1;
2079         }
2080         i = i->prev;
2081     }
2082     int simple_version_cost = (1+num_insertion_points)*code_size;
2083     int lookup_version_cost = 4*num_insertion_points + 5;
2084
2085     if(cantdup || simple_version_cost > lookup_version_cost) {
2086         //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
2087         return insert_finally_lookup(c, finally, tempvar);
2088     } else {
2089         //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
2090         return insert_finally_simple(c, finally, tempvar);
2091     }
2092 }
2093
2094 #define PASS1 }} if(as3_pass == 1) {{
2095 #define PASS1END }} if(as3_pass == 2) {{
2096 #define PASS2 }} if(as3_pass == 2) {{
2097 #define PASS12 }} {{
2098 #define PASS12END }} if(as3_pass == 2) {{
2099
2100 %}
2101
2102 %%
2103
2104 /* ------------ code blocks / statements ---------------- */
2105
2106 PROGRAM: MAYBE_PROGRAM_CODE_LIST
2107
2108 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST 
2109 PROGRAM_CODE_LIST: PROGRAM_CODE 
2110                  | PROGRAM_CODE_LIST PROGRAM_CODE
2111
2112 PROGRAM_CODE: PACKAGE_DECLARATION 
2113             | INTERFACE_DECLARATION 
2114             | CLASS_DECLARATION
2115             | FUNCTION_DECLARATION
2116             | SLOT_DECLARATION
2117             | PACKAGE_INITCODE
2118             | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' // conditional compilation
2119             | ';'
2120
2121 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
2122 INPACKAGE_CODE_LIST: INPACKAGE_CODE 
2123                    | INPACKAGE_CODE_LIST INPACKAGE_CODE
2124
2125 INPACKAGE_CODE: INTERFACE_DECLARATION 
2126               | CLASS_DECLARATION
2127               | FUNCTION_DECLARATION
2128               | SLOT_DECLARATION
2129               | PACKAGE_INITCODE
2130               | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' // conditional compilation
2131               | ';'
2132
2133 MAYBECODE: CODE {$$=$1;}
2134 MAYBECODE: {$$=code_new();}
2135
2136 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
2137 CODE: CODEPIECE {$$=$1;}
2138
2139 // code which may appear outside of methods
2140 CODE_STATEMENT: IMPORT 
2141 CODE_STATEMENT: FOR 
2142 CODE_STATEMENT: FOR_IN 
2143 CODE_STATEMENT: WHILE 
2144 CODE_STATEMENT: DO_WHILE 
2145 CODE_STATEMENT: SWITCH 
2146 CODE_STATEMENT: IF
2147 CODE_STATEMENT: WITH
2148 CODE_STATEMENT: TRY
2149 CODE_STATEMENT: VOIDEXPRESSION 
2150 CODE_STATEMENT: USE_NAMESPACE
2151 CODE_STATEMENT: NAMESPACE_DECLARATION
2152 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
2153 CODE_STATEMENT: '{' '}' {$$=0;}
2154
2155 // code which may appear in methods
2156 CODEPIECE: ';' {$$=0;}
2157 CODEPIECE: CODE_STATEMENT
2158 CODEPIECE: VARIABLE_DECLARATION
2159 CODEPIECE: BREAK
2160 CODEPIECE: CONTINUE
2161 CODEPIECE: RETURN
2162 CODEPIECE: THROW
2163 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
2164
2165 //CODEBLOCK :  '{' CODE '}' {$$=$2;}
2166 //CODEBLOCK :  '{' '}'      {$$=0;}
2167 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
2168 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
2169
2170 /* ------------ package init code ------------------- */
2171
2172 PACKAGE_INITCODE: CODE_STATEMENT {
2173     code_t**cc = &global->init->method->body->code;
2174     *cc = code_append(*cc, $1);
2175 }
2176
2177 /* ------------ conditional compilation ------------- */
2178
2179 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER 
2180
2181 /* ------------ variables --------------------------- */
2182
2183 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
2184                 |                {$$.c=abc_pushundefined(0);
2185                                   $$.t=TYPE_ANY;
2186                                  }
2187
2188 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2189 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2190
2191 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
2192 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2193
2194 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2195 {
2196 PASS12
2197     if(variable_exists($1))
2198         syntaxerror("Variable %s already defined", $1);
2199 PASS1
2200     new_variable($1, 0, 1, 0);
2201 PASS2
2202    
2203     if(!is_subtype_of($3.t, $2)) {
2204         syntaxerror("Can't convert %s to %s", $3.t->name, 
2205                                               $2->name);
2206     }
2207
2208     char slot = 0;
2209     int index = 0;
2210     if(state->method->uses_slots) {
2211         variable_t* v = find_slot(state, $1);
2212         if(v && !v->init) {
2213             // this variable is stored in a slot
2214             v->init = 1;
2215             v->type = $2;
2216             slot = 1;
2217             index = v->index;
2218         }
2219     }
2220     if(!index) {
2221         index = new_variable($1, $2, 1, 0);
2222     }
2223
2224     $$ = slot?abc_getscopeobject(0, 1):0;
2225     
2226     if($2) {
2227         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2228             $$ = code_append($$, $3.c);
2229             $$ = converttype($$, $3.t, $2);
2230         } else {
2231             code_free($3.c);
2232             $$ = defaultvalue($$, $2);
2233         }
2234     } else {
2235         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2236             $$ = code_append($$, $3.c);
2237             $$ = abc_coerce_a($$);
2238         } else {
2239             // don't do anything
2240             code_free($3.c);
2241             code_free($$);
2242             $$ = 0;
2243             break;
2244         }
2245     }
2246     if(slot) {
2247         $$ = abc_setslot($$, index);
2248     } else {
2249         $$ = abc_setlocal($$, index);
2250     }
2251 }
2252
2253 /* ------------ control flow ------------------------- */
2254
2255 MAYBEELSE:  %prec below_else {$$ = code_new();}
2256 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2257 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2258
2259 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2260      
2261     $$ = code_new();
2262     $$ = code_append($$, $4.c);
2263     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2264    
2265     $$ = code_append($$, $6);
2266     if($7) {
2267         myjmp = $$ = abc_jump($$, 0);
2268     }
2269     myif->branch = $$ = abc_nop($$);
2270     if($7) {
2271         $$ = code_append($$, $7);
2272         myjmp->branch = $$ = abc_nop($$);
2273     }
2274     $$ = var_block($$);
2275     PASS12 old_state();
2276 }
2277
2278 FOR_INIT : {$$=code_new();}
2279 FOR_INIT : VARIABLE_DECLARATION
2280 FOR_INIT : VOIDEXPRESSION
2281
2282 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2283 //       (I don't see any easy way to revolve this conflict otherwise, as we
2284 //        can't touch VAR_READ without upsetting the precedence about "return")
2285 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2286     PASS1 $$=$2;new_variable($2,0,1,0);
2287     PASS2 $$=$2;new_variable($2,$3,1,0);
2288 }
2289 FOR_IN_INIT : T_IDENTIFIER {
2290     PASS12
2291     $$=$1;
2292 }
2293
2294 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2295 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2296
2297 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2298     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2299     $$ = code_new();
2300     $$ = code_append($$, $2);
2301     code_t*loopstart = $$ = abc_label($$);
2302     $$ = code_append($$, $4.c);
2303     code_t*myif = $$ = abc_iffalse($$, 0);
2304     $$ = code_append($$, $8);
2305     code_t*cont = $$ = abc_nop($$);
2306     $$ = code_append($$, $6);
2307     $$ = abc_jump($$, loopstart);
2308     code_t*out = $$ = abc_nop($$);
2309     breakjumpsto($$, $1.name, out);
2310     continuejumpsto($$, $1.name, cont);
2311     myif->branch = out;
2312
2313     $$ = var_block($$);
2314     PASS12 old_state();
2315 }
2316
2317 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2318     variable_t*var = find_variable(state, $2);
2319     if(!var) {
2320         syntaxerror("variable %s not known in this scope", $2);
2321     }
2322
2323     char*tmp1name = concat2($2, "__tmp1__");
2324     int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2325     char*tmp2name = concat2($2, "__array__");
2326     int array = new_variable(tmp1name, 0, 0, 0);
2327
2328     $$ = code_new();
2329     $$ = code_append($$, $4.c);
2330     $$ = abc_coerce_a($$);
2331     $$ = abc_setlocal($$, array);
2332     $$ = abc_pushbyte($$, 0);
2333     $$ = abc_setlocal($$, it);
2334
2335     code_t*loopstart = $$ = abc_label($$);
2336     
2337     $$ = abc_hasnext2($$, array, it);
2338     code_t*myif = $$ = abc_iffalse($$, 0);
2339     $$ = abc_getlocal($$, array);
2340     $$ = abc_getlocal($$, it);
2341     if(!$1.each)
2342         $$ = abc_nextname($$);
2343     else
2344         $$ = abc_nextvalue($$);
2345     $$ = converttype($$, 0, var->type);
2346     $$ = abc_setlocal($$, var->index);
2347
2348     $$ = code_append($$, $6);
2349     $$ = abc_jump($$, loopstart);
2350     
2351     code_t*out = $$ = abc_nop($$);
2352     breakjumpsto($$, $1.name, out);
2353     continuejumpsto($$, $1.name, loopstart);
2354     
2355     myif->branch = out;
2356
2357     $$ = var_block($$);
2358
2359     free(tmp1name);
2360     free(tmp2name);
2361
2362     PASS12 old_state();
2363 }
2364
2365 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2366
2367     $$ = code_new();
2368
2369     code_t*myjmp = $$ = abc_jump($$, 0);
2370     code_t*loopstart = $$ = abc_label($$);
2371     $$ = code_append($$, $6);
2372     code_t*cont = $$ = abc_nop($$);
2373     myjmp->branch = cont;
2374     $$ = code_append($$, $4.c);
2375     $$ = abc_iftrue($$, loopstart);
2376     code_t*out = $$ = abc_nop($$);
2377     breakjumpsto($$, $1, out);
2378     continuejumpsto($$, $1, cont);
2379
2380     $$ = var_block($$);
2381     PASS12 old_state();
2382 }
2383
2384 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2385     $$ = code_new();
2386     code_t*loopstart = $$ = abc_label($$);
2387     $$ = code_append($$, $3);
2388     code_t*cont = $$ = abc_nop($$);
2389     $$ = code_append($$, $6.c);
2390     $$ = abc_iftrue($$, loopstart);
2391     code_t*out = $$ = abc_nop($$);
2392     breakjumpsto($$, $1, out);
2393     continuejumpsto($$, $1, cont);
2394     
2395     $$ = var_block($$);
2396     PASS12 old_state();
2397 }
2398
2399 BREAK : "break" %prec prec_none {
2400     $$ = abc___break__(0, "");
2401 }
2402 BREAK : "break" T_IDENTIFIER {
2403     $$ = abc___break__(0, $2);
2404 }
2405 CONTINUE : "continue" %prec prec_none {
2406     $$ = abc___continue__(0, "");
2407 }
2408 CONTINUE : "continue" T_IDENTIFIER {
2409     $$ = abc___continue__(0, $2);
2410 }
2411
2412 MAYBE_CASE_LIST :           {$$=0;}
2413 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2414 MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
2415 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2416 CASE_LIST: CASE             {$$=$1;}
2417 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
2418
2419 CASE: "case" E ':' MAYBECODE {
2420     $$ = abc_getlocal(0, state->switch_var);
2421     $$ = code_append($$, $2.c);
2422     code_t*j = $$ = abc_ifne($$, 0);
2423     $$ = code_append($$, $4);
2424     if($$->opcode != OPCODE___BREAK__) {
2425         $$ = abc___fallthrough__($$, "");
2426     }
2427     code_t*e = $$ = abc_nop($$);
2428     j->branch = e;
2429 }
2430 DEFAULT: "default" ':' MAYBECODE {
2431     $$ = $3;
2432 }
2433 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2434     $$=$4.c;
2435     $$ = abc_setlocal($$, state->switch_var);
2436     $$ = code_append($$, $7);
2437
2438     code_t*out = $$ = abc_kill($$, state->switch_var);
2439     breakjumpsto($$, $1, out);
2440     
2441     code_t*c = $$,*lastblock=0;
2442     while(c) {
2443         if(c->opcode == OPCODE_IFNE) {
2444             if(!c->next) syntaxerror("internal error in fallthrough handling");
2445             lastblock=c->next;
2446         } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2447             if(lastblock) {
2448                 c->opcode = OPCODE_JUMP;
2449                 c->branch = lastblock;
2450             } else {
2451                 /* fall through end of switch */
2452                 c->opcode = OPCODE_NOP;
2453             }
2454         }
2455         c=c->prev;
2456     }
2457    
2458     $$ = var_block($$);
2459     PASS12 old_state();
2460 }
2461
2462 /* ------------ try / catch /finally ---------------- */
2463
2464 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2465                                                       state->exception_name=$3;
2466                                                PASS1 new_variable($3, 0, 0, 0);
2467                                                PASS2 new_variable($3, $4, 0, 0);
2468                                               } 
2469         '{' MAYBECODE '}' {
2470     namespace_t name_ns = {ACCESS_PACKAGE, ""};
2471     multiname_t name = {QNAME, &name_ns, 0, $3};
2472     
2473     NEW(abc_exception_t, e)
2474     e->exc_type = sig2mname($4);
2475     e->var_name = multiname_clone(&name);
2476     $$ = e;
2477
2478     code_t*c = 0;
2479     int i = find_variable_safe(state, $3)->index;
2480     e->target = c = abc_nop(0);
2481     c = abc_setlocal(c, i);
2482     c = code_append(c, code_dup(state->method->scope_code));
2483     c = code_append(c, $8);
2484     c = abc_kill(c, i);
2485
2486     c = var_block(c);
2487     PASS12 old_state();
2488 }
2489 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2490     $4 = var_block($4);
2491     if(!$4) {
2492         $$=0;
2493     } else {
2494         NEW(abc_exception_t, e)
2495         e->exc_type = 0; //all exceptions
2496         e->var_name = 0; //no name
2497         e->target = 0;
2498         e->to = abc_nop(0);
2499         e->to = code_append(e->to, $4);
2500         $$ = e;
2501     }
2502     PASS12 old_state();
2503 }
2504
2505 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2506 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2507 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2508 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2509     $$ = $1;
2510     $$.finally = 0;
2511     if($2) {
2512         list_append($$.l,$2);
2513         $$.finally = $2->to;$2->to=0;
2514     }
2515 }
2516 CATCH_FINALLY_LIST: FINALLY {
2517     $$.l=list_new();
2518     $$.finally = 0;
2519     if($1) {
2520         list_append($$.l,$1);
2521         $$.finally = $1->to;$1->to=0;
2522     }
2523 }
2524
2525 TRY : "try" '{' {PASS12 new_state();
2526                  state->method->has_exceptions=1;
2527                  state->method->late_binding=1;//for invariant scope_code
2528                 } MAYBECODE '}' CATCH_FINALLY_LIST {
2529     code_t*out = abc_nop(0);
2530
2531     code_t*start = abc_nop(0);
2532     $$ = code_append(start, $4);
2533     if(!is_break_or_jump($4)) {
2534         $$ = abc_jump($$, out);
2535     }
2536     code_t*end = $$ = abc_nop($$);
2537   
2538     int tmp;
2539     if($6.finally)
2540         tmp = new_variable("__finally__", 0, 0, 0);
2541     
2542     abc_exception_list_t*l = $6.l;
2543     int count=0;
2544     while(l) {
2545         abc_exception_t*e = l->abc_exception;
2546         if(e->var_name) {
2547             $$ = code_append($$, e->target);
2548             $$ = abc_jump($$, out);
2549         } else {
2550             parserassert((ptroff_t)$6.finally);
2551             // finally block
2552             e->target = $$ = abc_nop($$);
2553             $$ = code_append($$, code_dup(state->method->scope_code));
2554             $$ = abc___rethrow__($$);
2555         }
2556         
2557         e->from = start;
2558         e->to = end;
2559
2560         l = l->next;
2561     }
2562     $$ = code_append($$, out);
2563
2564     $$ = insert_finally($$, $6.finally, tmp);
2565         
2566     list_concat(state->method->exceptions, $6.l);
2567    
2568     $$ = var_block($$);
2569     PASS12 old_state();
2570 }
2571
2572 /* ------------ throw ------------------------------- */
2573
2574 THROW : "throw" EXPRESSION {
2575     $$=$2.c;
2576     $$=abc_throw($$);
2577 }
2578 THROW : "throw" %prec prec_none {
2579     if(!state->exception_name)
2580         syntaxerror("re-throw only possible within a catch block");
2581     variable_t*v = find_variable(state, state->exception_name);
2582     $$=code_new();
2583     $$=abc_getlocal($$, v->index);
2584     $$=abc_throw($$);
2585 }
2586
2587 /* ------------ with -------------------------------- */
2588
2589 WITH_HEAD : "with" '(' EXPRESSION ')' {
2590      new_state();
2591      if(state->method->has_exceptions) {
2592          int v = alloc_local();
2593          state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2594          state->method->scope_code = abc_pushwith(state->method->scope_code);
2595          $$.number = v;
2596      }
2597      $$.cc = $3.c;
2598
2599 WITH : WITH_HEAD CODEBLOCK {
2600      /* remove getlocal;pushwith from scope code again */
2601      state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2602
2603      $$ = $1.cc;
2604      if(state->method->has_exceptions) {
2605          $$ = abc_dup($$);
2606          $$ = abc_setlocal($$, $1.number);
2607      }
2608      $$ = abc_pushwith($$);
2609      $$ = code_append($$, $2);
2610      $$ = abc_popscope($$);
2611      old_state();
2612 }
2613
2614 /* ------------ packages and imports ---------------- */
2615
2616 X_IDENTIFIER: T_IDENTIFIER
2617             | "package" {PASS12 $$="package";}
2618             | T_NAMESPACE {PASS12 $$=$1;}
2619
2620 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2621 PACKAGE: X_IDENTIFIER             {PASS12 $$=strdup($1);}
2622
2623 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2624                                 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2625 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");} 
2626                                 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2627
2628 IMPORT : "import" PACKAGEANDCLASS {
2629        PASS12
2630        slotinfo_t*s = registry_find($2->package, $2->name);
2631        if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2632            as3_schedule_class($2->package, $2->name);
2633        }
2634        classinfo_t*c = $2;
2635        if(!c) 
2636             syntaxerror("Couldn't import class\n");
2637        state_has_imports();
2638        dict_put(state->imports, c->name, c);
2639        import_toplevel(c->package);
2640        $$=0;
2641 }
2642 IMPORT : "import" PACKAGE '.' '*' {
2643        PASS12
2644        if(strncmp("flash.", $2, 6) && as3_pass==1) {
2645            as3_schedule_package($2);
2646        }
2647
2648        NEW(import_t,i);
2649        i->package = $2;
2650        state_has_imports();
2651        list_append(state->wildcard_imports, i);
2652        import_toplevel(i->package);
2653        $$=0;
2654 }
2655
2656 /* ------------ classes and interfaces (header) -------------- */
2657
2658 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2659 MAYBE_MODIFIERS : MODIFIER_LIST        {PASS12 $$=$1;}
2660 MODIFIER_LIST : MODIFIER               {PASS12 $$=$1;}
2661 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2662     PASS12 
2663     $$.flags=$1.flags|$2.flags;
2664     if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2665     $$.ns=$1.ns?$1.ns:$2.ns;
2666
2667 }
2668 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2669          | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2670          | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2671          | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2672          | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2673          | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2674          | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2675          | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2676          | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2677          | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2678                                $$.ns=$1;
2679                        }
2680
2681 EXTENDS : {PASS12 $$=0;}
2682 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2683
2684 EXTENDS_LIST : {PASS12 $$=list_new();}
2685 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2686
2687 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2688 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2689
2690 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
2691                               EXTENDS IMPLEMENTS_LIST 
2692                               '{' {PASS12 startclass(&$1,$3,$4,$5);} 
2693                               MAYBE_CLASS_BODY 
2694                               '}' {PASS12 endclass();$$=0;}
2695
2696 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
2697                               EXTENDS_LIST 
2698                               '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2699                                           startclass(&$1,$3,0,$4);}
2700                               MAYBE_INTERFACE_BODY 
2701                               '}' {PASS12 endclass();$$=0;}
2702
2703 /* ------------ classes and interfaces (body) -------------- */
2704
2705 MAYBE_CLASS_BODY : 
2706 MAYBE_CLASS_BODY : CLASS_BODY
2707 CLASS_BODY : CLASS_BODY_ITEM
2708 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2709 CLASS_BODY_ITEM : ';'
2710 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}'
2711 CLASS_BODY_ITEM : SLOT_DECLARATION
2712 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2713
2714 CLASS_BODY_ITEM : CODE_STATEMENT {
2715     code_t*c = state->cls->static_init->header;
2716     c = code_append(c, $1);  
2717     state->cls->static_init->header = c;
2718 }
2719
2720 MAYBE_INTERFACE_BODY : 
2721 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2722 INTERFACE_BODY : IDECLARATION
2723 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2724 IDECLARATION : ';'
2725 IDECLARATION : "var" T_IDENTIFIER {
2726     syntaxerror("variable declarations not allowed in interfaces");
2727 }
2728 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2729     PASS12
2730     $1.flags |= FLAG_PUBLIC;
2731     if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2732         syntaxerror("invalid method modifiers: interface methods always need to be public");
2733     }
2734     startfunction(&$1,$3,$4,&$6,$8);
2735     endfunction(&$1,$3,$4,&$6,$8, 0);
2736     list_deep_free($6.list);
2737 }
2738
2739 /* ------------ classes and interfaces (body, slots ) ------- */
2740
2741 VARCONST: "var" | "const"
2742
2743 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {setslotstate(&$1,$2);} SLOT_LIST {$$=$4;setslotstate(0, 0);}
2744
2745 SLOT_LIST: ONE_SLOT               {$$ = $1;}
2746 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {$$ = code_append($1, $3);}
2747
2748 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2749 {
2750     int flags = slotstate_flags->flags;
2751     namespace_t ns = modifiers2access(slotstate_flags);
2752
2753     varinfo_t* info = 0;
2754     if(state->cls) {
2755         memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2756         if(i) {
2757             check_override(i, flags);
2758         }
2759         info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2760     } else {
2761         slotinfo_t*i = registry_find(state->package, $1);
2762         if(i) {
2763             syntaxerror("package %s already contains '%s'", state->package, $1);
2764         }
2765         if(ns.name && ns.name[0]) {
2766             syntaxerror("namespaces not allowed on package-level variables");
2767         }
2768         info = varinfo_register_global(ns.access, state->package, $1);
2769     }
2770
2771     info->type = $2;
2772     info->flags = flags;
2773
2774     /* slot name */
2775     multiname_t mname = {QNAME, &ns, 0, $1};
2776   
2777     trait_list_t**traits;
2778     code_t**code;
2779     if(!state->cls) {
2780         // global variable
2781         ns.name = state->package;
2782         traits = &global->init->traits;
2783         code = &global->init->method->body->code;
2784     } else if(flags&FLAG_STATIC) {
2785         // static variable
2786         traits = &state->cls->abc->static_traits;
2787         code = &state->cls->static_init->header;
2788     } else {
2789         // instance variable
2790         traits = &state->cls->abc->traits;
2791         code = &state->cls->init->header;
2792     }
2793     
2794     trait_t*t=0;
2795     if($2) {
2796         MULTINAME(m, $2);
2797         t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2798     } else {
2799         t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2800     }
2801     info->slot = t->slot_id;
2802     
2803     /* initalization code (if needed) */
2804     code_t*c = 0;
2805     if($3.c && !is_pushundefined($3.c)) {
2806         c = abc_getlocal_0(c);
2807         c = code_append(c, $3.c);
2808         c = converttype(c, $3.t, $2);
2809         c = abc_setslot(c, t->slot_id);
2810     }
2811
2812     *code = code_append(*code, c);
2813
2814     if(slotstate_varconst==KW_CONST) {
2815         t->kind= TRAIT_CONST;
2816     }
2817
2818     $$=0;
2819 }
2820
2821 /* ------------ constants -------------------------------------- */
2822
2823 MAYBESTATICCONSTANT: {$$=0;}
2824 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2825
2826 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2827 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2828 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2829 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2830 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2831 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2832 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2833 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2834 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2835 STATICCONSTANT : T_IDENTIFIER {
2836     if(!strcmp($1, "NaN")) {
2837         $$ = constant_new_float(__builtin_nan(""));
2838     } else {
2839         as3_warning("Couldn't evaluate constant value of %s", $1);
2840         $$ = constant_new_null($1);
2841     }
2842 }
2843
2844 /* ------------ classes and interfaces (body, functions) ------- */
2845
2846 // non-vararg version
2847 MAYBE_PARAM_LIST: {
2848     PASS12
2849     memset(&$$,0,sizeof($$));
2850 }
2851 MAYBE_PARAM_LIST: PARAM_LIST {
2852     PASS12
2853     $$=$1;
2854 }
2855
2856 // vararg version
2857 MAYBE_PARAM_LIST: "..." PARAM {
2858     PASS12
2859     memset(&$$,0,sizeof($$));
2860     $$.varargs=1;
2861     list_append($$.list, $2);
2862 }
2863 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2864     PASS12
2865     $$ =$1;
2866     $$.varargs=1;
2867     list_append($$.list, $4);
2868 }
2869
2870 // non empty
2871 PARAM_LIST: PARAM_LIST ',' PARAM {
2872     PASS12
2873     $$ = $1;
2874     list_append($$.list, $3);
2875 }
2876 PARAM_LIST: PARAM {
2877     PASS12
2878     memset(&$$,0,sizeof($$));
2879     list_append($$.list, $1);
2880 }
2881
2882 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2883      PASS12
2884      $$ = rfx_calloc(sizeof(param_t));
2885      $$->name=$1;
2886      $$->type = $3;
2887      PASS2
2888      $$->value = $4;
2889 }
2890 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
2891      PASS12
2892      $$ = rfx_calloc(sizeof(param_t));
2893      $$->name=$1;
2894      $$->type = TYPE_ANY;
2895      PASS2
2896      $$->value = $2;
2897 }
2898 GETSET : "get"
2899        | "set"
2900        | {PASS12 $$=0;}
2901
2902 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
2903                       MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}' 
2904 {
2905     PASS1 
2906     endfunction(&$1,$3,$4,&$6,0,0);
2907     PASS2
2908     if(!state->method->info) syntaxerror("internal error");
2909     
2910     code_t*c = method_header(state->method);
2911     c = wrap_function(c, 0, $11);
2912
2913     endfunction(&$1,$3,$4,&$6,$8,c);
2914     PASS12
2915     list_deep_free($6.list);
2916     $$=0;
2917 }
2918
2919 MAYBE_IDENTIFIER: T_IDENTIFIER
2920 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2921 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE 
2922                '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2923 {
2924     PASS1
2925     endfunction(0,0,$2,&$4,0,0);
2926     PASS2
2927     methodinfo_t*f = state->method->info;
2928     if(!f || !f->kind) syntaxerror("internal error");
2929     
2930     code_t*c = method_header(state->method);
2931     c = wrap_function(c, 0, $9);
2932
2933     int index = state->method->var_index;
2934     endfunction(0,0,$2,&$4,$6,c);
2935     
2936     $$.c = abc_getlocal(0, index);
2937     $$.t = TYPE_FUNCTION(f);
2938
2939     PASS12 list_deep_free($4.list);
2940 }
2941
2942
2943 /* ------------- package + class ids --------------- */
2944
2945 CLASS: X_IDENTIFIER {
2946     PASS1 NEW(unresolvedinfo_t,c);
2947           memset(c, 0, sizeof(*c));
2948           c->kind = INFOTYPE_UNRESOLVED;
2949           c->name = $1;
2950           c->package = get_package_from_name($1);
2951           if(!c->package) {
2952               c->nsset = get_current_imports();
2953               /* make the compiler look for this class in the current directory,
2954                  just in case: */
2955               //as3_schedule_class_noerror(state->package, $1);
2956           }
2957           $$ = (classinfo_t*)c;
2958     PASS2
2959     slotinfo_t*s = find_class($1);
2960     if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2961     $$ = (classinfo_t*)s;
2962 }
2963
2964 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2965     PASS1 NEW(unresolvedinfo_t,c);
2966           memset(c, 0, sizeof(*c));
2967           c->kind = INFOTYPE_UNRESOLVED;
2968           c->package = $1;
2969           c->name = $3;
2970           $$ = (classinfo_t*)c;
2971     PASS2
2972     slotinfo_t*s = registry_find($1, $3);
2973     if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2974     free($1);$1=0;
2975     $$ = (classinfo_t*)s;
2976 }
2977
2978 CLASS_SPEC: PACKAGEANDCLASS
2979           | CLASS
2980
2981 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2982 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2983
2984 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2985      | '*'        {PASS12 $$=registry_getanytype();}
2986      | "void"     {PASS12 $$=registry_getanytype();}
2987     /*
2988      |  "String"  {$$=registry_getstringclass();}
2989      |  "int"     {$$=registry_getintclass();}
2990      |  "uint"    {$$=registry_getuintclass();}
2991      |  "Boolean" {$$=registry_getbooleanclass();}
2992      |  "Number"  {$$=registry_getnumberclass();}
2993     */
2994
2995 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2996 MAYBETYPE:          {PASS12 $$=0;}
2997
2998 /* ----------function calls, delete, constructor calls ------ */
2999
3000 MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.number=0;}
3001 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3002
3003 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3004 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3005 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3006
3007 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.number=1;
3008                                                   $$.cc = $1.c;
3009                                                  }
3010
3011 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3012 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3013                                                   $$.number= $1.number+1;
3014                                                   $$.cc = code_append($1.cc, $2.c);
3015                                                   }
3016                
3017 XX : %prec new2
3018 NEW : "new" E XX MAYBE_PARAM_VALUES {
3019     $$.c = $2.c;
3020     if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3021     
3022     code_t*paramcode = $4.cc;
3023     if($$.c->opcode == OPCODE_GETPROPERTY) {
3024         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3025         $$.c = code_cutlast($$.c);
3026         $$.c = code_append($$.c, paramcode);
3027         $$.c = abc_constructprop2($$.c, name, $4.number);
3028         multiname_destroy(name);
3029     } else if($$.c->opcode == OPCODE_GETSLOT) {
3030         int slot = (int)(ptroff_t)$$.c->data[0];
3031         trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3032         multiname_t*name = t->name;
3033         $$.c = code_cutlast($$.c);
3034         $$.c = code_append($$.c, paramcode);
3035         $$.c = abc_constructprop2($$.c, name, $4.number);
3036     } else {
3037         $$.c = code_append($$.c, paramcode);
3038         $$.c = abc_construct($$.c, $4.number);
3039     }
3040    
3041     $$.t = TYPE_ANY;
3042     if(TYPE_IS_CLASS($2.t) && $2.t->data) {
3043         $$.t = $2.t->data;
3044     } else {
3045         $$.c = abc_coerce_a($$.c);
3046         $$.t = TYPE_ANY;
3047     }
3048 }
3049
3050 /* TODO: use abc_call (for calling local variables),
3051          abc_callstatic (for calling own methods) 
3052          call (for closures)
3053 */
3054 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3055     
3056     $$.c = $1.c;
3057     if($$.c->opcode == OPCODE_COERCE_A) {
3058         $$.c = code_cutlast($$.c);
3059     }
3060     code_t*paramcode = $3.cc;
3061
3062     $$.t = TYPE_ANY;
3063     if($$.c->opcode == OPCODE_GETPROPERTY) {
3064         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3065         $$.c = code_cutlast($$.c);
3066         $$.c = code_append($$.c, paramcode);
3067         $$.c = abc_callproperty2($$.c, name, $3.number);
3068         multiname_destroy(name);
3069     } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3070         int slot = (int)(ptroff_t)$$.c->data[0];
3071         trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3072         if(t->kind!=TRAIT_METHOD) {
3073             //ok: flash allows to assign closures to members.
3074         }
3075         multiname_t*name = t->name;
3076         $$.c = code_cutlast($$.c);
3077         $$.c = code_append($$.c, paramcode);
3078         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3079         $$.c = abc_callproperty2($$.c, name, $3.number);
3080     } else if($$.c->opcode == OPCODE_GETSUPER) {
3081         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3082         $$.c = code_cutlast($$.c);
3083         $$.c = code_append($$.c, paramcode);
3084         $$.c = abc_callsuper2($$.c, name, $3.number);
3085         multiname_destroy(name);
3086     } else {
3087         $$.c = abc_getglobalscope($$.c);
3088         $$.c = code_append($$.c, paramcode);
3089         $$.c = abc_call($$.c, $3.number);
3090     }
3091    
3092     if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
3093         $$.t = ((methodinfo_t*)($1.t->data))->return_type;
3094     } else {
3095         $$.c = abc_coerce_a($$.c);
3096         $$.t = TYPE_ANY;
3097     }
3098 }
3099
3100 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3101     if(!state->cls) syntaxerror("super() not allowed outside of a class");
3102     if(!state->method) syntaxerror("super() not allowed outside of a function");
3103     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3104
3105     $$.c = code_new();
3106     $$.c = abc_getlocal_0($$.c);
3107
3108     $$.c = code_append($$.c, $3.cc);
3109     /*
3110     this is dependent on the control path, check this somewhere else
3111     if(state->method->has_super)
3112         syntaxerror("constructor may call super() only once");
3113     */
3114     state->method->has_super = 1;
3115
3116     $$.c = abc_constructsuper($$.c, $3.number);
3117     $$.c = abc_pushundefined($$.c);
3118     $$.t = TYPE_ANY;
3119 }
3120
3121 DELETE: "delete" E {
3122     $$.c = $2.c;
3123     if($$.c->opcode == OPCODE_COERCE_A) {
3124         $$.c = code_cutlast($$.c);
3125     }
3126     multiname_t*name = 0;
3127     if($$.c->opcode == OPCODE_GETPROPERTY) {
3128         $$.c->opcode = OPCODE_DELETEPROPERTY;
3129     } else if($$.c->opcode == OPCODE_GETSLOT) {
3130         int slot = (int)(ptroff_t)$$.c->data[0];
3131         multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3132         $$.c = code_cutlast($$.c);
3133         $$.c = abc_deleteproperty2($$.c, name);
3134     } else {
3135         $$.c = abc_getlocal_0($$.c);
3136         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
3137         $$.c = abc_deleteproperty2($$.c, &m);
3138     }
3139     $$.t = TYPE_BOOLEAN;
3140 }
3141
3142 RETURN: "return" %prec prec_none {
3143     $$ = abc_returnvoid(0);
3144 }
3145 RETURN: "return" EXPRESSION {
3146     $$ = $2.c;
3147     $$ = abc_returnvalue($$);
3148 }
3149
3150 // ----------------------- expression types -------------------------------------
3151
3152 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
3153 EXPRESSION : E                %prec below_minus {$$ = $1;}
3154 EXPRESSION : EXPRESSION ',' E %prec below_minus {
3155     $$.c = $1.c;
3156     $$.c = cut_last_push($$.c);
3157     $$.c = code_append($$.c,$3.c);
3158     $$.t = $3.t;
3159 }
3160 VOIDEXPRESSION : EXPRESSION %prec below_minus {
3161     $$=cut_last_push($1.c);
3162 }
3163
3164 // ----------------------- expression evaluation -------------------------------------
3165
3166 E : INNERFUNCTION %prec prec_none {$$ = $1;}
3167 //V : CONSTANT                    {$$ = 0;}
3168 E : CONSTANT
3169 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
3170 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3171 //V : NEW                         {$$ = $1.c;}
3172 E : NEW                         {$$ = $1;}
3173 //V : DELETE                      {$$ = $1.c;}
3174 E : DELETE                      {$$ = $1;}
3175
3176 E : FUNCTIONCALL
3177
3178 E : T_REGEXP {
3179     $$.c = 0;
3180     namespace_t ns = {ACCESS_PACKAGE, ""};
3181     multiname_t m = {QNAME, &ns, 0, "RegExp"};
3182     if(!$1.options) {
3183         $$.c = abc_getlex2($$.c, &m);
3184         $$.c = abc_pushstring($$.c, $1.pattern);
3185         $$.c = abc_construct($$.c, 1);
3186     } else {
3187         $$.c = abc_getlex2($$.c, &m);
3188         $$.c = abc_pushstring($$.c, $1.pattern);
3189         $$.c = abc_pushstring($$.c, $1.options);
3190         $$.c = abc_construct($$.c, 2);
3191     }
3192     $$.t = TYPE_REGEXP;
3193 }
3194
3195 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
3196                    //MULTINAME(m, registry_getintclass());
3197                    //$$.c = abc_coerce2($$.c, &m); // FIXME
3198                    $$.t = TYPE_INT;
3199                   }
3200 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
3201                     $$.t = TYPE_INT;
3202                    }
3203 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
3204                   $$.t = TYPE_INT;
3205                  }
3206 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
3207                    $$.t = TYPE_UINT;
3208                   }
3209 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
3210                     $$.t = TYPE_FLOAT;
3211                    }
3212 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
3213                      $$.t = TYPE_STRING;
3214                     }
3215 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
3216                     $$.t = TYPE_ANY;
3217                    }
3218 CONSTANT : "true" {$$.c = abc_pushtrue(0);
3219                     $$.t = TYPE_BOOLEAN;
3220                    }
3221 CONSTANT : "false" {$$.c = abc_pushfalse(0);
3222                      $$.t = TYPE_BOOLEAN;
3223                     }
3224 CONSTANT : "null" {$$.c = abc_pushnull(0);
3225                     $$.t = TYPE_NULL;
3226                    }
3227
3228 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
3229              $$.t = TYPE_BOOLEAN;
3230             }
3231 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
3232              $$.t = TYPE_BOOLEAN;
3233             }
3234 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
3235               $$.t = TYPE_BOOLEAN;
3236              }
3237 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
3238               $$.t = TYPE_BOOLEAN;
3239              }
3240 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
3241               $$.t = TYPE_BOOLEAN;
3242              }
3243 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
3244               $$.t = TYPE_BOOLEAN;
3245               }
3246 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
3247               $$.t = TYPE_BOOLEAN;
3248              }
3249 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
3250               $$.t = TYPE_BOOLEAN;
3251              }
3252
3253 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
3254               $$.c = $1.c;
3255               $$.c = converttype($$.c, $1.t, $$.t);
3256               $$.c = abc_dup($$.c);
3257               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
3258               $$.c = cut_last_push($$.c);
3259               $$.c = code_append($$.c,$3.c);
3260               $$.c = converttype($$.c, $3.t, $$.t);
3261               code_t*label = $$.c = abc_label($$.c);
3262               jmp->branch = label;
3263              }
3264 E : E "&&" E {
3265               $$.t = join_types($1.t, $3.t, 'A');
3266               /*printf("%08x:\n",$1.t);
3267               code_dump($1.c, 0, 0, "", stdout);
3268               printf("%08x:\n",$3.t);
3269               code_dump($3.c, 0, 0, "", stdout);
3270               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
3271               $$.c = $1.c;
3272               $$.c = converttype($$.c, $1.t, $$.t);
3273               $$.c = abc_dup($$.c);
3274               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
3275               $$.c = cut_last_push($$.c);
3276               $$.c = code_append($$.c,$3.c);
3277               $$.c = converttype($$.c, $3.t, $$.t);
3278               code_t*label = $$.c = abc_label($$.c);
3279               jmp->branch = label;              
3280              }
3281
3282 E : '!' E    {$$.c=$2.c;
3283               $$.c = abc_not($$.c);
3284               $$.t = TYPE_BOOLEAN;
3285              }
3286
3287 E : '~' E    {$$.c=$2.c;
3288               $$.c = abc_bitnot($$.c);
3289               $$.t = TYPE_INT;
3290              }
3291
3292 E : E '&' E {$$.c = code_append($1.c,$3.c);
3293              $$.c = abc_bitand($$.c);
3294              $$.t = TYPE_INT;
3295             }
3296
3297 E : E '^' E {$$.c = code_append($1.c,$3.c);
3298              $$.c = abc_bitxor($$.c);
3299              $$.t = TYPE_INT;
3300             }
3301
3302 E : E '|' E {$$.c = code_append($1.c,$3.c);
3303              $$.c = abc_bitor($$.c);
3304              $$.t = TYPE_INT;
3305             }
3306
3307 E : E ">>" E {$$.c = code_append($1.c,$3.c);
3308              $$.c = abc_rshift($$.c);
3309              $$.t = TYPE_INT;
3310             }
3311 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
3312              $$.c = abc_urshift($$.c);
3313              $$.t = TYPE_INT;
3314             }
3315 E : E "<<" E {$$.c = code_append($1.c,$3.c);
3316              $$.c = abc_lshift($$.c);
3317              $$.t = TYPE_INT;
3318             }
3319
3320 E : E '/' E {$$.c = code_append($1.c,$3.c);
3321              $$.c = abc_divide($$.c);
3322              $$.t = TYPE_NUMBER;
3323             }
3324 E : E '%' E {$$.c = code_append($1.c,$3.c);
3325              $$.c = abc_modulo($$.c);
3326              $$.t = TYPE_NUMBER;
3327             }
3328 E : E '+' E {$$.c = code_append($1.c,$3.c);
3329              if(BOTH_INT($1.t, $3.t)) {
3330                 $$.c = abc_add_i($$.c);
3331                 $$.t = TYPE_INT;
3332              } else {
3333                 $$.c = abc_add($$.c);
3334                 $$.t = join_types($1.t,$3.t,'+');
3335              }
3336             }
3337 E : E '-' E {$$.c = code_append($1.c,$3.c);
3338              if(BOTH_INT($1.t,$3.t)) {
3339                 $$.c = abc_subtract_i($$.c);
3340                 $$.t = TYPE_INT;
3341              } else {
3342                 $$.c = abc_subtract($$.c);
3343                 $$.t = TYPE_NUMBER;
3344              }
3345             }
3346 E : E '*' E {$$.c = code_append($1.c,$3.c);
3347              if(BOTH_INT($1.t,$3.t)) {
3348                 $$.c = abc_multiply_i($$.c);
3349                 $$.t = TYPE_INT;
3350              } else {
3351                 $$.c = abc_multiply($$.c);
3352                 $$.t = TYPE_NUMBER;
3353              }
3354             }
3355
3356 E : E "in" E {$$.c = code_append($1.c,$3.c);
3357               $$.c = abc_in($$.c);
3358               $$.t = TYPE_BOOLEAN;
3359              }
3360
3361 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
3362               if(use_astype && TYPE_IS_CLASS($3.t) && $3.t->data) {
3363                 MULTINAME(m, (classinfo_t*)($3.t->data));
3364                 $$.c = abc_astype2($1.c, &m);
3365                 $$.t = $3.t->data;
3366               } else {
3367                 $$.c = code_append($1.c, $3.c);
3368                 $$.c = abc_astypelate($$.c);
3369                 $$.t = TYPE_ANY;
3370               }
3371              }
3372
3373 E : E "instanceof" E 
3374              {$$.c = code_append($1.c, $3.c);
3375               $$.c = abc_instanceof($$.c);
3376               $$.t = TYPE_BOOLEAN;
3377              }
3378
3379 E : E "is" E {$$.c = code_append($1.c, $3.c);
3380               $$.c = abc_istypelate($$.c);
3381               $$.t = TYPE_BOOLEAN;
3382              }
3383
3384 E : "typeof" '(' E ')' {
3385               $$.c = $3.c;
3386               $$.c = abc_typeof($$.c);
3387               $$.t = TYPE_STRING;
3388              }
3389
3390 E : "void" E {
3391               $$.c = cut_last_push($2.c);
3392               $$.c = abc_pushundefined($$.c);
3393               $$.t = TYPE_ANY;
3394              }
3395
3396 E : "void" { $$.c = abc_pushundefined(0);
3397              $$.t = TYPE_ANY;
3398            }
3399
3400 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
3401
3402 E : '-' E {
3403   $$=$2;
3404   if(IS_INT($2.t)) {
3405    $$.c=abc_negate_i($$.c);
3406    $$.t = TYPE_INT;
3407   } else {
3408    $$.c=abc_negate($$.c);
3409    $$.t = TYPE_NUMBER;
3410   }
3411 }
3412
3413 E : E '[' E ']' {
3414   $$.c = $1.c;
3415   $$.c = code_append($$.c, $3.c);
3416
3417   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
3418   $$.c = abc_getproperty2($$.c, &m);
3419   $$.t = 0; // array elements have unknown type
3420 }
3421
3422 E : '[' MAYBE_EXPRESSION_LIST ']' {
3423     $$.c = code_new();
3424     $$.c = code_append($$.c, $2.cc);
3425     $$.c = abc_newarray($$.c, $2.number);
3426     $$.t = registry_getarrayclass();
3427 }
3428
3429 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3430 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
3431
3432 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3433     $$.cc = 0;
3434     $$.cc = code_append($$.cc, $1.c);
3435     $$.cc = code_append($$.cc, $3.c);
3436     $$.number = 2;
3437 }
3438 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3439     $$.cc = $1.cc;
3440     $$.number = $1.number+2;
3441     $$.cc = code_append($$.cc, $3.c);
3442     $$.cc = code_append($$.cc, $5.c);
3443 }
3444 //MAYBECOMMA: ','
3445 //MAYBECOMMA:
3446
3447 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
3448     $$.c = code_new();
3449     $$.c = code_append($$.c, $2.cc);
3450     $$.c = abc_newobject($$.c, $2.number/2);
3451     $$.t = registry_getobjectclass();
3452 }
3453
3454 E : E "*=" E { 
3455                code_t*c = $3.c;
3456                if(BOTH_INT($1.t,$3.t)) {
3457                 c=abc_multiply_i(c);
3458                } else {
3459                 c=abc_multiply(c);
3460                }
3461                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
3462                $$.c = toreadwrite($1.c, c, 0, 0);
3463                $$.t = $1.t;
3464               }
3465
3466 E : E "%=" E { 
3467                code_t*c = abc_modulo($3.c);
3468                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
3469                $$.c = toreadwrite($1.c, c, 0, 0);
3470                $$.t = $1.t;
3471               }
3472 E : E "<<=" E { 
3473                code_t*c = abc_lshift($3.c);
3474                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
3475                $$.c = toreadwrite($1.c, c, 0, 0);
3476                $$.t = $1.t;
3477               }
3478 E : E ">>=" E { 
3479                code_t*c = abc_rshift($3.c);
3480                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
3481                $$.c = toreadwrite($1.c, c, 0, 0);
3482                $$.t = $1.t;
3483               }
3484 E : E ">>>=" E { 
3485                code_t*c = abc_urshift($3.c);
3486                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
3487                $$.c = toreadwrite($1.c, c, 0, 0);
3488                $$.t = $1.t;
3489               }
3490 E : E "/=" E { 
3491                code_t*c = abc_divide($3.c);
3492                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
3493                $$.c = toreadwrite($1.c, c, 0, 0);
3494                $$.t = $1.t;
3495               }
3496 E : E "|=" E { 
3497                code_t*c = abc_bitor($3.c);
3498                c=converttype(c, TYPE_INT, $1.t);
3499                $$.c = toreadwrite($1.c, c, 0, 0);
3500                $$.t = $1.t;
3501               }
3502 E : E "^=" E { 
3503                code_t*c = abc_bitxor($3.c);
3504                c=converttype(c, TYPE_INT, $1.t);
3505                $$.c = toreadwrite($1.c, c, 0, 0);
3506                $$.t = $1.t;
3507               }
3508 E : E "+=" E { 
3509                code_t*c = $3.c;
3510
3511                if(TYPE_IS_INT($1.t)) {
3512                 c=abc_add_i(c);
3513                } else {
3514                 c=abc_add(c);
3515                 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
3516                }
3517                
3518                $$.c = toreadwrite($1.c, c, 0, 0);
3519                $$.t = $1.t;
3520               }
3521 E : E "-=" E { code_t*c = $3.c; 
3522                if(TYPE_IS_INT($1.t)) {
3523                 c=abc_subtract_i(c);
3524                } else {
3525                 c=abc_subtract(c);
3526                 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
3527                }
3528                
3529                $$.c = toreadwrite($1.c, c, 0, 0);
3530                $$.t = $1.t;
3531              }
3532 E : E '=' E { code_t*c = 0;
3533               c = code_append(c, $3.c);
3534               c = converttype(c, $3.t, $1.t);
3535               $$.c = toreadwrite($1.c, c, 1, 0);
3536               $$.t = $1.t;
3537             }
3538
3539 E : E '?' E ':' E %prec below_assignment { 
3540               $$.t = join_types($3.t,$5.t,'?');
3541               $$.c = $1.c;
3542               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
3543               $$.c = code_append($$.c, $3.c);
3544               $$.c = converttype($$.c, $3.t, $$.t);
3545               code_t*j2 = $$.c = abc_jump($$.c, 0);
3546               $$.c = j1->branch = abc_label($$.c);
3547               $$.c = code_append($$.c, $5.c);
3548               $$.c = converttype($$.c, $5.t, $$.t);
3549               $$.c = j2->branch = abc_label($$.c);
3550             }
3551
3552 E : E "++" { code_t*c = 0;
3553              classinfo_t*type = $1.t;
3554              if(is_getlocal($1.c) && (TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t))) {
3555                  int nr = getlocalnr($1.c);
3556                  code_free($1.c);$1.c=0;
3557                  if(TYPE_IS_INT($1.t)) {
3558                     $$.c = abc_getlocal(0, nr);
3559                     $$.c = abc_inclocal_i($$.c, nr);
3560                  } else if(TYPE_IS_NUMBER($1.t)) {
3561                     $$.c = abc_getlocal(0, nr);
3562                     $$.c = abc_inclocal($$.c, nr);
3563                  } else syntaxerror("internal error");
3564              } else {
3565                  if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3566                      c=abc_increment_i(c);
3567                      type = TYPE_INT;
3568                  } else {
3569                      c=abc_increment(c);
3570                      type = TYPE_NUMBER;
3571                  }
3572                  c=converttype(c, type, $1.t);
3573                  $$.c = toreadwrite($1.c, c, 0, 1);
3574                  $$.t = $1.t;
3575              }
3576            }
3577
3578 // TODO: use inclocal, like with ++
3579 E : E "--" { code_t*c = 0;
3580              classinfo_t*type = $1.t;
3581              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3582                  c=abc_decrement_i(c);
3583                  type = TYPE_INT;
3584              } else {
3585                  c=abc_decrement(c);
3586                  type = TYPE_NUMBER;
3587              }
3588              c=converttype(c, type, $1.t);
3589              $$.c = toreadwrite($1.c, c, 0, 1);
3590              $$.t = $1.t;
3591             }
3592
3593 E : "++" %prec plusplus_prefix E { code_t*c = 0;
3594              classinfo_t*type = $2.t;
3595              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3596                  c=abc_increment_i(c);
3597                  type = TYPE_INT;
3598              } else {
3599                  c=abc_increment(c);
3600                  type = TYPE_NUMBER;
3601              }
3602              c=converttype(c, type, $2.t);
3603              $$.c = toreadwrite($2.c, c, 0, 0);
3604              $$.t = $2.t;
3605            }
3606
3607 E : "--" %prec minusminus_prefix E { code_t*c = 0;
3608              classinfo_t*type = $2.t;
3609              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3610                  c=abc_decrement_i(c);
3611                  type = TYPE_INT;
3612              } else {
3613                  c=abc_decrement(c);
3614                  type = TYPE_NUMBER;
3615              }
3616              c=converttype(c, type, $2.t);
3617              $$.c = toreadwrite($2.c, c, 0, 0);
3618              $$.t = $2.t;
3619            }
3620
3621 E : "super" '.' T_IDENTIFIER 
3622            { if(!state->cls->info)
3623                   syntaxerror("super keyword not allowed outside a class");
3624               classinfo_t*t = state->cls->info->superclass;
3625               if(!t) t = TYPE_OBJECT;
3626
3627               memberinfo_t*f = findmember_nsset(t, $3, 1);
3628
3629               MEMBER_MULTINAME(m, f, $3);
3630               $$.c = 0;
3631               $$.c = abc_getlocal_0($$.c);
3632               $$.c = abc_getsuper2($$.c, &m);
3633               $$.t = slotinfo_gettype((slotinfo_t*)f);
3634            }
3635
3636 E : '@' T_IDENTIFIER {
3637               // attribute TODO
3638               $$.c = abc_pushundefined(0);
3639               $$.t = 0;
3640               as3_warning("ignored @ operator");
3641            }
3642
3643 E : E '.' '@' T_IDENTIFIER {
3644               // child attribute  TODO
3645               $$.c = abc_pushundefined(0);
3646               $$.t = 0;
3647               as3_warning("ignored .@ operator");
3648            }
3649
3650 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3651               // namespace declaration TODO
3652               $$.c = abc_pushundefined(0);
3653               $$.t = 0;
3654               as3_warning("ignored :: operator");
3655            }
3656
3657 E : E ".." T_IDENTIFIER {
3658               // descendants TODO
3659               $$.c = abc_pushundefined(0);
3660               $$.t = 0;
3661               as3_warning("ignored .. operator");
3662            }
3663
3664 E : E '.' '(' E ')' {
3665               // filter TODO
3666               $$.c = abc_pushundefined(0);
3667               $$.t = 0;
3668               as3_warning("ignored .() operator");
3669            }
3670
3671 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
3672
3673
3674
3675 E : E '.' T_IDENTIFIER {
3676     $$.c = $1.c;
3677     classinfo_t*t = $1.t;
3678     char is_static = 0;
3679     if(TYPE_IS_CLASS(t) && t->data) {
3680         t = t->data;
3681         is_static = 1;
3682     }
3683     if(t) {
3684         if(t->subtype==INFOTYPE_UNRESOLVED) {
3685             syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3686         }
3687         memberinfo_t*f = findmember_nsset(t, $3, 1);
3688         char noslot = 0;
3689         if(f && !is_static != !(f->flags&FLAG_STATIC))
3690            noslot=1;
3691         if(f && f->slot && !noslot) {
3692             $$.c = abc_getslot($$.c, f->slot);
3693         } else {
3694             MEMBER_MULTINAME(m, f, $3);
3695             $$.c = abc_getproperty2($$.c, &m);
3696         }
3697         /* determine type */
3698         $$.t = slotinfo_gettype((slotinfo_t*)f);
3699         if(!$$.t)
3700            $$.c = abc_coerce_a($$.c);
3701     } else if($1.c && $1.c->opcode == OPCODE___PUSHPACKAGE__) {
3702         string_t*package = $1.c->data[0];
3703         char*package2 = concat3(package->str, ".", $3);
3704
3705         slotinfo_t*a = registry_find(package->str, $3);
3706         if(a) {
3707             $$ = push_class(a);
3708         } else if(dict_contains(state->import_toplevel_packages, package2) ||
3709                   registry_ispackage(package2)) {
3710             $$.c = $1.c;
3711             $$.c->data[0] = string_new4(package2);
3712             $$.t = 0;
3713         } else {
3714             syntaxerror("couldn't resolve %s", package2);
3715         }
3716     } else {
3717         /* when resolving a property on an unknown type, we do know the
3718            name of the property (and don't seem to need the package), but
3719            we need to make avm2 try out all access modes */
3720         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3721         $$.c = abc_getproperty2($$.c, &m);
3722         $$.c = abc_coerce_a($$.c);
3723         $$.t = registry_getanytype();
3724     }
3725 }
3726
3727 VAR_READ : T_IDENTIFIER {
3728     PASS1
3729     /* Queue unresolved identifiers for checking against the parent
3730        function's variables.
3731        We consider everything which is not a local variable "unresolved".
3732        This encompasses class names, members of the surrounding class
3733        etc. which is *correct* because local variables of the parent function
3734        would shadow those.
3735        */
3736     if(state->method->inner && !find_variable(state, $1)) {
3737         unknown_variable($1);
3738     }
3739    
3740     /* let the compiler know that it might want to check the current directory/package
3741        for this identifier- maybe there's a file $1.as defining $1. */
3742     //as3_schedule_class_noerror(state->package, $1);
3743     PASS2
3744
3745     $$.t = 0;
3746     $$.c = 0;
3747     slotinfo_t*a = 0;
3748     memberinfo_t*f = 0;
3749
3750     variable_t*v;
3751     /* look at variables */
3752     if((v = find_variable(state, $1))) {
3753         // $1 is a local variable
3754         $$.c = abc_getlocal($$.c, v->index);
3755         $$.t = v->type;
3756         break;
3757     }
3758     if((v = find_slot(state, $1))) {
3759         $$.c = abc_getscopeobject($$.c, 1);
3760         $$.c = abc_getslot($$.c, v->index);
3761         $$.t = v->type;
3762         break;
3763     }
3764
3765     int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3766
3767     /* look at current class' members */
3768     if(!state->method->inner && 
3769         state->cls && 
3770         (f = findmember_nsset(state->cls->info, $1, 1)) &&
3771         (f->flags&FLAG_STATIC) >= i_am_static) 
3772     {
3773         // $1 is a function in this class
3774         int var_is_static = (f->flags&FLAG_STATIC);
3775
3776         if(f->kind == INFOTYPE_METHOD) {
3777             $$.t = TYPE_FUNCTION(f);
3778         } else {
3779             $$.t = f->type;
3780         }
3781         if(var_is_static && !i_am_static) {
3782         /* access to a static member from a non-static location.
3783            do this via findpropstrict:
3784            there doesn't seem to be any non-lookup way to access
3785            static properties of a class */
3786             state->method->late_binding = 1;
3787             $$.t = f->type;
3788             namespace_t ns = {f->access, ""};
3789             multiname_t m = {QNAME, &ns, 0, $1};
3790             $$.c = abc_findpropstrict2($$.c, &m);
3791             $$.c = abc_getproperty2($$.c, &m);
3792             break;
3793         } else if(f->slot>0) {
3794             $$.c = abc_getlocal_0($$.c);
3795             $$.c = abc_getslot($$.c, f->slot);
3796             break;
3797         } else {
3798             namespace_t ns = {f->access, ""};
3799             multiname_t m = {QNAME, &ns, 0, $1};
3800             $$.c = abc_getlocal_0($$.c);
3801             $$.c = abc_getproperty2($$.c, &m);
3802             break;
3803         }
3804     } 
3805     
3806     /* look at actual classes, in the current package and imported */
3807     if((a = find_class($1))) {
3808         $$ = push_class(a);
3809         break;
3810     }
3811
3812     /* look through package prefixes */
3813     if(dict_contains(state->import_toplevel_packages, $1) || 
3814        registry_ispackage($1)) {
3815         $$.c = abc___pushpackage__($$.c, $1);
3816         $$.t = 0;
3817         break;
3818     }
3819
3820     /* unknown object, let the avm2 resolve it */
3821     if(1) {
3822         //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3823         as3_warning("Couldn't resolve '%s', doing late binding", $1);
3824         state->method->late_binding = 1;
3825                 
3826         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3827
3828         $$.t = 0;
3829         $$.c = abc_findpropstrict2($$.c, &m);
3830         $$.c = abc_getproperty2($$.c, &m);
3831     }
3832 }
3833
3834 // ----------------- namespaces -------------------------------------------------
3835
3836 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3837     PASS12
3838     NEW(namespace_decl_t,n);
3839     n->name = $2;
3840     n->url = $2;
3841     $$=n;
3842 }
3843 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3844     PASS12
3845     NEW(namespace_decl_t,n);
3846     n->name = $2;
3847     n->url = $4;
3848     $$=n;
3849 }
3850 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3851     PASS12
3852     NEW(namespace_decl_t,n);
3853     n->name = $2;
3854     n->url = $4.str;
3855     $$=n;
3856 }
3857 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3858     PASS12
3859     trie_put(active_namespaces, $2->name, (void*)$2->url);
3860
3861     namespace_t access = modifiers2access(&$1);
3862     varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3863     var->type = TYPE_NAMESPACE;
3864     namespace_t ns;
3865     ns.access = ACCESS_NAMESPACE;
3866     ns.name = $2->url;
3867     var->value = constant_new_namespace(&ns);
3868
3869     $$=0;
3870 }
3871
3872 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3873     
3874     const char*url = $3->name;
3875     varinfo_t*s = (varinfo_t*)$3;
3876     if(!s || s->kind != INFOTYPE_SLOT)
3877         syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3878     if(!s->value || !NS_TYPE(s->value->type))
3879         syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3880     url = s->value->ns->name;
3881
3882     trie_put(active_namespaces, $3->name, (void*)url);
3883     add_active_url(url);
3884     $$=0;
3885 }
3886