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