small fix in dynamic handling
[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
35 %}
36
37 //%glr-parser
38 //%expect-rr 1
39 %error-verbose
40
41 %union tokenunion {
42     enum yytokentype token;
43     int flags;
44
45     classinfo_t*classinfo;
46     classinfo_list_t*classinfo_list;
47
48     int number_int;
49     unsigned int number_uint;
50     double number_float;
51     code_t*code;
52     typedcode_t value;
53     typedcode_list_t*value_list;
54     param_t* param;
55     params_t params;
56     string_t str;
57     char*id;
58     constant_t*constant;
59 }
60
61
62 %token<id> T_IDENTIFIER
63 %token<str> T_STRING
64 %token<token> T_REGEXP
65 %token<token> T_EMPTY
66 %token<number_int> T_INT
67 %token<number_uint> T_UINT
68 %token<number_uint> T_BYTE
69 %token<number_uint> T_SHORT
70 %token<number_float> T_FLOAT
71
72 %token<token> KW_IMPLEMENTS
73 %token<token> KW_NAMESPACE "namespace"
74 %token<token> KW_PACKAGE "package"
75 %token<token> KW_PROTECTED
76 %token<token> KW_PUBLIC
77 %token<token> KW_PRIVATE
78 %token<token> KW_USE "use"
79 %token<token> KW_INTERNAL
80 %token<token> KW_NEW "new"
81 %token<token> KW_NATIVE
82 %token<token> KW_FUNCTION "function"
83 %token<token> KW_UNDEFINED "undefined"
84 %token<token> KW_CONTINUE "continue"
85 %token<token> KW_FOR "for"
86 %token<token> KW_CLASS "class"
87 %token<token> KW_CONST "const"
88 %token<token> KW_SET "set"
89 %token<token> KW_VOID "void"
90 %token<token> KW_STATIC
91 %token<token> KW_INSTANCEOF "instanceof"
92 %token<token> KW_IMPORT "import"
93 %token<token> KW_RETURN "return"
94 %token<token> KW_TYPEOF "typeof"
95 %token<token> KW_INTERFACE "interface"
96 %token<token> KW_NULL "null"
97 %token<token> KW_VAR "var"
98 %token<token> KW_DYNAMIC "dynamic"
99 %token<token> KW_OVERRIDE
100 %token<token> KW_FINAL
101 %token<token> KW_GET "get"
102 %token<token> KW_SUPER "super"
103 %token<token> KW_EXTENDS
104 %token<token> KW_FALSE "false"
105 %token<token> KW_TRUE "true"
106 %token<token> KW_BOOLEAN "Boolean"
107 %token<token> KW_UINT "uint"
108 %token<token> KW_INT "int"
109 %token<token> KW_WHILE "while"
110 %token<token> KW_NUMBER "Number"
111 %token<token> KW_STRING "String"
112 %token<token> KW_DELETE "delete"
113 %token<token> KW_IF "if"
114 %token<token> KW_ELSE  "else"
115 %token<token> KW_BREAK   "break"
116 %token<token> KW_IS "is"
117 %token<token> KW_AS "as"
118 %token<token> KW_DO "do"
119
120 %token<token> T_EQEQ "=="
121 %token<token> T_EQEQEQ "==="
122 %token<token> T_NE "!="
123 %token<token> T_NEE "!=="
124 %token<token> T_LE "<="
125 %token<token> T_GE ">="
126 %token<token> T_DIVBY "/=" 
127 %token<token> T_MODBY "%="
128 %token<token> T_MULBY "*="
129 %token<token> T_PLUSBY "+=" 
130 %token<token> T_MINUSBY "-="
131 %token<token> T_SHRBY ">>="
132 %token<token> T_SHLBY "<<="
133 %token<token> T_USHRBY ">>>="
134 %token<token> T_OROR "||"
135 %token<token> T_ANDAND "&&"
136 %token<token> T_COLONCOLON "::"
137 %token<token> T_MINUSMINUS "--"
138 %token<token> T_PLUSPLUS "++"
139 %token<token> T_DOTDOT ".."
140 %token<token> T_DOTDOTDOT "..."
141 %token<token> T_SHL "<<"
142 %token<token> T_USHR ">>>"
143 %token<token> T_SHR ">>"
144
145 %type <id> X_IDENTIFIER PACKAGE MAYBELABEL
146 %type <token> VARCONST
147 %type <code> CODE
148 %type <code> CODEPIECE
149 %type <code> CODEBLOCK MAYBECODE
150 %type <token> PACKAGE_DECLARATION
151 %type <token> FUNCTION_DECLARATION
152 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
153 %type <token> CLASS_DECLARATION
154 %type <token> NAMESPACE_DECLARATION
155 %type <token> INTERFACE_DECLARATION
156 %type <code> VOIDEXPRESSION
157 %type <value> EXPRESSION NONCOMMAEXPRESSION
158 %type <value> MAYBEEXPRESSION
159 %type <value> E DELETE
160 %type <value> CONSTANT
161 %type <code> FOR IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
162 %type <token> USE_NAMESPACE
163 %type <code> FOR_INIT
164 %type <token> IMPORT
165 %type <classinfo> MAYBETYPE
166 %type <token> GETSET
167 %type <param> PARAM
168 %type <params> PARAM_LIST
169 %type <params> MAYBE_PARAM_LIST
170 %type <flags> MAYBE_MODIFIERS
171 %type <flags> MODIFIER_LIST
172 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
173 %type <classinfo_list> IMPLEMENTS_LIST
174 %type <classinfo> EXTENDS
175 %type <classinfo_list> EXTENDS_LIST
176 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
177 %type <classinfo_list> QNAME_LIST
178 %type <classinfo> TYPE
179 %type <token> VAR
180 //%type <token> VARIABLE
181 %type <value> VAR_READ
182 %type <value> NEW
183 //%type <token> T_IDENTIFIER
184 %type <token> MODIFIER
185 %type <value> FUNCTIONCALL
186 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
187
188 // precedence: from low to high
189
190 %left prec_none
191
192 %left below_semicolon
193 %left ';'
194 %left ','
195 %nonassoc below_assignment // for ?:, contrary to spec
196 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
197 %right '?' ':'
198 %left "||"
199 %left "&&"
200 %nonassoc '|'
201 %nonassoc '^'
202 %nonassoc '&'
203 %nonassoc "==" "!=" "===" "!=="
204 %nonassoc "is" "as"
205 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
206 %left "<<" ">>" ">>>" 
207 %left below_minus
208 %left '-' '+'
209 %left '/' '*' '%'
210 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
211 %left "--" "++" 
212 %left '[' ']' '{' "new" '.' ".." "::"
213 %nonassoc T_IDENTIFIER
214 %left below_else
215 %nonassoc "else"
216 %left '('
217
218 // needed for "return" precedence:
219 %nonassoc T_STRING T_REGEXP
220 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
221 %nonassoc "false" "true" "null" "undefined" "super"
222
223      
224 %{
225
226 static int yyerror(char*s)
227 {
228    syntaxerror("%s", s); 
229 }
230 static char* concat3str(const char* t1, const char* t2, const char* t3)
231 {
232     int l1 = strlen(t1);
233     int l2 = strlen(t2);
234     int l3 = strlen(t3);
235     char*text = malloc(l1+l2+l3+1);
236     memcpy(text   , t1, l1);
237     memcpy(text+l1, t2, l2);
238     memcpy(text+l1+l2, t3, l3);
239     text[l1+l2+l3] = 0;
240     return text;
241 }
242
243 typedef struct _import {
244     char*package;
245 } import_t;
246
247 DECLARE_LIST(import);
248
249 typedef struct _classstate {
250     /* class data */
251     classinfo_t*info;
252     abc_class_t*abc;
253     code_t*init;
254     code_t*static_init;
255     char has_constructor;
256 } classstate_t;
257
258 typedef struct _methodstate {
259     /* method data */
260     memberinfo_t*info;
261     char late_binding;
262     /* code that needs to be executed at the start of
263        a method (like initializing local registers) */
264     code_t*initcode;
265     char is_constructor;
266     char has_super;
267 } methodstate_t;
268
269 typedef struct _state {
270     int level;
271
272     char*package;     
273     import_list_t*wildcard_imports;
274     dict_t*imports;
275     char has_own_imports;
276   
277     classstate_t*cls;   
278     methodstate_t*method;
279     
280     dict_t*vars;
281 } state_t;
282
283 typedef struct _global {
284     abc_file_t*file;
285     abc_script_t*init;
286
287     int variable_count;
288 } global_t;
289
290 static global_t*global = 0;
291 static state_t* state = 0;
292
293 DECLARE_LIST(state);
294
295 #define MULTINAME(m,x) \
296     multiname_t m;\
297     namespace_t m##_ns;\
298     registry_fill_multiname(&m, &m##_ns, x);
299                     
300 #define MEMBER_MULTINAME(m,f,n) \
301     multiname_t m;\
302     namespace_t m##_ns;\
303     if(f) { \
304         m##_ns.access = flags2access(f->flags); \
305         m##_ns.name = ""; \
306         m.type = QNAME; \
307         m.ns = &m##_ns; \
308         m.namespace_set = 0; \
309         m.name = f->name; \
310     } else { \
311         m.type = MULTINAME; \
312         m.ns =0; \
313         m.namespace_set = &nopackage_namespace_set; \
314         m.name = n; \
315     }
316
317 /* warning: list length of namespace set is undefined */
318 #define MULTINAME_LATE(m, access, package) \
319     namespace_t m##_ns = {access, package}; \
320     namespace_set_t m##_nsset; \
321     namespace_list_t m##_l;m##_l.next = 0; \
322     m##_nsset.namespaces = &m##_l; \
323     m##_nsset = m##_nsset; \
324     m##_l.namespace = &m##_ns; \
325     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
326
327 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
328 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
329 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
330 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
331 static namespace_list_t nl4 = {&ns4,0};
332 static namespace_list_t nl3 = {&ns3,&nl4};
333 static namespace_list_t nl2 = {&ns2,&nl3};
334 static namespace_list_t nl1 = {&ns1,&nl2};
335 static namespace_set_t nopackage_namespace_set = {&nl1};
336
337 static state_list_t*state_stack=0;
338     
339 static void init_globals()
340 {
341     global = rfx_calloc(sizeof(global_t));
342 }
343
344 static void new_state()
345 {
346     NEW(state_t, s);
347     NEW(state_list_t, sl);
348
349     state_t*oldstate = state;
350     if(state)
351         memcpy(s, state, sizeof(state_t)); //shallow copy
352     sl->next = state_stack;
353     sl->state = s;
354     if(!s->imports) {
355         s->imports = dict_new();
356     }
357     state_stack = sl;
358     state = s;
359     state->level++;
360     state->has_own_imports = 0;    
361     state->vars = dict_new();
362 }
363 static void state_has_imports()
364 {
365     state->wildcard_imports = list_clone(state->wildcard_imports);
366     state->imports = dict_clone(state->imports);
367     state->has_own_imports = 1;
368 }
369
370 static void old_state()
371 {
372     if(!state_stack || !state_stack->next)
373         syntaxerror("invalid nesting");
374     state_t*oldstate = state;
375     state_list_t*old = state_stack;
376     state_stack = state_stack->next;
377     free(old);
378     state = state_stack->state;
379     /*if(state->method->initcode) {
380         printf("residual initcode\n");
381         code_dump(state->method->initcode, 0, 0, "", stdout);
382     }*/
383     if(oldstate->has_own_imports) {
384         list_free(oldstate->wildcard_imports);
385         dict_destroy(oldstate->imports);oldstate->imports=0;
386     }
387 }
388 void initialize_state()
389 {
390     init_globals();
391     new_state();
392
393     global->file = abc_file_new();
394     global->file->flags &= ~ABCFILE_LAZY;
395     
396     global->init = abc_initscript(global->file, 0);
397     code_t*c = global->init->method->body->code;
398
399     c = abc_getlocal_0(c);
400     c = abc_pushscope(c);
401   
402     /* findpropstrict doesn't just return a scope object- it
403        also makes it "active" somehow. Push local_0 on the
404        scope stack and read it back with findpropstrict, it'll
405        contain properties like "trace". Trying to find the same
406        property on a "vanilla" local_0 yields only a "undefined" */
407     //c = abc_findpropstrict(c, "[package]::trace");
408     
409     /*c = abc_getlocal_0(c);
410     c = abc_findpropstrict(c, "[package]::trace");
411     c = abc_coerce_a(c);
412     c = abc_setlocal_1(c);
413
414     c = abc_pushbyte(c, 0);
415     c = abc_setlocal_2(c);
416    
417     code_t*xx = c = abc_label(c);
418     c = abc_findpropstrict(c, "[package]::trace");
419     c = abc_pushstring(c, "prop:");
420     c = abc_hasnext2(c, 1, 2);
421     c = abc_dup(c);
422     c = abc_setlocal_3(c);
423     c = abc_callpropvoid(c, "[package]::trace", 2);
424     c = abc_getlocal_3(c);
425     c = abc_kill(c, 3);
426     c = abc_iftrue(c,xx);*/
427
428     c = abc_findpropstrict(c, "[package]::trace");
429     c = abc_pushstring(c, "[entering global init function]");
430     c = abc_callpropvoid(c, "[package]::trace", 1);
431     
432     global->init->method->body->code = c;
433 }
434 void* finalize_state()
435 {
436     if(state->level!=1) {
437         syntaxerror("unexpected end of file");
438     }
439     abc_method_body_t*m = global->init->method->body;
440     //__ popscope(m);
441     
442     __ findpropstrict(m, "[package]::trace");
443     __ pushstring(m, "[leaving global init function]");
444     __ callpropvoid(m, "[package]::trace", 1);
445     __ returnvoid(m);
446     return global->file;
447 }
448
449
450 static void startpackage(char*name)
451 {
452     if(state->package) {
453         syntaxerror("Packages can not be nested."); 
454     } 
455     new_state();
456     /*printf("entering package \"%s\"\n", name);*/
457     state->package = name;
458 }
459 static void endpackage()
460 {
461     /*printf("leaving package \"%s\"\n", state->package);*/
462     old_state();
463 }
464
465 char*globalclass=0;
466 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
467 {
468     if(state->cls) {
469         syntaxerror("inner classes now allowed"); 
470     }
471     new_state();
472     state->cls = rfx_calloc(sizeof(classstate_t));
473
474     token_list_t*t=0;
475     classinfo_list_t*mlist=0;
476     /*printf("entering class %s\n", name);
477     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
478     if(extends) 
479         printf("  extends: %s.%s\n", extends->package, extends->name);
480     printf("  implements (%d): ", list_length(implements));
481     for(mlist=implements;mlist;mlist=mlist->next)  {
482         printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
483     }
484     printf("\n");
485     */
486
487     if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
488         syntaxerror("invalid modifier(s)");
489
490     if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
491         syntaxerror("public and internal not supported at the same time.");
492
493     /* create the class name, together with the proper attributes */
494     int access=0;
495     char*package=0;
496
497     if(!(flags&FLAG_PUBLIC) && !state->package) {
498         access = ACCESS_PRIVATE; package = current_filename;
499     } else if(!(flags&FLAG_PUBLIC) && state->package) {
500         access = ACCESS_PACKAGEINTERNAL; package = state->package;
501     } else if(state->package) {
502         access = ACCESS_PACKAGE; package = state->package;
503     } else {
504         syntaxerror("public classes only allowed inside a package");
505     }
506
507     if(registry_findclass(package, classname)) {
508         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
509     }
510    
511
512     /* build info struct */
513     int num_interfaces = (list_length(implements));
514     state->cls->info = classinfo_register(access, package, classname, num_interfaces);
515     state->cls->info->superclass = extends?extends:TYPE_OBJECT;
516     int pos = 0;
517     classinfo_list_t*l = implements;
518     for(l=implements;l;l=l->next) {
519         state->cls->info->interfaces[pos++] = l->classinfo;
520     }
521     
522     multiname_t*extends2 = sig2mname(extends);
523
524     MULTINAME(classname2,state->cls->info);
525
526     /*if(extends) {
527         state->cls_init = abc_getlocal_0(state->cls_init);
528         state->cls_init = abc_constructsuper(state->cls_init, 0);
529     }*/
530
531     state->cls->abc = abc_class_new(global->file, &classname2, extends2);
532     if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
533     if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
534     if(interface) {
535         state->cls->info->flags |= CLASS_INTERFACE;
536         abc_class_interface(state->cls->abc);
537     }
538
539     abc_class_protectedNS(state->cls->abc, classname);
540
541     for(mlist=implements;mlist;mlist=mlist->next) {
542         MULTINAME(m, mlist->classinfo);
543         abc_class_add_interface(state->cls->abc, &m);
544     }
545
546     /* now write the construction code for this class */
547     int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
548
549     abc_method_body_t*m = global->init->method->body;
550     __ getglobalscope(m);
551     classinfo_t*s = extends;
552
553     int count=0;
554     
555     while(s) {
556         //TODO: take a look at the current scope stack, maybe 
557         //      we can re-use something
558         s = s->superclass;
559         if(!s) 
560         break;
561        
562         multiname_t*s2 = sig2mname(s);
563         __ getlex2(m, s2);
564         multiname_destroy(s2);
565
566         __ pushscope(m); count++;
567         m->code = m->code->prev->prev; // invert
568     }
569     /* continue appending after last op end */
570     while(m->code && m->code->next) m->code = m->code->next; 
571
572     /* TODO: if this is one of *our* classes, we can also 
573              do a getglobalscope/getslot <nr> (which references
574              the init function's slots) */
575     if(extends2) {
576         __ getlex2(m, extends2);
577         __ dup(m);
578         /* notice: we get a Verify Error #1107 if the top elemnt on the scope
579            stack is not the superclass */
580         __ pushscope(m);count++;
581     } else {
582         __ pushnull(m);
583         /* notice: we get a verify error #1107 if the top element on the scope 
584            stack is not the global object */
585         __ getlocal_0(m);
586         __ pushscope(m);count++;
587     }
588     __ newclass(m,state->cls->abc);
589     while(count--) {
590         __ popscope(m);
591     }
592     __ setslot(m, slotindex);
593
594     /* flash.display.MovieClip handling */
595     if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
596         if(state->package && state->package[0]) {
597             globalclass = concat3str(state->package, ".", classname);
598         } else {
599             globalclass = strdup(classname);
600         }
601     }
602     multiname_destroy(extends2);
603 }
604
605 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
606 {
607     c = code_append(c, initcode);
608     c = code_append(c, body);
609     /* append return if necessary */
610     if(!c || c->opcode != OPCODE_RETURNVOID && 
611              c->opcode != OPCODE_RETURNVALUE) {
612         c = abc_returnvoid(c);
613     }
614     return c;
615 }
616
617 static void endclass()
618 {
619     if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
620         code_t*c = 0;
621         c = abc_getlocal_0(c);
622         c = abc_constructsuper(c, 0);
623         state->cls->init = code_append(state->cls->init, c);
624     }
625
626     if(state->cls->init) {
627         abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
628         m->body->code = wrap_function(0, state->cls->init, m->body->code);
629     }
630     if(state->cls->static_init) {
631         abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
632         m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
633     } else {
634         // handy for scope testing 
635         /*code_t*c = 0;
636         c = abc_pop(c);
637         c = abc_pop(c);
638         abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
639     }
640
641     old_state();
642 }
643
644 typedef struct _variable {
645     int index;
646     classinfo_t*type;
647 } variable_t;
648
649 static int find_variable(char*name, classinfo_t**m)
650 {
651     state_list_t* s = state_stack;
652     while(s) {
653         variable_t*v = 0;
654         if(s->state->method)
655             v = dict_lookup(s->state->vars, name);
656         if(v) {
657             if(m) {
658                 *m = v->type;
659             }
660             return v->index;
661         }
662         s = s->next;
663     }
664     return -1;
665
666 static int find_variable_safe(char*name, classinfo_t**m)
667 {
668     int i = find_variable(name, m);
669     if(i<0)
670         syntaxerror("undefined variable: %s", name);
671     return i;
672 }
673 static char variable_exists(char*name) 
674 {
675     return dict_lookup(state->vars, name)!=0;
676 }
677 static int new_variable(char*name, classinfo_t*type)
678 {
679     NEW(variable_t, v);
680     v->index = global->variable_count;
681     v->type = type;
682     dict_put(state->vars, name, v);
683     return global->variable_count++;
684 }
685 #define TEMPVARNAME "__as3_temp__"
686 static int gettempvar()
687 {
688     int i = find_variable(TEMPVARNAME, 0);
689     if(i<0) {
690         i = new_variable(TEMPVARNAME, 0);
691     }
692     return i;
693 }
694
695 code_t* killvars(code_t*c) 
696 {
697     int t;
698     for(t=0;t<state->vars->hashsize;t++) {
699         dictentry_t*e =state->vars->slots[t];
700         while(e) {
701             variable_t*v = (variable_t*)e->data;
702             //do this always, otherwise register types don't match
703             //in the verifier when doing nested loops
704             //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
705             c = abc_kill(c, v->index);
706             e = e->next;
707         }
708     }
709     return c;
710 }
711
712 void check_code_for_break(code_t*c)
713 {
714     while(c) {
715         if(c->opcode == OPCODE___BREAK__) {
716             char*name = string_cstr(c->data[0]);
717             syntaxerror("Unresolved \"break %s\"", name);
718         }
719         if(c->opcode == OPCODE___CONTINUE__) {
720             char*name = string_cstr(c->data[0]);
721             syntaxerror("Unresolved \"continue %s\"", name);
722         }
723         c=c->prev;
724     }
725 }
726
727
728 static void check_constant_against_type(classinfo_t*t, constant_t*c)
729 {
730 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
731    if(TYPE_IS_NUMBER(t)) {
732         xassert(c->type == CONSTANT_FLOAT
733              || c->type == CONSTANT_INT
734              || c->type == CONSTANT_UINT);
735    } else if(TYPE_IS_UINT(t)) {
736         xassert(c->type == CONSTANT_UINT ||
737                (c->type == CONSTANT_INT && c->i>0));
738    } else if(TYPE_IS_INT(t)) {
739         xassert(c->type == CONSTANT_INT);
740    } else if(TYPE_IS_BOOLEAN(t)) {
741         xassert(c->type == CONSTANT_TRUE
742              || c->type == CONSTANT_FALSE);
743    }
744 }
745
746 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
747 {
748     memberinfo_t*minfo = 0;
749     if(getset != KW_GET && getset != KW_SET) {
750         if(registry_findmember(state->cls->info, name)) {
751             syntaxerror("class already contains a member/method called '%s'", name);
752         }
753         minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
754         minfo->return_type = return_type;
755         // getslot on a member slot only returns "undefined", so no need
756         // to actually store these
757         //state->minfo->slot = state->method->abc->method->trait->slot_id;
758     } else {
759         int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
760         classinfo_t*type=0;
761         if(getset == KW_GET)
762             type = return_type;
763         else if(params->list)
764             type = params->list->param->type;
765         if((minfo=registry_findmember(state->cls->info, name))) {
766             if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
767                 syntaxerror("class already contains a member or method called '%s'", name);
768             if(minfo->kind & gs)
769                 syntaxerror("getter/setter for '%s' already defined", name);
770             /* make a setter or getter into a getset */
771             minfo->kind |= gs;
772             if(!minfo->type) 
773                 minfo->type = type;
774             else
775                 if(type && minfo->type != type)
776                     syntaxerror("different type in getter and setter");
777         } else {
778             minfo = memberinfo_register(state->cls->info, name, gs);
779             minfo->type = type;
780         }
781         /* can't assign a slot as getter and setter might have different slots */
782         //minfo->slot = slot;
783     }
784     if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
785     if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
786     if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
787     if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
788     if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
789     return minfo;
790 }
791
792 static int flags2access(int flags)
793 {
794     int access = 0;
795     if(flags&FLAG_PUBLIC)  {
796         if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
797         access = ACCESS_PACKAGE;
798     } else if(flags&FLAG_PRIVATE) {
799         if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
800         access = ACCESS_PRIVATE;
801     } else if(flags&FLAG_PROTECTED) {
802         if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
803         access = ACCESS_PROTECTED;
804     } else {
805         access = ACCESS_PACKAGEINTERNAL;
806     }
807     return access;
808 }
809
810 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
811                           params_t*params, classinfo_t*return_type)
812 {
813     if(state->method) {
814         syntaxerror("not able to start another method scope");
815     }
816     new_state();
817     state->method = rfx_calloc(sizeof(methodstate_t));
818     state->method->initcode = 0;
819     state->method->is_constructor = !strcmp(state->cls->info->name,name);
820     state->method->has_super = 0;
821     
822     state->cls->has_constructor |= state->method->is_constructor;
823
824     global->variable_count = 0;
825
826     /* state->vars is initialized by state_new */
827     if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
828     param_list_t*p=0;
829     for(p=params->list;p;p=p->next) {
830         new_variable(p->param->name, p->param->type);
831     }
832     if(state->method->is_constructor)
833         name = "__as3_constructor__";
834     state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
835 }
836
837 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
838                           params_t*params, classinfo_t*return_type, code_t*body)
839 {
840     namespace_t mname_ns = {flags2access(flags), ""};
841     multiname_t mname = {QNAME, &mname_ns, 0, name};
842
843     abc_method_t*f = 0;
844
845     multiname_t*type2 = sig2mname(return_type);
846     int slot = 0;
847     if(state->method->is_constructor) {
848         f = abc_class_getconstructor(state->cls->abc, type2);
849     } else {
850         if(flags&FLAG_STATIC)
851             f = abc_class_staticmethod(state->cls->abc, type2, &mname);
852         else
853             f = abc_class_method(state->cls->abc, type2, &mname);
854         slot = f->trait->slot_id;
855     }
856     //flash doesn't seem to allow us to access function slots
857     //state->method->info->slot = slot;
858
859     if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
860     if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
861     if(params->varargs) f->flags |= METHOD_NEED_REST;
862
863     char opt=0;
864     param_list_t*p=0;
865     for(p=params->list;p;p=p->next) {
866         if(params->varargs && !p->next) {
867             break; //varargs: omit last parameter in function signature
868         }
869         multiname_t*m = sig2mname(p->param->type);
870         list_append(f->parameters, m);
871         if(p->param->value) {
872             check_constant_against_type(p->param->type, p->param->value);
873             opt=1;list_append(f->optional_parameters, p->param->value);
874         } else if(opt) {
875             syntaxerror("non-optional parameter not allowed after optional parameters");
876         }
877     }
878     check_code_for_break(body);
879
880     if(f->body)
881         f->body->code = body;
882     else //interface
883         if(body)
884             syntaxerror("interface methods can't have a method body");
885         
886     old_state();
887 }
888
889
890
891 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
892 {
893     return 1; // FIXME
894 }
895
896 void breakjumpsto(code_t*c, char*name, code_t*jump) 
897 {
898     while(c) {
899         if(c->opcode == OPCODE___BREAK__) {
900             string_t*name2 = c->data[0];
901             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
902                 c->opcode = OPCODE_JUMP;
903                 c->branch = jump;
904             }
905         }
906         c=c->prev;
907     }
908 }
909 void continuejumpsto(code_t*c, char*name, code_t*jump) 
910 {
911     while(c) {
912         if(c->opcode == OPCODE___CONTINUE__) {
913             string_t*name2 = c->data[0];
914             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
915                 c->opcode = OPCODE_JUMP;
916                 c->branch = jump;
917             }
918         }
919         c = c->prev;
920     }
921 }
922
923 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
924 {
925     if(!type1 || !type2) 
926         return registry_getanytype();
927     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
928         return registry_getanytype();
929     if(type1 == type2)
930         return type1;
931     return registry_getanytype();
932 }
933 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
934 {
935     if(from==to)
936         return c;
937     if(!to) {
938         return abc_coerce_a(c);
939     }
940     MULTINAME(m, to);
941     if(!from) {
942         // cast an "any" type to a specific type. subject to
943         // runtime exceptions
944         return abc_coerce2(c, &m);
945     }
946     
947     if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
948         return abc_coerce2(c, &m);
949     }
950     if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
951         return abc_coerce2(c, &m);
952     }
953     /* these are subject to overflow */
954     if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
955         return abc_coerce2(c, &m);
956     }
957     if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
958         return abc_coerce2(c, &m);
959     }
960
961     classinfo_t*supertype = from;
962     while(supertype) {
963         if(supertype == to) {
964              // target type is one of from's superclasses
965              return abc_coerce2(c, &m);
966         }
967         int t=0;
968         while(supertype->interfaces[t]) {
969             if(supertype->interfaces[t]==to) {
970                 // to type is one of from's interfaces
971                 return abc_coerce2(c, &m);
972             }
973             t++;
974         }
975         supertype = supertype->superclass;
976     }
977     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
978         return c;
979     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
980         return c;
981     syntaxerror("can't convert type %s to %s", from->name, to->name);
982 }
983
984 code_t*defaultvalue(code_t*c, classinfo_t*type)
985 {
986     if(TYPE_IS_INT(type)) {
987        c = abc_pushbyte(c, 0);
988     } else if(TYPE_IS_UINT(type)) {
989        c = abc_pushuint(c, 0);
990     } else if(TYPE_IS_FLOAT(type)) {
991        c = abc_pushnan(c);
992     } else if(TYPE_IS_BOOLEAN(type)) {
993        c = abc_pushfalse(c);
994     } else {
995        c = abc_pushnull(c);
996     }
997     return c;
998 }
999
1000 char is_pushundefined(code_t*c)
1001 {
1002     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1003 }
1004
1005 void parserassert(int b)
1006 {
1007     if(!b) syntaxerror("internal error: assertion failed");
1008 }
1009
1010 static classinfo_t* find_class(char*name)
1011 {
1012     classinfo_t*c=0;
1013
1014     c = registry_findclass(state->package, name);
1015
1016     /* try explicit imports */
1017     dictentry_t* e = dict_get_slot(state->imports, name);
1018     while(e) {
1019         if(c)
1020             break;
1021         if(!strcmp(e->key, name)) {
1022             c = (classinfo_t*)e->data;
1023         }
1024         e = e->next;
1025     }
1026
1027     /* try package.* imports */
1028     import_list_t*l = state->wildcard_imports;
1029     while(l) {
1030         if(c)
1031             break;
1032         //printf("does package %s contain a class %s?\n", l->import->package, name);
1033         c = registry_findclass(l->import->package, name);
1034         l = l->next;
1035     }
1036
1037     /* try global package */
1038     if(!c) {
1039         c = registry_findclass("", name);
1040     }
1041     return c;
1042 }
1043
1044 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1045 {
1046     /* converts this:
1047
1048        [prefix code] [read instruction]
1049
1050        to this:
1051
1052        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1053     */
1054     
1055     if(in && in->opcode == OPCODE_COERCE_A) {
1056         in = code_cutlast(in);
1057     }
1058     if(in->next)
1059         syntaxerror("internal error");
1060
1061     /* chop off read instruction */
1062     code_t*prefix = in;
1063     code_t*r = in;
1064     if(r->prev) {
1065         prefix = r->prev;r->prev = 0;
1066         prefix->next=0;
1067     } else {
1068         prefix = 0;
1069     }
1070
1071     char use_temp_var = readbefore;
1072
1073     /* generate the write instruction, and maybe append a dup to the prefix code */
1074     code_t* write = abc_nop(0);
1075     if(r->opcode == OPCODE_GETPROPERTY) {
1076         write->opcode = OPCODE_SETPROPERTY;
1077         multiname_t*m = (multiname_t*)r->data[0];
1078         write->data[0] = multiname_clone(m);
1079         if(m->type == QNAME || m->type == MULTINAME) {
1080             if(!justassign) {
1081                 prefix = abc_dup(prefix); // we need the object, too
1082             }
1083             use_temp_var = 1;
1084         } else if(m->type == MULTINAMEL) {
1085             if(!justassign) {
1086                 /* dupping two values on the stack requires 5 operations and one register- 
1087                    couldn't adobe just have given us a dup2? */
1088                 int temp = gettempvar();
1089                 prefix = abc_setlocal(prefix, temp);
1090                 prefix = abc_dup(prefix);
1091                 prefix = abc_getlocal(prefix, temp);
1092                 prefix = abc_swap(prefix);
1093                 prefix = abc_getlocal(prefix, temp);
1094             }
1095             use_temp_var = 1;
1096         } else {
1097             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1098         }
1099     } else if(r->opcode == OPCODE_GETSLOT) {
1100         write->opcode = OPCODE_SETSLOT;
1101         write->data[0] = r->data[0];
1102         if(!justassign) {
1103             prefix = abc_dup(prefix); // we need the object, too
1104         }
1105         use_temp_var = 1;
1106     } else if(r->opcode == OPCODE_GETLOCAL) { 
1107         write->opcode = OPCODE_SETLOCAL;
1108         write->data[0] = r->data[0];
1109     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1110         write->opcode = OPCODE_SETLOCAL_0;
1111     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1112         write->opcode = OPCODE_SETLOCAL_1;
1113     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1114         write->opcode = OPCODE_SETLOCAL_2;
1115     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1116         write->opcode = OPCODE_SETLOCAL_3;
1117     } else {
1118         code_dump(r, 0, 0, "", stdout);
1119         syntaxerror("illegal lvalue: can't assign a value to this expression");
1120     }
1121     code_t* c = 0;
1122     
1123     int temp = -1;
1124     if(!justassign) {
1125         if(use_temp_var) {
1126             /* with getproperty/getslot, we have to be extra careful not
1127                to execute the read code twice, as it might have side-effects
1128                (e.g. if the property is in fact a setter/getter combination)
1129
1130                So read the value, modify it, and write it again,
1131                using prefix only once and making sure (by using a temporary
1132                register) that the return value is what we just wrote */
1133             temp = gettempvar();
1134             c = code_append(c, prefix);
1135             c = code_append(c, r);
1136             if(readbefore) {
1137                 c = abc_dup(c);
1138                 c = abc_setlocal(c, temp);
1139             }
1140             c = code_append(c, middlepart);
1141             if(!readbefore) {
1142                 c = abc_dup(c);
1143                 c = abc_setlocal(c, temp);
1144             }
1145             c = code_append(c, write);
1146             c = abc_getlocal(c, temp);
1147             c = abc_kill(c, temp);
1148         } else {
1149             /* if we're allowed to execute the read code twice *and*
1150                the middlepart doesn't modify the code, things are easier.
1151             */
1152             code_t* r2 = code_dup(r);
1153             //c = code_append(c, prefix);
1154             parserassert(!prefix);
1155             c = code_append(c, r);
1156             c = code_append(c, middlepart);
1157             c = code_append(c, write);
1158             c = code_append(c, r2);
1159         }
1160     } else {
1161         /* even smaller version: overwrite the value without reading
1162            it out first */
1163         if(!use_temp_var) {
1164             if(prefix) {
1165                 c = code_append(c, prefix);
1166                 c = abc_dup(c);
1167             }
1168             c = code_append(c, middlepart);
1169             c = code_append(c, write);
1170             c = code_append(c, r);
1171         } else {
1172             temp = gettempvar();
1173             if(prefix) {
1174                 c = code_append(c, prefix);
1175                 c = abc_dup(c);
1176             }
1177             c = code_append(c, middlepart);
1178             c = abc_dup(c);
1179             c = abc_setlocal(c, temp);
1180             c = code_append(c, write);
1181             c = abc_getlocal(c, temp);
1182         }
1183     }
1184
1185     return c;
1186 }
1187
1188 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1189 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1190
1191 %}
1192
1193
1194 %%
1195
1196 /* ------------ code blocks / statements ---------------- */
1197
1198 PROGRAM: MAYBECODE
1199
1200 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1201 MAYBECODE:      {$$=code_new();}
1202
1203 CODE: CODE CODEPIECE {
1204     $$=code_append($1,$2);
1205 }
1206 CODE: CODEPIECE {
1207     $$=$1;
1208 }
1209
1210 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
1211 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
1212 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
1213 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1214 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
1215 CODEPIECE: ';'                   {$$=code_new();}
1216 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
1217 CODEPIECE: VOIDEXPRESSION        {$$=$1}
1218 CODEPIECE: FOR                   {$$=$1}
1219 CODEPIECE: WHILE                 {$$=$1}
1220 CODEPIECE: DO_WHILE              {$$=$1}
1221 CODEPIECE: BREAK                 {$$=$1}
1222 CODEPIECE: CONTINUE              {$$=$1}
1223 CODEPIECE: RETURN                {$$=$1}
1224 CODEPIECE: IF                    {$$=$1}
1225 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1226 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
1227
1228 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
1229 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1230 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1231
1232 /* ------------ variables --------------------------- */
1233
1234 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1235                 |                {$$.c=abc_pushundefined(0);
1236                                   $$.t=TYPE_ANY;
1237                                  }
1238
1239 VAR : "const" | "var"
1240 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1241
1242 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1243 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1244
1245 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1246 {
1247     if(variable_exists($2))
1248         syntaxerror("Variable %s already defined", $2);
1249    
1250     if(!is_subtype_of($4.t, $3)) {
1251         syntaxerror("Can't convert %s to %s", $4.t->name, 
1252                                               $3->name);
1253     }
1254
1255     int index = new_variable($2, $3);
1256     
1257     if($3) {
1258         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1259             $$ = $4.c;
1260             $$ = converttype($$, $4.t, $3);
1261             $$ = abc_setlocal($$, index);
1262         } else {
1263             $$ = defaultvalue(0, $3);
1264             $$ = abc_setlocal($$, index);
1265         }
1266
1267         /* if this is a typed variable:
1268            push default value for type on stack */
1269         if($3) {
1270             state->method->initcode = defaultvalue(state->method->initcode, $3);
1271             state->method->initcode = abc_setlocal(state->method->initcode, index);
1272         }
1273     } else {
1274         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1275             $$ = $4.c;
1276             $$ = abc_coerce_a($$);
1277             $$ = abc_setlocal($$, index);
1278         } else {
1279             $$ = code_new();
1280         }
1281     }
1282     
1283     /* that's the default for a local register, anyway
1284         else {
1285         state->method->initcode = abc_pushundefined(state->method->initcode);
1286         state->method->initcode = abc_setlocal(state->method->initcode, index);
1287     }*/
1288     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1289 }
1290
1291 /* ------------ control flow ------------------------- */
1292
1293 MAYBEELSE:  %prec below_else {$$ = code_new();}
1294 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1295 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1296
1297 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1298     $$ = code_new();
1299     $$ = code_append($$, $4.c);
1300     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1301    
1302     $$ = code_append($$, $6);
1303     if($7) {
1304         myjmp = $$ = abc_jump($$, 0);
1305     }
1306     myif->branch = $$ = abc_nop($$);
1307     if($7) {
1308         $$ = code_append($$, $7);
1309         myjmp->branch = $$ = abc_nop($$);
1310     }
1311     
1312     $$ = killvars($$);old_state();
1313 }
1314
1315 MAYBELABEL : T_IDENTIFIER ':' {$$=$1;}
1316 MAYBELABEL :                  {$$="";}
1317
1318 FOR_INIT : {$$=code_new();}
1319 FOR_INIT : VARIABLE_DECLARATION
1320 FOR_INIT : VOIDEXPRESSION
1321
1322 FOR : MAYBELABEL "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1323     $$ = code_new();
1324     $$ = code_append($$, $5);
1325     code_t*loopstart = $$ = abc_label($$);
1326     $$ = code_append($$, $7.c);
1327     code_t*myif = $$ = abc_iffalse($$, 0);
1328     $$ = code_append($$, $11);
1329     code_t*cont = $$ = abc_nop($$);
1330     $$ = code_append($$, $9);
1331     $$ = abc_jump($$, loopstart);
1332     code_t*out = $$ = abc_nop($$);
1333     breakjumpsto($$, $1, out);
1334     continuejumpsto($$, $1, cont);
1335     myif->branch = out;
1336
1337     $$ = killvars($$);old_state();
1338 }
1339
1340 WHILE : MAYBELABEL "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1341     $$ = code_new();
1342
1343     code_t*myjmp = $$ = abc_jump($$, 0);
1344     code_t*loopstart = $$ = abc_label($$);
1345     $$ = code_append($$, $7);
1346     code_t*cont = $$ = abc_nop($$);
1347     myjmp->branch = cont;
1348     $$ = code_append($$, $5.c);
1349     $$ = abc_iftrue($$, loopstart);
1350     code_t*out = $$ = abc_nop($$);
1351     breakjumpsto($$, $1, out);
1352     continuejumpsto($$, $1, cont);
1353
1354     $$ = killvars($$);
1355     old_state();
1356 }
1357
1358 DO_WHILE : MAYBELABEL "do" {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1359     $$ = code_new();
1360     code_t*loopstart = $$ = abc_label($$);
1361     $$ = code_append($$, $4);
1362     code_t*cont = $$ = abc_nop($$);
1363     $$ = code_append($$, $7.c);
1364     $$ = abc_iftrue($$, loopstart);
1365     code_t*out = $$ = abc_nop($$);
1366     breakjumpsto($$, $1, out);
1367     continuejumpsto($$, $1, cont);
1368     $$ = killvars($$);
1369     old_state();
1370 }
1371
1372 BREAK : "break" %prec prec_none {
1373     $$ = abc___break__(0, "");
1374 }
1375 BREAK : "break" T_IDENTIFIER {
1376     $$ = abc___break__(0, $2);
1377 }
1378 CONTINUE : "continue" %prec prec_none {
1379     $$ = abc___continue__(0, "");
1380 }
1381 CONTINUE : "continue" T_IDENTIFIER {
1382     $$ = abc___continue__(0, $2);
1383 }
1384
1385 /* ------------ packages and imports ---------------- */
1386
1387 X_IDENTIFIER: T_IDENTIFIER
1388             | "package" {$$="package";}
1389
1390 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1391 PACKAGE: X_IDENTIFIER             {$$=$1;}
1392
1393 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1394 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1395
1396 IMPORT : "import" QNAME {
1397        classinfo_t*c = $2;
1398        if(!c) 
1399             syntaxerror("Couldn't import class\n");
1400        state_has_imports();
1401        dict_put(state->imports, c->name, c);
1402        $$=0;
1403 }
1404 IMPORT : "import" PACKAGE '.' '*' {
1405        NEW(import_t,i);
1406        i->package = $2;
1407        state_has_imports();
1408        list_append(state->wildcard_imports, i);
1409        $$=0;
1410 }
1411
1412 /* ------------ classes and interfaces (header) -------------- */
1413
1414 MAYBE_MODIFIERS : {$$=0;}
1415 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1416 MODIFIER_LIST : MODIFIER               {$$=$1;}
1417 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1418
1419 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1420          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1421          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1422          | KW_STATIC {$$=FLAG_STATIC;}
1423          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1424          | KW_FINAL {$$=FLAG_FINAL;}
1425          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1426          | KW_NATIVE {$$=FLAG_NATIVE;}
1427          | KW_INTERNAL {$$=FLAG_INTERNAL;}
1428
1429 EXTENDS : {$$=registry_getobjectclass();}
1430 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1431
1432 EXTENDS_LIST : {$$=list_new();}
1433 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1434
1435 IMPLEMENTS_LIST : {$$=list_new();}
1436 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1437
1438 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1439                               EXTENDS IMPLEMENTS_LIST 
1440                               '{' {startclass($1,$3,$4,$5, 0);} 
1441                               MAYBE_DECLARATION_LIST 
1442                               '}' {endclass();}
1443
1444 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1445                               EXTENDS_LIST 
1446                               '{' {startclass($1,$3,0,$4,1);}
1447                               MAYBE_IDECLARATION_LIST 
1448                               '}' {endclass();}
1449
1450 /* ------------ classes and interfaces (body) -------------- */
1451
1452 MAYBE_DECLARATION_LIST : 
1453 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1454 DECLARATION_LIST : DECLARATION
1455 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1456 DECLARATION : ';'
1457 DECLARATION : SLOT_DECLARATION
1458 DECLARATION : FUNCTION_DECLARATION
1459
1460 MAYBE_IDECLARATION_LIST : 
1461 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1462 IDECLARATION_LIST : IDECLARATION
1463 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1464 IDECLARATION : ';'
1465 IDECLARATION : "var" T_IDENTIFIER {
1466     syntaxerror("variable declarations not allowed in interfaces");
1467 }
1468 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1469     $1 |= FLAG_PUBLIC;
1470     if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1471         syntaxerror("invalid method modifiers: interface methods always need to be public");
1472     }
1473     startfunction(0,$1,$3,$4,&$6,$8);
1474     endfunction(0,$1,$3,$4,&$6,$8, 0);
1475 }
1476
1477 /* ------------ classes and interfaces (body, slots ) ------- */
1478
1479 VARCONST: "var" | "const"
1480
1481 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1482     int flags = $1;
1483     memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1484     info->type = $4;
1485     info->flags = flags;
1486     trait_t*t=0;
1487
1488     namespace_t mname_ns = {flags2access(flags), ""};
1489     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1490
1491     if(!(flags&FLAG_STATIC)) {
1492         if($4) {
1493             MULTINAME(m, $4);
1494             t=abc_class_slot(state->cls->abc, &mname, &m);
1495         } else {
1496             t=abc_class_slot(state->cls->abc, &mname, 0);
1497         }
1498         info->slot = t->slot_id;
1499     } else {
1500         if($4) {
1501             MULTINAME(m, $4);
1502             t=abc_class_staticslot(state->cls->abc, &mname, &m);
1503         } else {
1504             t=abc_class_staticslot(state->cls->abc, &mname, 0);
1505         }
1506         info->slot = t->slot_id;
1507     }
1508     if($5.c && !is_pushundefined($5.c)) {
1509         code_t*c = 0;
1510         c = abc_getlocal_0(c);
1511         c = code_append(c, $5.c);
1512         c = converttype(c, $5.t, $4);
1513         c = abc_setslot(c, t->slot_id);
1514         if(!(flags&FLAG_STATIC))
1515             state->cls->init = code_append(state->cls->init, c);
1516         else
1517             state->cls->static_init = code_append(state->cls->static_init, c);
1518     }
1519     if($2==KW_CONST) {
1520         t->kind= TRAIT_CONST;
1521     }
1522 }
1523
1524 /* ------------ constants -------------------------------------- */
1525
1526 MAYBESTATICCONSTANT: {$$=0;}
1527 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1528
1529 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1530 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1531 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1532 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1533 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1534 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1535 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1536 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1537 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1538
1539 /* ------------ classes and interfaces (body, functions) ------- */
1540
1541 // non-vararg version
1542 MAYBE_PARAM_LIST: {
1543     memset(&$$,0,sizeof($$));
1544 }
1545 MAYBE_PARAM_LIST: PARAM_LIST {
1546     $$=$1;
1547 }
1548
1549 // vararg version
1550 MAYBE_PARAM_LIST: "..." PARAM {
1551     memset(&$$,0,sizeof($$));
1552     $$.varargs=1;
1553     list_append($$.list, $2);
1554 }
1555 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1556     $$ =$1;
1557     $$.varargs=1;
1558     list_append($$.list, $4);
1559 }
1560
1561 // non empty
1562 PARAM_LIST: PARAM_LIST ',' PARAM {
1563     $$ = $1;
1564     list_append($$.list, $3);
1565 }
1566 PARAM_LIST: PARAM {
1567     memset(&$$,0,sizeof($$));
1568     list_append($$.list, $1);
1569 }
1570
1571 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1572      $$ = malloc(sizeof(param_t));
1573      $$->name=$1;
1574      $$->type = $3;
1575      $$->value = $4;
1576 }
1577 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1578      $$ = malloc(sizeof(param_t));
1579      $$->name=$1;
1580      $$->type = TYPE_ANY;
1581      $$->value = $2;
1582 }
1583 GETSET : "get" {$$=$1;}
1584        | "set" {$$=$1;}
1585        |       {$$=0;}
1586
1587 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1588                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1589 {
1590     code_t*c = 0;
1591     if(state->method->late_binding) {
1592         c = abc_getlocal_0(c);
1593         c = abc_pushscope(c);
1594     }
1595     if(state->method->is_constructor && !state->method->has_super) {
1596         // call default constructor
1597         c = abc_getlocal_0(c);
1598         c = abc_constructsuper(c, 0);
1599     }
1600     c = wrap_function(c, state->method->initcode, $11);
1601     endfunction(0,$1,$3,$4,&$6,$8,c);
1602 }
1603
1604 /* ------------- package + class ids --------------- */
1605
1606 CLASS: T_IDENTIFIER {
1607
1608     /* try current package */
1609     $$ = find_class($1);
1610     if(!$$) syntaxerror("Could not find class %s\n", $1);
1611 }
1612
1613 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1614     $$ = registry_findclass($1, $3);
1615     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1616 }
1617
1618 QNAME: PACKAGEANDCLASS
1619      | CLASS
1620
1621 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1622 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1623
1624 TYPE : QNAME      {$$=$1;}
1625      | '*'        {$$=registry_getanytype();}
1626     /*
1627      |  "String"  {$$=registry_getstringclass();}
1628      |  "int"     {$$=registry_getintclass();}
1629      |  "uint"    {$$=registry_getuintclass();}
1630      |  "Boolean" {$$=registry_getbooleanclass();}
1631      |  "Number"  {$$=registry_getnumberclass();}
1632     */
1633
1634 MAYBETYPE: ':' TYPE {$$=$2;}
1635 MAYBETYPE:          {$$=0;}
1636
1637 /* ----------function calls, delete, constructor calls ------ */
1638
1639 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1640 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1641
1642 MAYBE_EXPRESSION_LIST : {$$=0;}
1643 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1644 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1645                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1646                                                   *t = $1;
1647                                                   list_append($$, t);}
1648 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1649                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1650                                                   *t = $3;
1651                                                   list_append($$, t);}
1652
1653 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1654     MULTINAME(m, $2);
1655     $$.c = code_new();
1656
1657     if($2->slot) {
1658         $$.c = abc_getglobalscope($$.c);
1659         $$.c = abc_getslot($$.c, $2->slot);
1660     } else {
1661         $$.c = abc_findpropstrict2($$.c, &m);
1662     }
1663
1664     typedcode_list_t*l = $3;
1665     int len = 0;
1666     while(l) {
1667         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1668         l = l->next;
1669         len ++;
1670     }
1671     if($2->slot)
1672         $$.c = abc_construct($$.c, len);
1673     else
1674         $$.c = abc_constructprop2($$.c, &m, len);
1675     $$.t = $2;
1676 }
1677
1678 /* TODO: use abc_call (for calling local variables),
1679          abc_callstatic (for calling own methods) 
1680          call (for closures)
1681 */
1682 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1683     typedcode_list_t*l = $3;
1684     int len = 0;
1685     code_t*paramcode = 0;
1686     while(l) {
1687         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1688         l = l->next;
1689         len ++;
1690     }
1691        
1692     $$.c = $1.c;
1693     if($$.c->opcode == OPCODE_COERCE_A) {
1694         $$.c = code_cutlast($$.c);
1695     }
1696
1697     $$.t = TYPE_ANY;
1698     multiname_t*name = 0;
1699     if($$.c->opcode == OPCODE_GETPROPERTY) {
1700         name = multiname_clone($$.c->data[0]);
1701         $$.c = code_cutlast($$.c);
1702         $$.c = code_append($$.c, paramcode);
1703         $$.c = abc_callproperty2($$.c, name, len);
1704     } else if($$.c->opcode == OPCODE_GETSLOT) {
1705         int slot = (int)(ptroff_t)$$.c->data[0];
1706         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1707         if(t->kind!=TRAIT_METHOD) {
1708             //ok: flash allows to assign closures to members.
1709         }
1710         name = t->name;
1711         $$.c = code_cutlast($$.c);
1712         $$.c = code_append($$.c, paramcode);
1713         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1714         $$.c = abc_callproperty2($$.c, name, len);
1715     } else if($$.c->opcode == OPCODE_GETSUPER) {
1716         name = multiname_clone($$.c->data[0]);
1717         $$.c = code_cutlast($$.c);
1718         $$.c = code_append($$.c, paramcode);
1719         $$.c = abc_callsuper2($$.c, name, len);
1720     } else {
1721         $$.c = abc_getlocal_0($$.c);
1722         $$.c = code_append($$.c, paramcode);
1723         $$.c = abc_call($$.c, len);
1724     }
1725    
1726     memberinfo_t*f = 0;
1727    
1728     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1729         $$.t = $1.t->function->return_type;
1730     } else {
1731         $$.c = abc_coerce_a($$.c);
1732         $$.t = TYPE_ANY;
1733     }
1734 }
1735 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1736     if(!state->cls) syntaxerror("super() not allowed outside of a class");
1737     if(!state->method) syntaxerror("super() not allowed outside of a function");
1738     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1739
1740     $$.c = code_new();
1741     $$.c = abc_getlocal_0($$.c);
1742     typedcode_list_t*l = 0;
1743     int len = 0;
1744     for(l=$3;l;l=l->next) {
1745         $$.c = code_append($$.c, l->typedcode->c);len++;
1746     }
1747     /*
1748     this is dependent on the control path, check this somewhere else
1749     if(state->method->has_super)
1750         syntaxerror("constructor may call super() only once");
1751     */
1752     state->method->has_super = 1;
1753     $$.c = abc_constructsuper($$.c, len);
1754     $$.c = abc_pushundefined($$.c);
1755     $$.t = TYPE_ANY;
1756 }
1757
1758 DELETE: "delete" E {
1759     $$.c = $2.c;
1760     if($$.c->opcode == OPCODE_COERCE_A) {
1761         $$.c = code_cutlast($$.c);
1762     }
1763     multiname_t*name = 0;
1764     if($$.c->opcode == OPCODE_GETPROPERTY) {
1765         $$.c->opcode = OPCODE_DELETEPROPERTY;
1766     } else if($$.c->opcode == OPCODE_GETSLOT) {
1767         int slot = (int)(ptroff_t)$$.c->data[0];
1768         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1769         $$.c = code_cutlast($$.c);
1770         $$.c = abc_deleteproperty2($$.c, name);
1771     } else {
1772         $$.c = abc_getlocal_0($$.c);
1773         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1774         $$.c = abc_deleteproperty2($$.c, &m);
1775     }
1776     $$.t = TYPE_BOOLEAN;
1777 }
1778
1779 RETURN: "return" %prec prec_none {
1780     $$ = abc_returnvoid(0);
1781 }
1782 RETURN: "return" EXPRESSION {
1783     $$ = $2.c;
1784     $$ = abc_returnvalue($$);
1785 }
1786
1787 // ----------------------- expression types -------------------------------------
1788
1789 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
1790 EXPRESSION : E                %prec below_minus {$$ = $1;}
1791 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1792     $$.c = $1.c;
1793     $$.c = cut_last_push($$.c);
1794     $$.c = code_append($$.c,$3.c);
1795     $$.t = $3.t;
1796 }
1797 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1798     $$=cut_last_push($1.c);
1799 }
1800
1801 // ----------------------- expression evaluation -------------------------------------
1802
1803 E : CONSTANT
1804 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1805 E : NEW                         {$$ = $1;}
1806 E : DELETE                      {$$ = $1;}
1807 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1808                                  $$.t = TYPE_ANY;
1809                                 }
1810
1811 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1812                    //MULTINAME(m, registry_getintclass());
1813                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1814                    $$.t = TYPE_INT;
1815                   }
1816 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1817                     $$.t = TYPE_INT;
1818                    }
1819 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1820                   $$.t = TYPE_INT;
1821                  }
1822 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1823                    $$.t = TYPE_UINT;
1824                   }
1825 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1826                     $$.t = TYPE_FLOAT;
1827                    }
1828 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1829                      $$.t = TYPE_STRING;
1830                     }
1831 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1832                     $$.t = TYPE_ANY;
1833                    }
1834 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1835                     $$.t = TYPE_BOOLEAN;
1836                    }
1837 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1838                      $$.t = TYPE_BOOLEAN;
1839                     }
1840 CONSTANT : "null" {$$.c = abc_pushnull(0);
1841                     $$.t = TYPE_NULL;
1842                    }
1843
1844 E : FUNCTIONCALL
1845 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1846              $$.t = TYPE_BOOLEAN;
1847             }
1848 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1849              $$.t = TYPE_BOOLEAN;
1850             }
1851 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1852               $$.t = TYPE_BOOLEAN;
1853              }
1854 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1855               $$.t = TYPE_BOOLEAN;
1856              }
1857 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1858               $$.t = TYPE_BOOLEAN;
1859              }
1860 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1861               $$.t = TYPE_BOOLEAN;
1862               }
1863 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1864               $$.t = TYPE_BOOLEAN;
1865              }
1866 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1867               $$.t = TYPE_BOOLEAN;
1868              }
1869
1870 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1871               $$.c = $1.c;
1872               $$.c = converttype($$.c, $1.t, $$.t);
1873               $$.c = abc_dup($$.c);
1874               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1875               $$.c = cut_last_push($$.c);
1876               $$.c = code_append($$.c,$3.c);
1877               $$.c = converttype($$.c, $3.t, $$.t);
1878               code_t*label = $$.c = abc_label($$.c);
1879               jmp->branch = label;
1880              }
1881 E : E "&&" E {
1882               $$.t = join_types($1.t, $3.t, 'A');
1883               /*printf("%08x:\n",$1.t);
1884               code_dump($1.c, 0, 0, "", stdout);
1885               printf("%08x:\n",$3.t);
1886               code_dump($3.c, 0, 0, "", stdout);
1887               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1888               $$.c = $1.c;
1889               $$.c = converttype($$.c, $1.t, $$.t);
1890               $$.c = abc_dup($$.c);
1891               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1892               $$.c = cut_last_push($$.c);
1893               $$.c = code_append($$.c,$3.c);
1894               $$.c = converttype($$.c, $3.t, $$.t);
1895               code_t*label = $$.c = abc_label($$.c);
1896               jmp->branch = label;              
1897              }
1898
1899 E : '!' E    {$$.c=$2.c;
1900               $$.c = abc_not($$.c);
1901               $$.t = TYPE_BOOLEAN;
1902              }
1903
1904 E : '~' E    {$$.c=$2.c;
1905               $$.c = abc_bitnot($$.c);
1906               $$.t = TYPE_INT;
1907              }
1908
1909 E : E '&' E {$$.c = code_append($1.c,$3.c);
1910              $$.c = abc_bitand($$.c);
1911              $$.t = TYPE_INT;
1912             }
1913
1914 E : E '^' E {$$.c = code_append($1.c,$3.c);
1915              $$.c = abc_bitxor($$.c);
1916              $$.t = TYPE_INT;
1917             }
1918
1919 E : E '|' E {$$.c = code_append($1.c,$3.c);
1920              $$.c = abc_bitor($$.c);
1921              $$.t = TYPE_INT;
1922             }
1923
1924 E : E '-' E {$$.c = code_append($1.c,$3.c);
1925              if(BOTH_INT($1,$3)) {
1926                 $$.c = abc_subtract_i($$.c);
1927                 $$.t = TYPE_INT;
1928              } else {
1929                 $$.c = abc_subtract($$.c);
1930                 $$.t = TYPE_NUMBER;
1931              }
1932             }
1933 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1934              $$.c = abc_rshift($$.c);
1935              $$.t = TYPE_INT;
1936             }
1937 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1938              $$.c = abc_urshift($$.c);
1939              $$.t = TYPE_INT;
1940             }
1941 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1942              $$.c = abc_lshift($$.c);
1943              $$.t = TYPE_INT;
1944             }
1945
1946 E : E '/' E {$$.c = code_append($1.c,$3.c);
1947              $$.c = abc_divide($$.c);
1948              $$.t = TYPE_NUMBER;
1949             }
1950 E : E '+' E {$$.c = code_append($1.c,$3.c);
1951              $$.c = abc_add($$.c);
1952              $$.t = TYPE_NUMBER;
1953             }
1954 E : E '%' E {$$.c = code_append($1.c,$3.c);
1955              $$.c = abc_modulo($$.c);
1956              $$.t = TYPE_NUMBER;
1957             }
1958 E : E '*' E {$$.c = code_append($1.c,$3.c);
1959              if(BOTH_INT($1,$3)) {
1960                 $$.c = abc_multiply_i($$.c);
1961                 $$.t = TYPE_INT;
1962              } else {
1963                 $$.c = abc_multiply($$.c);
1964                 $$.t = TYPE_NUMBER;
1965              }
1966             }
1967
1968 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1969               if(use_astype && TYPE_IS_CLASS($3.t)) {
1970                 MULTINAME(m,$3.t->cls);
1971                 $$.c = abc_astype2($1.c, &m);
1972                 $$.t = $3.t->cls;
1973               } else {
1974                 $$.c = code_append($1.c, $3.c);
1975                 $$.c = abc_astypelate($$.c);
1976                 $$.t = TYPE_ANY;
1977               }
1978              }
1979
1980 E : E "instanceof" E 
1981              {$$.c = code_append($1.c, $3.c);
1982               $$.c = abc_instanceof($$.c);
1983               $$.t = TYPE_BOOLEAN;
1984              }
1985
1986 E : E "is" E {$$.c = code_append($1.c, $3.c);
1987               $$.c = abc_istypelate($$.c);
1988               $$.t = TYPE_BOOLEAN;
1989              }
1990
1991 E : "typeof" '(' E ')' {
1992               $$.c = $3.c;
1993               $$.c = abc_typeof($$.c);
1994               $$.t = TYPE_STRING;
1995              }
1996
1997 E : "void" E {
1998               $$.c = cut_last_push($2.c);
1999               $$.c = abc_pushundefined($$.c);
2000               $$.t = TYPE_ANY;
2001              }
2002
2003 E : "void" { $$.c = abc_pushundefined(0);
2004              $$.t = TYPE_ANY;
2005            }
2006
2007 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2008
2009 E : '-' E {
2010   $$=$2;
2011   if(IS_INT($2)) {
2012    $$.c=abc_negate_i($$.c);
2013    $$.t = TYPE_INT;
2014   } else {
2015    $$.c=abc_negate($$.c);
2016    $$.t = TYPE_NUMBER;
2017   }
2018 }
2019
2020 E : E '[' E ']' {
2021   $$.c = $1.c;
2022   $$.c = code_append($$.c, $3.c);
2023  
2024   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2025   $$.c = abc_getproperty2($$.c, &m);
2026   $$.t = 0; // array elements have unknown type
2027 }
2028
2029 E : '[' MAYBE_EXPRESSION_LIST ']' {
2030     $$.c = code_new();
2031     typedcode_list_t*l = 0;
2032     int len = 0;
2033     for(l=$2;l;l=l->next) {
2034         $$.c = code_append($$.c, l->typedcode->c);len++;
2035     }
2036     $$.c = abc_newarray($$.c, len);
2037     $$.t = registry_getarrayclass();
2038 }
2039
2040 E : E "*=" E { 
2041                code_t*c = $3.c;
2042                if(BOTH_INT($1,$3)) {
2043                 c=abc_multiply_i(c);
2044                } else {
2045                 c=abc_multiply(c);
2046                }
2047                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2048                $$.c = toreadwrite($1.c, c, 0, 0);
2049                $$.t = $1.t;
2050               }
2051
2052 E : E "%=" E { 
2053                code_t*c = abc_modulo($3.c);
2054                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2055                $$.c = toreadwrite($1.c, c, 0, 0);
2056                $$.t = $1.t;
2057               }
2058 E : E "<<=" E { 
2059                code_t*c = abc_lshift($3.c);
2060                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2061                $$.c = toreadwrite($1.c, c, 0, 0);
2062                $$.t = $1.t;
2063               }
2064 E : E ">>=" E { 
2065                code_t*c = abc_rshift($3.c);
2066                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2067                $$.c = toreadwrite($1.c, c, 0, 0);
2068                $$.t = $1.t;
2069               }
2070 E : E ">>>=" E { 
2071                code_t*c = abc_urshift($3.c);
2072                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2073                $$.c = toreadwrite($1.c, c, 0, 0);
2074                $$.t = $1.t;
2075               }
2076 E : E "/=" E { 
2077                code_t*c = abc_divide($3.c);
2078                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2079                $$.c = toreadwrite($1.c, c, 0, 0);
2080                $$.t = $1.t;
2081               }
2082 E : E "+=" E { 
2083                code_t*c = $3.c;
2084                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2085                 c=abc_add_i(c);
2086                } else {
2087                 c=abc_add(c);
2088                }
2089                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2090                
2091                $$.c = toreadwrite($1.c, c, 0, 0);
2092                $$.t = $1.t;
2093               }
2094 E : E "-=" E { code_t*c = $3.c; 
2095                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2096                 c=abc_subtract_i(c);
2097                } else {
2098                 c=abc_subtract(c);
2099                }
2100                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2101                
2102                $$.c = toreadwrite($1.c, c, 0, 0);
2103                $$.t = $1.t;
2104              }
2105 E : E '=' E { code_t*c = 0;
2106               c = code_append(c, $3.c);
2107               c = converttype(c, $3.t, $1.t);
2108               $$.c = toreadwrite($1.c, c, 1, 0);
2109               $$.t = $1.t;
2110             }
2111
2112 E : E '?' E ':' E %prec below_assignment { 
2113               $$.c = $1.c;
2114               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2115               $$.c = code_append($$.c, $3.c);
2116               code_t*j2 = $$.c = abc_jump($$.c, 0);
2117               $$.c = j1->branch = abc_label($$.c);
2118               $$.c = code_append($$.c, $5.c);
2119               $$.c = j2->branch = abc_label($$.c);
2120               $$.t = join_types($3.t,$5.t,'?');
2121             }
2122
2123 // TODO: use inclocal where appropriate
2124 E : E "++" { code_t*c = 0;
2125              classinfo_t*type = $1.t;
2126              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2127                  c=abc_increment_i(c);
2128                  type = TYPE_INT;
2129              } else {
2130                  c=abc_increment(c);
2131                  type = TYPE_NUMBER;
2132              }
2133              c=converttype(c, type, $1.t);
2134              $$.c = toreadwrite($1.c, c, 0, 1);
2135              $$.t = $1.t;
2136            }
2137 E : E "--" { code_t*c = 0;
2138              classinfo_t*type = $1.t;
2139              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2140                  c=abc_decrement_i(c);
2141                  type = TYPE_INT;
2142              } else {
2143                  c=abc_decrement(c);
2144                  type = TYPE_NUMBER;
2145              }
2146              c=converttype(c, type, $1.t);
2147              $$.c = toreadwrite($1.c, c, 0, 1);
2148              $$.t = $1.t;
2149             }
2150
2151 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2152              classinfo_t*type = $2.t;
2153              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2154                  c=abc_increment_i(c);
2155                  type = TYPE_INT;
2156              } else {
2157                  c=abc_increment(c);
2158                  type = TYPE_NUMBER;
2159              }
2160              c=converttype(c, type, $2.t);
2161              $$.c = toreadwrite($2.c, c, 0, 0);
2162              $$.t = $2.t;
2163            }
2164
2165 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2166              classinfo_t*type = $2.t;
2167              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2168                  c=abc_decrement_i(c);
2169                  type = TYPE_INT;
2170              } else {
2171                  c=abc_decrement(c);
2172                  type = TYPE_NUMBER;
2173              }
2174              c=converttype(c, type, $2.t);
2175              $$.c = toreadwrite($2.c, c, 0, 0);
2176              $$.t = $2.t;
2177            }
2178
2179 E : "super" '.' T_IDENTIFIER 
2180            { if(!state->cls->info)
2181                   syntaxerror("super keyword not allowed outside a class");
2182               classinfo_t*t = state->cls->info->superclass;
2183               if(!t) t = TYPE_OBJECT;
2184
2185               memberinfo_t*f = registry_findmember(t, $3);
2186               namespace_t ns = {flags2access(f->flags), ""};
2187               MEMBER_MULTINAME(m, f, $3);
2188               $$.c = 0;
2189               $$.c = abc_getlocal_0($$.c);
2190               $$.c = abc_getsuper2($$.c, &m);
2191               $$.t = memberinfo_gettype(f);
2192            }
2193
2194 E : E '.' T_IDENTIFIER
2195             {$$.c = $1.c;
2196              classinfo_t*t = $1.t;
2197              char is_static = 0;
2198              if(TYPE_IS_CLASS(t) && t->cls) {
2199                  t = t->cls;
2200                  is_static = 1;
2201              }
2202              if(t) {
2203                  memberinfo_t*f = registry_findmember(t, $3);
2204                  char noslot = 0;
2205                  if(f && !is_static != !(f->flags&FLAG_STATIC))
2206                     noslot=1;
2207                  if(f && f->slot && !noslot) {
2208                      $$.c = abc_getslot($$.c, f->slot);
2209                  } else {
2210                      MEMBER_MULTINAME(m, f, $3);
2211                      $$.c = abc_getproperty2($$.c, &m);
2212                  }
2213                  /* determine type */
2214                  $$.t = memberinfo_gettype(f);
2215                  if(!$$.t)
2216                     $$.c = abc_coerce_a($$.c);
2217              } else {
2218                  /* when resolving a property on an unknown type, we do know the
2219                     name of the property (and don't seem to need the package), but
2220                     we need to make avm2 try out all access modes */
2221                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2222                  $$.c = abc_getproperty2($$.c, &m);
2223                  $$.c = abc_coerce_a($$.c);
2224                  $$.t = registry_getanytype();
2225              }
2226             }
2227
2228 VAR_READ : T_IDENTIFIER {
2229     $$.t = 0;
2230     $$.c = 0;
2231     int i;
2232     classinfo_t*a = 0;
2233     memberinfo_t*f = 0;
2234
2235     /* look at variables */
2236     if((i = find_variable($1, &$$.t)) >= 0) {
2237         // $1 is a local variable
2238         $$.c = abc_getlocal($$.c, i);
2239
2240     /* look at current class' members */
2241     } else if((f = registry_findmember(state->cls->info, $1))) {
2242         // $1 is a function in this class
2243         int var_is_static = (f->flags&FLAG_STATIC);
2244         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2245         if(var_is_static != i_am_static) {
2246             /* there doesn't seem to be any "static" way to access
2247                static properties of a class */
2248             state->method->late_binding = 1;
2249             $$.t = f->type;
2250             namespace_t ns = {flags2access(f->flags), ""};
2251             multiname_t m = {QNAME, &ns, 0, $1};
2252             $$.c = abc_findpropstrict2($$.c, &m);
2253             $$.c = abc_getproperty2($$.c, &m);
2254         } else {
2255             if(f->slot>0) {
2256                 $$.c = abc_getlocal_0($$.c);
2257                 $$.c = abc_getslot($$.c, f->slot);
2258             } else {
2259                 namespace_t ns = {flags2access(f->flags), ""};
2260                 multiname_t m = {QNAME, &ns, 0, $1};
2261                 $$.c = abc_getlocal_0($$.c);
2262                 $$.c = abc_getproperty2($$.c, &m);
2263             }
2264         }
2265         if(f->kind == MEMBER_METHOD) {
2266             $$.t = TYPE_FUNCTION(f);
2267         } else {
2268             $$.t = f->type;
2269         }
2270     
2271     /* look at classes in the current package and imported classes */
2272     } else if((a = find_class($1))) {
2273         if(a->flags & FLAG_METHOD) {
2274             MULTINAME(m, a);
2275             $$.c = abc_findpropstrict2($$.c, &m);
2276             $$.c = abc_getproperty2($$.c, &m);
2277             $$.t = TYPE_FUNCTION(a->function);
2278         } else {
2279             if(a->slot) {
2280                 $$.c = abc_getglobalscope($$.c);
2281                 $$.c = abc_getslot($$.c, a->slot);
2282             } else {
2283                 MULTINAME(m, a);
2284                 $$.c = abc_getlex2($$.c, &m);
2285             }
2286             $$.t = TYPE_CLASS(a);
2287         }
2288
2289     /* unknown object, let the avm2 resolve it */
2290     } else {
2291         if(strcmp($1,"trace"))
2292             warning("Couldn't resolve '%s', doing late binding", $1);
2293         state->method->late_binding = 1;
2294                 
2295         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2296
2297         $$.t = 0;
2298         $$.c = abc_findpropstrict2($$.c, &m);
2299         $$.c = abc_getproperty2($$.c, &m);
2300     }
2301 }
2302
2303 //TODO: 
2304 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2305 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2306 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2307
2308 // ----------------- namespaces -------------------------------------------------
2309
2310 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2311 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2312 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2313
2314 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
2315