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