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