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