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