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