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