fixed bug in break/continue w/ label
[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
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))
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     f->body->code = body;
880         
881     old_state();
882 }
883
884
885
886 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
887 {
888     return 1; // FIXME
889 }
890
891 void breakjumpsto(code_t*c, char*name, code_t*jump) 
892 {
893     while(c) {
894         if(c->opcode == OPCODE___BREAK__) {
895             string_t*name2 = c->data[0];
896             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
897                 c->opcode = OPCODE_JUMP;
898                 c->branch = jump;
899             }
900         }
901         c=c->prev;
902     }
903 }
904 void continuejumpsto(code_t*c, char*name, code_t*jump) 
905 {
906     while(c) {
907         if(c->opcode == OPCODE___CONTINUE__) {
908             string_t*name2 = c->data[0];
909             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
910                 c->opcode = OPCODE_JUMP;
911                 c->branch = jump;
912             }
913         }
914         c = c->prev;
915     }
916 }
917
918 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
919 {
920     if(!type1 || !type2) 
921         return registry_getanytype();
922     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
923         return registry_getanytype();
924     if(type1 == type2)
925         return type1;
926     return registry_getanytype();
927 }
928 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
929 {
930     if(from==to)
931         return c;
932     if(!to) {
933         return abc_coerce_a(c);
934     }
935     MULTINAME(m, to);
936     if(!from) {
937         // cast an "any" type to a specific type. subject to
938         // runtime exceptions
939         return abc_coerce2(c, &m);
940     }
941     
942     if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
943         return abc_coerce2(c, &m);
944     }
945     if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
946         return abc_coerce2(c, &m);
947     }
948     /* these are subject to overflow */
949     if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
950         return abc_coerce2(c, &m);
951     }
952     if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
953         return abc_coerce2(c, &m);
954     }
955
956     classinfo_t*supertype = from;
957     while(supertype) {
958         if(supertype == to) {
959              // target type is one of from's superclasses
960              return abc_coerce2(c, &m);
961         }
962         int t=0;
963         while(supertype->interfaces[t]) {
964             if(supertype->interfaces[t]==to) {
965                 // to type is one of from's interfaces
966                 return abc_coerce2(c, &m);
967             }
968             t++;
969         }
970         supertype = supertype->superclass;
971     }
972     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
973         return c;
974     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
975         return c;
976     syntaxerror("can't convert type %s to %s", from->name, to->name);
977 }
978
979 code_t*defaultvalue(code_t*c, classinfo_t*type)
980 {
981     if(TYPE_IS_INT(type)) {
982        c = abc_pushbyte(c, 0);
983     } else if(TYPE_IS_UINT(type)) {
984        c = abc_pushuint(c, 0);
985     } else if(TYPE_IS_FLOAT(type)) {
986        c = abc_pushnan(c);
987     } else if(TYPE_IS_BOOLEAN(type)) {
988        c = abc_pushfalse(c);
989     } else {
990        c = abc_pushnull(c);
991     }
992     return c;
993 }
994
995 char is_pushundefined(code_t*c)
996 {
997     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
998 }
999
1000 void parserassert(int b)
1001 {
1002     if(!b) syntaxerror("internal error: assertion failed");
1003 }
1004
1005 static classinfo_t* find_class(char*name)
1006 {
1007     classinfo_t*c=0;
1008
1009     c = registry_findclass(state->package, name);
1010
1011     /* try explicit imports */
1012     dictentry_t* e = dict_get_slot(state->imports, name);
1013     while(e) {
1014         if(c)
1015             break;
1016         if(!strcmp(e->key, name)) {
1017             c = (classinfo_t*)e->data;
1018         }
1019         e = e->next;
1020     }
1021
1022     /* try package.* imports */
1023     import_list_t*l = state->wildcard_imports;
1024     while(l) {
1025         if(c)
1026             break;
1027         //printf("does package %s contain a class %s?\n", l->import->package, name);
1028         c = registry_findclass(l->import->package, name);
1029         l = l->next;
1030     }
1031
1032     /* try global package */
1033     if(!c) {
1034         c = registry_findclass("", name);
1035     }
1036     return c;
1037 }
1038
1039 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1040 {
1041     /* converts this:
1042
1043        [prefix code] [read instruction]
1044
1045        to this:
1046
1047        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1048     */
1049     
1050     if(in && in->opcode == OPCODE_COERCE_A) {
1051         in = code_cutlast(in);
1052     }
1053     if(in->next)
1054         syntaxerror("internal error");
1055
1056     /* chop off read instruction */
1057     code_t*prefix = in;
1058     code_t*r = in;
1059     if(r->prev) {
1060         prefix = r->prev;r->prev = 0;
1061         prefix->next=0;
1062     } else {
1063         prefix = 0;
1064     }
1065
1066     char use_temp_var = readbefore;
1067
1068     /* generate the write instruction, and maybe append a dup to the prefix code */
1069     code_t* write = abc_nop(0);
1070     if(r->opcode == OPCODE_GETPROPERTY) {
1071         write->opcode = OPCODE_SETPROPERTY;
1072         multiname_t*m = (multiname_t*)r->data[0];
1073         write->data[0] = multiname_clone(m);
1074         if(m->type == QNAME || m->type == MULTINAME) {
1075             if(!justassign) {
1076                 prefix = abc_dup(prefix); // we need the object, too
1077             }
1078             use_temp_var = 1;
1079         } else if(m->type == MULTINAMEL) {
1080             if(!justassign) {
1081                 /* dupping two values on the stack requires 5 operations and one register- 
1082                    couldn't adobe just have given us a dup2? */
1083                 int temp = gettempvar();
1084                 prefix = abc_setlocal(prefix, temp);
1085                 prefix = abc_dup(prefix);
1086                 prefix = abc_getlocal(prefix, temp);
1087                 prefix = abc_swap(prefix);
1088                 prefix = abc_getlocal(prefix, temp);
1089             }
1090             use_temp_var = 1;
1091         } else {
1092             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1093         }
1094     } else if(r->opcode == OPCODE_GETSLOT) {
1095         write->opcode = OPCODE_SETSLOT;
1096         write->data[0] = r->data[0];
1097         if(!justassign) {
1098             prefix = abc_dup(prefix); // we need the object, too
1099         }
1100         use_temp_var = 1;
1101     } else if(r->opcode == OPCODE_GETLOCAL) { 
1102         write->opcode = OPCODE_SETLOCAL;
1103         write->data[0] = r->data[0];
1104     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1105         write->opcode = OPCODE_SETLOCAL_0;
1106     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1107         write->opcode = OPCODE_SETLOCAL_1;
1108     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1109         write->opcode = OPCODE_SETLOCAL_2;
1110     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1111         write->opcode = OPCODE_SETLOCAL_3;
1112     } else {
1113         code_dump(r, 0, 0, "", stdout);
1114         syntaxerror("illegal lvalue: can't assign a value to this expression");
1115     }
1116     code_t* c = 0;
1117     
1118     int temp = -1;
1119     if(!justassign) {
1120         if(use_temp_var) {
1121             /* with getproperty/getslot, we have to be extra careful not
1122                to execute the read code twice, as it might have side-effects
1123                (e.g. if the property is in fact a setter/getter combination)
1124
1125                So read the value, modify it, and write it again,
1126                using prefix only once and making sure (by using a temporary
1127                register) that the return value is what we just wrote */
1128             temp = gettempvar();
1129             c = code_append(c, prefix);
1130             c = code_append(c, r);
1131             if(readbefore) {
1132                 c = abc_dup(c);
1133                 c = abc_setlocal(c, temp);
1134             }
1135             c = code_append(c, middlepart);
1136             if(!readbefore) {
1137                 c = abc_dup(c);
1138                 c = abc_setlocal(c, temp);
1139             }
1140             c = code_append(c, write);
1141             c = abc_getlocal(c, temp);
1142             c = abc_kill(c, temp);
1143         } else {
1144             /* if we're allowed to execute the read code twice *and*
1145                the middlepart doesn't modify the code, things are easier.
1146             */
1147             code_t* r2 = code_dup(r);
1148             //c = code_append(c, prefix);
1149             parserassert(!prefix);
1150             c = code_append(c, r);
1151             c = code_append(c, middlepart);
1152             c = code_append(c, write);
1153             c = code_append(c, r2);
1154         }
1155     } else {
1156         /* even smaller version: overwrite the value without reading
1157            it out first */
1158         if(!use_temp_var) {
1159             if(prefix) {
1160                 c = code_append(c, prefix);
1161                 c = abc_dup(c);
1162             }
1163             c = code_append(c, middlepart);
1164             c = code_append(c, write);
1165             c = code_append(c, r);
1166         } else {
1167             temp = gettempvar();
1168             if(prefix) {
1169                 c = code_append(c, prefix);
1170                 c = abc_dup(c);
1171             }
1172             c = code_append(c, middlepart);
1173             c = abc_dup(c);
1174             c = abc_setlocal(c, temp);
1175             c = code_append(c, write);
1176             c = abc_getlocal(c, temp);
1177         }
1178     }
1179
1180     return c;
1181 }
1182
1183 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1184 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1185
1186 %}
1187
1188
1189 %%
1190
1191 /* ------------ code blocks / statements ---------------- */
1192
1193 PROGRAM: MAYBECODE
1194
1195 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1196 MAYBECODE:      {$$=code_new();}
1197
1198 CODE: CODE CODEPIECE {
1199     $$=code_append($1,$2);
1200 }
1201 CODE: CODEPIECE {
1202     $$=$1;
1203 }
1204
1205 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
1206 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
1207 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
1208 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1209 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
1210 CODEPIECE: ';'                   {$$=code_new();}
1211 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
1212 CODEPIECE: VOIDEXPRESSION        {$$=$1}
1213 CODEPIECE: FOR                   {$$=$1}
1214 CODEPIECE: WHILE                 {$$=$1}
1215 CODEPIECE: DO_WHILE              {$$=$1}
1216 CODEPIECE: BREAK                 {$$=$1}
1217 CODEPIECE: CONTINUE              {$$=$1}
1218 CODEPIECE: RETURN                {$$=$1}
1219 CODEPIECE: IF                    {$$=$1}
1220 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1221 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
1222
1223 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
1224 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1225 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1226
1227 /* ------------ variables --------------------------- */
1228
1229 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1230                 |                {$$.c=abc_pushundefined(0);
1231                                   $$.t=TYPE_ANY;
1232                                  }
1233
1234 VAR : "const" | "var"
1235 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1236
1237 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1238 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1239
1240 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1241 {
1242     if(variable_exists($2))
1243         syntaxerror("Variable %s already defined", $2);
1244    
1245     if(!is_subtype_of($4.t, $3)) {
1246         syntaxerror("Can't convert %s to %s", $4.t->name, 
1247                                               $3->name);
1248     }
1249
1250     int index = new_variable($2, $3);
1251     
1252     if($3) {
1253         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1254             $$ = $4.c;
1255             $$ = converttype($$, $4.t, $3);
1256             $$ = abc_setlocal($$, index);
1257         } else {
1258             $$ = defaultvalue(0, $3);
1259             $$ = abc_setlocal($$, index);
1260         }
1261
1262         /* if this is a typed variable:
1263            push default value for type on stack */
1264         if($3) {
1265             state->method->initcode = defaultvalue(state->method->initcode, $3);
1266             state->method->initcode = abc_setlocal(state->method->initcode, index);
1267         }
1268     } else {
1269         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1270             $$ = $4.c;
1271             $$ = abc_coerce_a($$);
1272             $$ = abc_setlocal($$, index);
1273         } else {
1274             $$ = code_new();
1275         }
1276     }
1277     
1278     /* that's the default for a local register, anyway
1279         else {
1280         state->method->initcode = abc_pushundefined(state->method->initcode);
1281         state->method->initcode = abc_setlocal(state->method->initcode, index);
1282     }*/
1283     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1284 }
1285
1286 /* ------------ control flow ------------------------- */
1287
1288 MAYBEELSE:  %prec below_else {$$ = code_new();}
1289 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1290 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1291
1292 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1293     $$ = code_new();
1294     $$ = code_append($$, $4.c);
1295     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1296    
1297     $$ = code_append($$, $6);
1298     if($7) {
1299         myjmp = $$ = abc_jump($$, 0);
1300     }
1301     myif->branch = $$ = abc_nop($$);
1302     if($7) {
1303         $$ = code_append($$, $7);
1304         myjmp->branch = $$ = abc_nop($$);
1305     }
1306     
1307     $$ = killvars($$);old_state();
1308 }
1309
1310 MAYBELABEL : T_IDENTIFIER ':' {$$=$1;}
1311 MAYBELABEL :                  {$$="";}
1312
1313 FOR_INIT : {$$=code_new();}
1314 FOR_INIT : VARIABLE_DECLARATION
1315 FOR_INIT : VOIDEXPRESSION
1316
1317 FOR : MAYBELABEL "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1318     $$ = code_new();
1319     $$ = code_append($$, $5);
1320     code_t*loopstart = $$ = abc_label($$);
1321     $$ = code_append($$, $7.c);
1322     code_t*myif = $$ = abc_iffalse($$, 0);
1323     $$ = code_append($$, $11);
1324     code_t*cont = $$ = abc_nop($$);
1325     $$ = code_append($$, $9);
1326     $$ = abc_jump($$, loopstart);
1327     code_t*out = $$ = abc_nop($$);
1328     breakjumpsto($$, $1, out);
1329     continuejumpsto($$, $1, cont);
1330     myif->branch = out;
1331
1332     $$ = killvars($$);old_state();
1333 }
1334
1335 WHILE : MAYBELABEL "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1336     $$ = code_new();
1337
1338     code_t*myjmp = $$ = abc_jump($$, 0);
1339     code_t*loopstart = $$ = abc_label($$);
1340     $$ = code_append($$, $7);
1341     myjmp->branch = $$ = abc_nop($$);
1342     $$ = code_append($$, $5.c);
1343     $$ = abc_iftrue($$, loopstart);
1344     code_t*out = $$ = abc_nop($$);
1345     breakjumpsto($$, $1, out);
1346     continuejumpsto($$, $1, loopstart);
1347
1348     $$ = killvars($$);
1349     old_state();
1350 }
1351
1352 DO_WHILE : MAYBELABEL "do" {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1353     $$ = code_new();
1354     code_t*loopstart = $$ = abc_label($$);
1355     $$ = code_append($$, $4);
1356     code_t*cont = $$ = abc_nop($$);
1357     $$ = code_append($$, $7.c);
1358     $$ = abc_iftrue($$, loopstart);
1359     code_t*out = $$ = abc_nop($$);
1360     breakjumpsto($$, $1, out);
1361     continuejumpsto($$, $1, cont);
1362     $$ = killvars($$);
1363     old_state();
1364 }
1365
1366 BREAK : "break" %prec prec_none {
1367     $$ = abc___break__(0, "");
1368 }
1369 BREAK : "break" T_IDENTIFIER {
1370     $$ = abc___break__(0, $2);
1371 }
1372 CONTINUE : "continue" %prec prec_none {
1373     $$ = abc___continue__(0, "");
1374 }
1375 CONTINUE : "continue" T_IDENTIFIER {
1376     $$ = abc___continue__(0, $2);
1377 }
1378
1379 /* ------------ packages and imports ---------------- */
1380
1381 X_IDENTIFIER: T_IDENTIFIER
1382             | "package" {$$="package";}
1383
1384 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1385 PACKAGE: X_IDENTIFIER             {$$=$1;}
1386
1387 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1388 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1389
1390 IMPORT : "import" QNAME {
1391        classinfo_t*c = $2;
1392        if(!c) 
1393             syntaxerror("Couldn't import class\n");
1394        state_has_imports();
1395        dict_put(state->imports, c->name, c);
1396        $$=0;
1397 }
1398 IMPORT : "import" PACKAGE '.' '*' {
1399        NEW(import_t,i);
1400        i->package = $2;
1401        state_has_imports();
1402        list_append(state->wildcard_imports, i);
1403        $$=0;
1404 }
1405
1406 /* ------------ classes and interfaces (header) -------------- */
1407
1408 MAYBE_MODIFIERS : {$$=0;}
1409 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1410 MODIFIER_LIST : MODIFIER               {$$=$1;}
1411 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1412
1413 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1414          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1415          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1416          | KW_STATIC {$$=FLAG_STATIC;}
1417          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1418          | KW_FINAL {$$=FLAG_FINAL;}
1419          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1420          | KW_NATIVE {$$=FLAG_NATIVE;}
1421          | KW_INTERNAL {$$=FLAG_INTERNAL;}
1422
1423 EXTENDS : {$$=registry_getobjectclass();}
1424 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1425
1426 EXTENDS_LIST : {$$=list_new();}
1427 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1428
1429 IMPLEMENTS_LIST : {$$=list_new();}
1430 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1431
1432 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1433                               EXTENDS IMPLEMENTS_LIST 
1434                               '{' {startclass($1,$3,$4,$5, 0);} 
1435                               MAYBE_DECLARATION_LIST 
1436                               '}' {endclass();}
1437
1438 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1439                               EXTENDS_LIST 
1440                               '{' {startclass($1,$3,0,$4,1);}
1441                               MAYBE_IDECLARATION_LIST 
1442                               '}' {endclass();}
1443
1444 /* ------------ classes and interfaces (body) -------------- */
1445
1446 MAYBE_DECLARATION_LIST : 
1447 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1448 DECLARATION_LIST : DECLARATION
1449 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1450 DECLARATION : ';'
1451 DECLARATION : SLOT_DECLARATION
1452 DECLARATION : FUNCTION_DECLARATION
1453
1454 MAYBE_IDECLARATION_LIST : 
1455 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1456 IDECLARATION_LIST : IDECLARATION
1457 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1458 IDECLARATION : ';'
1459 IDECLARATION : "var" T_IDENTIFIER {
1460     syntaxerror("variable declarations not allowed in interfaces");
1461 }
1462 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1463     $1 |= FLAG_PUBLIC;
1464     if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1465         syntaxerror("invalid method modifiers: interface methods always need to be public");
1466     }
1467     startfunction(0,$1,$3,$4,&$6,$8);
1468     endfunction(0,$1,$3,$4,&$6,$8, 0);
1469 }
1470
1471 /* ------------ classes and interfaces (body, slots ) ------- */
1472
1473 VARCONST: "var" | "const"
1474
1475 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1476     int flags = $1;
1477     memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1478     info->type = $4;
1479     info->flags = flags;
1480     trait_t*t=0;
1481
1482     namespace_t mname_ns = {flags2access(flags), ""};
1483     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1484
1485     if(!(flags&FLAG_STATIC)) {
1486         if($4) {
1487             MULTINAME(m, $4);
1488             t=abc_class_slot(state->cls->abc, &mname, &m);
1489         } else {
1490             t=abc_class_slot(state->cls->abc, &mname, 0);
1491         }
1492         info->slot = t->slot_id;
1493     } else {
1494         if($4) {
1495             MULTINAME(m, $4);
1496             t=abc_class_staticslot(state->cls->abc, &mname, &m);
1497         } else {
1498             t=abc_class_staticslot(state->cls->abc, &mname, 0);
1499         }
1500         info->slot = t->slot_id;
1501     }
1502     if($5.c && !is_pushundefined($5.c)) {
1503         code_t*c = 0;
1504         c = abc_getlocal_0(c);
1505         c = code_append(c, $5.c);
1506         c = converttype(c, $5.t, $4);
1507         c = abc_setslot(c, t->slot_id);
1508         if(!(flags&FLAG_STATIC))
1509             state->cls->init = code_append(state->cls->init, c);
1510         else
1511             state->cls->static_init = code_append(state->cls->static_init, c);
1512     }
1513     if($2==KW_CONST) {
1514         t->kind= TRAIT_CONST;
1515     }
1516 }
1517
1518 /* ------------ constants -------------------------------------- */
1519
1520 MAYBESTATICCONSTANT: {$$=0;}
1521 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1522
1523 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1524 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1525 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1526 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1527 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1528 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1529 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1530 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1531 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1532
1533 /* ------------ classes and interfaces (body, functions) ------- */
1534
1535 // non-vararg version
1536 MAYBE_PARAM_LIST: {
1537     memset(&$$,0,sizeof($$));
1538 }
1539 MAYBE_PARAM_LIST: PARAM_LIST {
1540     $$=$1;
1541 }
1542
1543 // vararg version
1544 MAYBE_PARAM_LIST: "..." PARAM {
1545     memset(&$$,0,sizeof($$));
1546     $$.varargs=1;
1547     list_append($$.list, $2);
1548 }
1549 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1550     $$ =$1;
1551     $$.varargs=1;
1552     list_append($$.list, $4);
1553 }
1554
1555 // non empty
1556 PARAM_LIST: PARAM_LIST ',' PARAM {
1557     $$ = $1;
1558     list_append($$.list, $3);
1559 }
1560 PARAM_LIST: PARAM {
1561     memset(&$$,0,sizeof($$));
1562     list_append($$.list, $1);
1563 }
1564
1565 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1566      $$ = malloc(sizeof(param_t));
1567      $$->name=$1;
1568      $$->type = $3;
1569      $$->value = $4;
1570 }
1571 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1572      $$ = malloc(sizeof(param_t));
1573      $$->name=$1;
1574      $$->type = TYPE_ANY;
1575      $$->value = $2;
1576 }
1577 GETSET : "get" {$$=$1;}
1578        | "set" {$$=$1;}
1579        |       {$$=0;}
1580
1581 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1582                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1583 {
1584     code_t*c = 0;
1585     if(state->method->late_binding) {
1586         c = abc_getlocal_0(c);
1587         c = abc_pushscope(c);
1588     }
1589     if(state->method->is_constructor && !state->method->has_super) {
1590         // call default constructor
1591         c = abc_getlocal_0(c);
1592         c = abc_constructsuper(c, 0);
1593     }
1594     c = wrap_function(c, state->method->initcode, $11);
1595     endfunction(0,$1,$3,$4,&$6,$8,c);
1596 }
1597
1598 /* ------------- package + class ids --------------- */
1599
1600 CLASS: T_IDENTIFIER {
1601
1602     /* try current package */
1603     $$ = find_class($1);
1604     if(!$$) syntaxerror("Could not find class %s\n", $1);
1605 }
1606
1607 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1608     $$ = registry_findclass($1, $3);
1609     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1610 }
1611
1612 QNAME: PACKAGEANDCLASS
1613      | CLASS
1614
1615 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1616 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1617
1618 TYPE : QNAME      {$$=$1;}
1619      | '*'        {$$=registry_getanytype();}
1620     /*
1621      |  "String"  {$$=registry_getstringclass();}
1622      |  "int"     {$$=registry_getintclass();}
1623      |  "uint"    {$$=registry_getuintclass();}
1624      |  "Boolean" {$$=registry_getbooleanclass();}
1625      |  "Number"  {$$=registry_getnumberclass();}
1626     */
1627
1628 MAYBETYPE: ':' TYPE {$$=$2;}
1629 MAYBETYPE:          {$$=0;}
1630
1631 /* ----------function calls, delete, constructor calls ------ */
1632
1633 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1634 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1635
1636 MAYBE_EXPRESSION_LIST : {$$=0;}
1637 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1638 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1639                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1640                                                   *t = $1;
1641                                                   list_append($$, t);}
1642 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1643                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1644                                                   *t = $3;
1645                                                   list_append($$, t);}
1646
1647 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1648     MULTINAME(m, $2);
1649     $$.c = code_new();
1650
1651     if($2->slot) {
1652         $$.c = abc_getglobalscope($$.c);
1653         $$.c = abc_getslot($$.c, $2->slot);
1654     } else {
1655         $$.c = abc_findpropstrict2($$.c, &m);
1656     }
1657
1658     typedcode_list_t*l = $3;
1659     int len = 0;
1660     while(l) {
1661         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1662         l = l->next;
1663         len ++;
1664     }
1665     if($2->slot)
1666         $$.c = abc_construct($$.c, len);
1667     else
1668         $$.c = abc_constructprop2($$.c, &m, len);
1669     $$.t = $2;
1670 }
1671
1672 /* TODO: use abc_call (for calling local variables),
1673          abc_callstatic (for calling own methods) 
1674          call (for closures)
1675 */
1676 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1677     typedcode_list_t*l = $3;
1678     int len = 0;
1679     code_t*paramcode = 0;
1680     while(l) {
1681         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1682         l = l->next;
1683         len ++;
1684     }
1685        
1686     $$.c = $1.c;
1687     if($$.c->opcode == OPCODE_COERCE_A) {
1688         $$.c = code_cutlast($$.c);
1689     }
1690
1691     $$.t = TYPE_ANY;
1692     multiname_t*name = 0;
1693     if($$.c->opcode == OPCODE_GETPROPERTY) {
1694         name = multiname_clone($$.c->data[0]);
1695         $$.c = code_cutlast($$.c);
1696         $$.c = code_append($$.c, paramcode);
1697         $$.c = abc_callproperty2($$.c, name, len);
1698     } else if($$.c->opcode == OPCODE_GETSLOT) {
1699         int slot = (int)(ptroff_t)$$.c->data[0];
1700         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1701         if(t->kind!=TRAIT_METHOD) {
1702             //ok: flash allows to assign closures to members.
1703         }
1704         name = t->name;
1705         $$.c = code_cutlast($$.c);
1706         $$.c = code_append($$.c, paramcode);
1707         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1708         $$.c = abc_callproperty2($$.c, name, len);
1709     } else if($$.c->opcode == OPCODE_GETSUPER) {
1710         name = multiname_clone($$.c->data[0]);
1711         $$.c = code_cutlast($$.c);
1712         $$.c = code_append($$.c, paramcode);
1713         $$.c = abc_callsuper2($$.c, name, len);
1714     } else {
1715         $$.c = abc_getlocal_0($$.c);
1716         $$.c = code_append($$.c, paramcode);
1717         $$.c = abc_call($$.c, len);
1718     }
1719    
1720     memberinfo_t*f = 0;
1721    
1722     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1723         $$.t = $1.t->function->return_type;
1724     } else {
1725         $$.c = abc_coerce_a($$.c);
1726         $$.t = TYPE_ANY;
1727     }
1728 }
1729 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1730     if(!state->cls) syntaxerror("super() not allowed outside of a class");
1731     if(!state->method) syntaxerror("super() not allowed outside of a function");
1732     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1733
1734     $$.c = code_new();
1735     $$.c = abc_getlocal_0($$.c);
1736     typedcode_list_t*l = 0;
1737     int len = 0;
1738     for(l=$3;l;l=l->next) {
1739         $$.c = code_append($$.c, l->typedcode->c);len++;
1740     }
1741     /*
1742     this is dependent on the control path, check this somewhere else
1743     if(state->method->has_super)
1744         syntaxerror("constructor may call super() only once");
1745     */
1746     state->method->has_super = 1;
1747     $$.c = abc_constructsuper($$.c, len);
1748     $$.c = abc_pushundefined($$.c);
1749     $$.t = TYPE_ANY;
1750 }
1751
1752 DELETE: "delete" E {
1753     $$.c = $2.c;
1754     if($$.c->opcode == OPCODE_COERCE_A) {
1755         $$.c = code_cutlast($$.c);
1756     }
1757     multiname_t*name = 0;
1758     if($$.c->opcode == OPCODE_GETPROPERTY) {
1759         $$.c->opcode = OPCODE_DELETEPROPERTY;
1760     } else if($$.c->opcode == OPCODE_GETSLOT) {
1761         int slot = (int)(ptroff_t)$$.c->data[0];
1762         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1763         $$.c = code_cutlast($$.c);
1764         $$.c = abc_deleteproperty2($$.c, name);
1765     } else {
1766         $$.c = abc_getlocal_0($$.c);
1767         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1768         $$.c = abc_deleteproperty2($$.c, &m);
1769     }
1770     $$.t = TYPE_BOOLEAN;
1771 }
1772
1773 RETURN: "return" %prec prec_none {
1774     $$ = abc_returnvoid(0);
1775 }
1776 RETURN: "return" EXPRESSION {
1777     $$ = $2.c;
1778     $$ = abc_returnvalue($$);
1779 }
1780
1781 // ----------------------- expression types -------------------------------------
1782
1783 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
1784 EXPRESSION : E                %prec below_minus {$$ = $1;}
1785 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1786     $$.c = $1.c;
1787     $$.c = cut_last_push($$.c);
1788     $$.c = code_append($$.c,$3.c);
1789     $$.t = $3.t;
1790 }
1791 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1792     $$=cut_last_push($1.c);
1793 }
1794
1795 // ----------------------- expression evaluation -------------------------------------
1796
1797 E : CONSTANT
1798 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1799 E : NEW                         {$$ = $1;}
1800 E : DELETE                      {$$ = $1;}
1801 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1802                                  $$.t = TYPE_ANY;
1803                                 }
1804
1805 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1806                    //MULTINAME(m, registry_getintclass());
1807                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1808                    $$.t = TYPE_INT;
1809                   }
1810 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1811                     $$.t = TYPE_INT;
1812                    }
1813 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1814                   $$.t = TYPE_INT;
1815                  }
1816 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1817                    $$.t = TYPE_UINT;
1818                   }
1819 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1820                     $$.t = TYPE_FLOAT;
1821                    }
1822 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1823                      $$.t = TYPE_STRING;
1824                     }
1825 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1826                     $$.t = TYPE_ANY;
1827                    }
1828 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1829                     $$.t = TYPE_BOOLEAN;
1830                    }
1831 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1832                      $$.t = TYPE_BOOLEAN;
1833                     }
1834 CONSTANT : "null" {$$.c = abc_pushnull(0);
1835                     $$.t = TYPE_NULL;
1836                    }
1837
1838 E : FUNCTIONCALL
1839 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1840              $$.t = TYPE_BOOLEAN;
1841             }
1842 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1843              $$.t = TYPE_BOOLEAN;
1844             }
1845 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1846               $$.t = TYPE_BOOLEAN;
1847              }
1848 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1849               $$.t = TYPE_BOOLEAN;
1850              }
1851 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1852               $$.t = TYPE_BOOLEAN;
1853              }
1854 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1855               $$.t = TYPE_BOOLEAN;
1856               }
1857 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1858               $$.t = TYPE_BOOLEAN;
1859              }
1860 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1861               $$.t = TYPE_BOOLEAN;
1862              }
1863
1864 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1865               $$.c = $1.c;
1866               $$.c = converttype($$.c, $1.t, $$.t);
1867               $$.c = abc_dup($$.c);
1868               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1869               $$.c = cut_last_push($$.c);
1870               $$.c = code_append($$.c,$3.c);
1871               $$.c = converttype($$.c, $3.t, $$.t);
1872               code_t*label = $$.c = abc_label($$.c);
1873               jmp->branch = label;
1874              }
1875 E : E "&&" E {
1876               $$.t = join_types($1.t, $3.t, 'A');
1877               /*printf("%08x:\n",$1.t);
1878               code_dump($1.c, 0, 0, "", stdout);
1879               printf("%08x:\n",$3.t);
1880               code_dump($3.c, 0, 0, "", stdout);
1881               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1882               $$.c = $1.c;
1883               $$.c = converttype($$.c, $1.t, $$.t);
1884               $$.c = abc_dup($$.c);
1885               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1886               $$.c = cut_last_push($$.c);
1887               $$.c = code_append($$.c,$3.c);
1888               $$.c = converttype($$.c, $3.t, $$.t);
1889               code_t*label = $$.c = abc_label($$.c);
1890               jmp->branch = label;              
1891              }
1892
1893 E : '!' E    {$$.c=$2.c;
1894               $$.c = abc_not($$.c);
1895               $$.t = TYPE_BOOLEAN;
1896              }
1897
1898 E : '~' E    {$$.c=$2.c;
1899               $$.c = abc_bitnot($$.c);
1900               $$.t = TYPE_INT;
1901              }
1902
1903 E : E '&' E {$$.c = code_append($1.c,$3.c);
1904              $$.c = abc_bitand($$.c);
1905              $$.t = TYPE_INT;
1906             }
1907
1908 E : E '^' E {$$.c = code_append($1.c,$3.c);
1909              $$.c = abc_bitxor($$.c);
1910              $$.t = TYPE_INT;
1911             }
1912
1913 E : E '|' E {$$.c = code_append($1.c,$3.c);
1914              $$.c = abc_bitor($$.c);
1915              $$.t = TYPE_INT;
1916             }
1917
1918 E : E '-' E {$$.c = code_append($1.c,$3.c);
1919              if(BOTH_INT($1,$3)) {
1920                 $$.c = abc_subtract_i($$.c);
1921                 $$.t = TYPE_INT;
1922              } else {
1923                 $$.c = abc_subtract($$.c);
1924                 $$.t = TYPE_NUMBER;
1925              }
1926             }
1927 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1928              $$.c = abc_rshift($$.c);
1929              $$.t = TYPE_INT;
1930             }
1931 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1932              $$.c = abc_urshift($$.c);
1933              $$.t = TYPE_INT;
1934             }
1935 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1936              $$.c = abc_lshift($$.c);
1937              $$.t = TYPE_INT;
1938             }
1939
1940 E : E '/' E {$$.c = code_append($1.c,$3.c);
1941              $$.c = abc_divide($$.c);
1942              $$.t = TYPE_NUMBER;
1943             }
1944 E : E '+' E {$$.c = code_append($1.c,$3.c);
1945              $$.c = abc_add($$.c);
1946              $$.t = TYPE_NUMBER;
1947             }
1948 E : E '%' E {$$.c = code_append($1.c,$3.c);
1949              $$.c = abc_modulo($$.c);
1950              $$.t = TYPE_NUMBER;
1951             }
1952 E : E '*' E {$$.c = code_append($1.c,$3.c);
1953              if(BOTH_INT($1,$3)) {
1954                 $$.c = abc_multiply_i($$.c);
1955                 $$.t = TYPE_INT;
1956              } else {
1957                 $$.c = abc_multiply($$.c);
1958                 $$.t = TYPE_NUMBER;
1959              }
1960             }
1961
1962 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1963               if(use_astype && TYPE_IS_CLASS($3.t)) {
1964                 MULTINAME(m,$3.t->cls);
1965                 $$.c = abc_astype2($1.c, &m);
1966                 $$.t = $3.t->cls;
1967               } else {
1968                 $$.c = code_append($1.c, $3.c);
1969                 $$.c = abc_astypelate($$.c);
1970                 $$.t = TYPE_ANY;
1971               }
1972              }
1973
1974 E : E "instanceof" E 
1975              {$$.c = code_append($1.c, $3.c);
1976               $$.c = abc_instanceof($$.c);
1977               $$.t = TYPE_BOOLEAN;
1978              }
1979
1980 E : E "is" E {$$.c = code_append($1.c, $3.c);
1981               $$.c = abc_istypelate($$.c);
1982               $$.t = TYPE_BOOLEAN;
1983              }
1984
1985 E : "typeof" '(' E ')' {
1986               $$.c = $3.c;
1987               $$.c = abc_typeof($$.c);
1988               $$.t = TYPE_STRING;
1989              }
1990
1991 E : "void" E {
1992               $$.c = cut_last_push($2.c);
1993               $$.c = abc_pushundefined($$.c);
1994               $$.t = TYPE_ANY;
1995              }
1996
1997 E : "void" { $$.c = abc_pushundefined(0);
1998              $$.t = TYPE_ANY;
1999            }
2000
2001 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2002
2003 E : '-' E {
2004   $$=$2;
2005   if(IS_INT($2)) {
2006    $$.c=abc_negate_i($$.c);
2007    $$.t = TYPE_INT;
2008   } else {
2009    $$.c=abc_negate($$.c);
2010    $$.t = TYPE_NUMBER;
2011   }
2012 }
2013
2014 E : E '[' E ']' {
2015   $$.c = $1.c;
2016   $$.c = code_append($$.c, $3.c);
2017  
2018   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2019   $$.c = abc_getproperty2($$.c, &m);
2020   $$.t = 0; // array elements have unknown type
2021 }
2022
2023 E : '[' MAYBE_EXPRESSION_LIST ']' {
2024     $$.c = code_new();
2025     typedcode_list_t*l = 0;
2026     int len = 0;
2027     for(l=$2;l;l=l->next) {
2028         $$.c = code_append($$.c, l->typedcode->c);len++;
2029     }
2030     $$.c = abc_newarray($$.c, len);
2031     $$.t = registry_getarrayclass();
2032 }
2033
2034 E : E "*=" E { 
2035                code_t*c = $3.c;
2036                if(BOTH_INT($1,$3)) {
2037                 c=abc_multiply_i(c);
2038                } else {
2039                 c=abc_multiply(c);
2040                }
2041                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2042                $$.c = toreadwrite($1.c, c, 0, 0);
2043                $$.t = $1.t;
2044               }
2045
2046 E : E "%=" E { 
2047                code_t*c = abc_modulo($3.c);
2048                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2049                $$.c = toreadwrite($1.c, c, 0, 0);
2050                $$.t = $1.t;
2051               }
2052 E : E "<<=" E { 
2053                code_t*c = abc_lshift($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_rshift($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_urshift($3.c);
2066                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2067                $$.c = toreadwrite($1.c, c, 0, 0);
2068                $$.t = $1.t;
2069               }
2070 E : E "/=" E { 
2071                code_t*c = abc_divide($3.c);
2072                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2073                $$.c = toreadwrite($1.c, c, 0, 0);
2074                $$.t = $1.t;
2075               }
2076 E : E "+=" E { 
2077                code_t*c = $3.c;
2078                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2079                 c=abc_add_i(c);
2080                } else {
2081                 c=abc_add(c);
2082                }
2083                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2084                
2085                $$.c = toreadwrite($1.c, c, 0, 0);
2086                $$.t = $1.t;
2087               }
2088 E : E "-=" E { code_t*c = $3.c; 
2089                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2090                 c=abc_subtract_i(c);
2091                } else {
2092                 c=abc_subtract(c);
2093                }
2094                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2095                
2096                $$.c = toreadwrite($1.c, c, 0, 0);
2097                $$.t = $1.t;
2098              }
2099 E : E '=' E { code_t*c = 0;
2100               c = code_append(c, $3.c);
2101               c = converttype(c, $3.t, $1.t);
2102               $$.c = toreadwrite($1.c, c, 1, 0);
2103               $$.t = $1.t;
2104             }
2105
2106 E : E '?' E ':' E %prec below_assignment { 
2107               $$.c = $1.c;
2108               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2109               $$.c = code_append($$.c, $3.c);
2110               code_t*j2 = $$.c = abc_jump($$.c, 0);
2111               $$.c = j1->branch = abc_label($$.c);
2112               $$.c = code_append($$.c, $5.c);
2113               $$.c = j2->branch = abc_label($$.c);
2114               $$.t = join_types($3.t,$5.t,'?');
2115             }
2116
2117 // TODO: use inclocal where appropriate
2118 E : E "++" { code_t*c = 0;
2119              classinfo_t*type = $1.t;
2120              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2121                  c=abc_increment_i(c);
2122                  type = TYPE_INT;
2123              } else {
2124                  c=abc_increment(c);
2125                  type = TYPE_NUMBER;
2126              }
2127              c=converttype(c, type, $1.t);
2128              $$.c = toreadwrite($1.c, c, 0, 1);
2129              $$.t = $1.t;
2130            }
2131 E : E "--" { code_t*c = 0;
2132              classinfo_t*type = $1.t;
2133              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2134                  c=abc_decrement_i(c);
2135                  type = TYPE_INT;
2136              } else {
2137                  c=abc_decrement(c);
2138                  type = TYPE_NUMBER;
2139              }
2140              c=converttype(c, type, $1.t);
2141              $$.c = toreadwrite($1.c, c, 0, 1);
2142              $$.t = $1.t;
2143             }
2144
2145 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2146              classinfo_t*type = $2.t;
2147              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2148                  c=abc_increment_i(c);
2149                  type = TYPE_INT;
2150              } else {
2151                  c=abc_increment(c);
2152                  type = TYPE_NUMBER;
2153              }
2154              c=converttype(c, type, $2.t);
2155              $$.c = toreadwrite($2.c, c, 0, 0);
2156              $$.t = $2.t;
2157            }
2158
2159 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2160              classinfo_t*type = $2.t;
2161              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2162                  c=abc_decrement_i(c);
2163                  type = TYPE_INT;
2164              } else {
2165                  c=abc_decrement(c);
2166                  type = TYPE_NUMBER;
2167              }
2168              c=converttype(c, type, $2.t);
2169              $$.c = toreadwrite($2.c, c, 0, 0);
2170              $$.t = $2.t;
2171            }
2172
2173 E : "super" '.' T_IDENTIFIER 
2174            { if(!state->cls->info)
2175                   syntaxerror("super keyword not allowed outside a class");
2176               classinfo_t*t = state->cls->info->superclass;
2177               if(!t) t = TYPE_OBJECT;
2178
2179               memberinfo_t*f = registry_findmember(t, $3);
2180               namespace_t ns = {flags2access(f->flags), ""};
2181               MEMBER_MULTINAME(m, f, $3);
2182               $$.c = 0;
2183               $$.c = abc_getlocal_0($$.c);
2184               $$.c = abc_getsuper2($$.c, &m);
2185               $$.t = memberinfo_gettype(f);
2186            }
2187
2188 E : E '.' T_IDENTIFIER
2189             {$$.c = $1.c;
2190              classinfo_t*t = $1.t;
2191              char is_static = 0;
2192              if(TYPE_IS_CLASS(t) && t->cls) {
2193                  t = t->cls;
2194                  is_static = 1;
2195              }
2196              if(t) {
2197                  memberinfo_t*f = registry_findmember(t, $3);
2198                  char noslot = 0;
2199                  if(f && !is_static != !(f->flags&FLAG_STATIC))
2200                     noslot=1;
2201                  if(f && f->slot && !noslot) {
2202                      $$.c = abc_getslot($$.c, f->slot);
2203                  } else {
2204                      MEMBER_MULTINAME(m, f, $3);
2205                      $$.c = abc_getproperty2($$.c, &m);
2206                  }
2207                  /* determine type */
2208                  $$.t = memberinfo_gettype(f);
2209                  if(!$$.t)
2210                     $$.c = abc_coerce_a($$.c);
2211              } else {
2212                  /* when resolving a property on an unknown type, we do know the
2213                     name of the property (and don't seem to need the package), but
2214                     we need to make avm2 try out all access modes */
2215                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2216                  $$.c = abc_getproperty2($$.c, &m);
2217                  $$.c = abc_coerce_a($$.c);
2218                  $$.t = registry_getanytype();
2219              }
2220             }
2221
2222 VAR_READ : T_IDENTIFIER {
2223     $$.t = 0;
2224     $$.c = 0;
2225     int i;
2226     classinfo_t*a = 0;
2227     memberinfo_t*f = 0;
2228
2229     /* look at variables */
2230     if((i = find_variable($1, &$$.t)) >= 0) {
2231         // $1 is a local variable
2232         $$.c = abc_getlocal($$.c, i);
2233
2234     /* look at current class' members */
2235     } else if((f = registry_findmember(state->cls->info, $1))) {
2236         // $1 is a function in this class
2237         int var_is_static = (f->flags&FLAG_STATIC);
2238         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2239         if(var_is_static != i_am_static) {
2240             /* there doesn't seem to be any "static" way to access
2241                static properties of a class */
2242             state->method->late_binding = 1;
2243             $$.t = f->type;
2244             namespace_t ns = {flags2access(f->flags), ""};
2245             multiname_t m = {QNAME, &ns, 0, $1};
2246             $$.c = abc_findpropstrict2($$.c, &m);
2247             $$.c = abc_getproperty2($$.c, &m);
2248         } else {
2249             if(f->slot>0) {
2250                 $$.c = abc_getlocal_0($$.c);
2251                 $$.c = abc_getslot($$.c, f->slot);
2252             } else {
2253                 namespace_t ns = {flags2access(f->flags), ""};
2254                 multiname_t m = {QNAME, &ns, 0, $1};
2255                 $$.c = abc_getlocal_0($$.c);
2256                 $$.c = abc_getproperty2($$.c, &m);
2257             }
2258         }
2259         if(f->kind == MEMBER_METHOD) {
2260             $$.t = TYPE_FUNCTION(f);
2261         } else {
2262             $$.t = f->type;
2263         }
2264     
2265     /* look at classes in the current package and imported classes */
2266     } else if((a = find_class($1))) {
2267         if(a->flags & FLAG_METHOD) {
2268             MULTINAME(m, a);
2269             $$.c = abc_findpropstrict2($$.c, &m);
2270             $$.c = abc_getproperty2($$.c, &m);
2271             $$.t = TYPE_FUNCTION(a->function);
2272         } else {
2273             if(a->slot) {
2274                 $$.c = abc_getglobalscope($$.c);
2275                 $$.c = abc_getslot($$.c, a->slot);
2276             } else {
2277                 MULTINAME(m, a);
2278                 $$.c = abc_getlex2($$.c, &m);
2279             }
2280             $$.t = TYPE_CLASS(a);
2281         }
2282
2283     /* unknown object, let the avm2 resolve it */
2284     } else {
2285         if(strcmp($1,"trace"))
2286             warning("Couldn't resolve '%s', doing late binding", $1);
2287         state->method->late_binding = 1;
2288                 
2289         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2290
2291         $$.t = 0;
2292         $$.c = abc_findpropstrict2($$.c, &m);
2293         $$.c = abc_getproperty2($$.c, &m);
2294     }
2295 }
2296
2297 //TODO: 
2298 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2299 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2300 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2301
2302 // ----------------- namespaces -------------------------------------------------
2303
2304 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2305 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2306 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2307
2308 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
2309