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