implemented switch
[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     $$ = abc___continue__($$, "");
1403     code_t*e = $$ = abc_nop($$);
1404     j->branch = e;
1405 }
1406 DEFAULT: "default" ':' MAYBECODE {
1407     $$ = $3;
1408 }
1409 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1410     $$=$4.c;
1411     $$ = code_append($$, $7);
1412     code_t*out = $$ = abc_pop($$);
1413     breakjumpsto($$, $1, out);
1414     
1415     code_t*c = $$,*lastblock=0;
1416     while(c) {
1417         if(c->opcode == OPCODE_IFNE) {
1418             lastblock=c->next;
1419         } else if(c->opcode == OPCODE___CONTINUE__) {
1420             if(lastblock) {
1421                 c->opcode = OPCODE_JUMP;
1422                 c->branch = lastblock;
1423             } else {
1424                 /* fall through end of switch */
1425                 c->opcode = OPCODE_NOP;
1426             }
1427         }
1428         c=c->prev;
1429     }
1430     old_state();
1431 }
1432
1433 /* ------------ packages and imports ---------------- */
1434
1435 X_IDENTIFIER: T_IDENTIFIER
1436             | "package" {$$="package";}
1437
1438 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1439 PACKAGE: X_IDENTIFIER             {$$=$1;}
1440
1441 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1442 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1443
1444 IMPORT : "import" QNAME {
1445        classinfo_t*c = $2;
1446        if(!c) 
1447             syntaxerror("Couldn't import class\n");
1448        state_has_imports();
1449        dict_put(state->imports, c->name, c);
1450        $$=0;
1451 }
1452 IMPORT : "import" PACKAGE '.' '*' {
1453        NEW(import_t,i);
1454        i->package = $2;
1455        state_has_imports();
1456        list_append(state->wildcard_imports, i);
1457        $$=0;
1458 }
1459
1460 /* ------------ classes and interfaces (header) -------------- */
1461
1462 MAYBE_MODIFIERS : {$$=0;}
1463 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1464 MODIFIER_LIST : MODIFIER               {$$=$1;}
1465 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1466
1467 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1468          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1469          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1470          | KW_STATIC {$$=FLAG_STATIC;}
1471          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1472          | KW_FINAL {$$=FLAG_FINAL;}
1473          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1474          | KW_NATIVE {$$=FLAG_NATIVE;}
1475          | KW_INTERNAL {$$=FLAG_INTERNAL;}
1476
1477 EXTENDS : {$$=registry_getobjectclass();}
1478 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1479
1480 EXTENDS_LIST : {$$=list_new();}
1481 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1482
1483 IMPLEMENTS_LIST : {$$=list_new();}
1484 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1485
1486 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1487                               EXTENDS IMPLEMENTS_LIST 
1488                               '{' {startclass($1,$3,$4,$5, 0);} 
1489                               MAYBE_DECLARATION_LIST 
1490                               '}' {endclass();}
1491
1492 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1493                               EXTENDS_LIST 
1494                               '{' {startclass($1,$3,0,$4,1);}
1495                               MAYBE_IDECLARATION_LIST 
1496                               '}' {endclass();}
1497
1498 /* ------------ classes and interfaces (body) -------------- */
1499
1500 MAYBE_DECLARATION_LIST : 
1501 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1502 DECLARATION_LIST : DECLARATION
1503 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1504 DECLARATION : ';'
1505 DECLARATION : SLOT_DECLARATION
1506 DECLARATION : FUNCTION_DECLARATION
1507
1508 MAYBE_IDECLARATION_LIST : 
1509 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1510 IDECLARATION_LIST : IDECLARATION
1511 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1512 IDECLARATION : ';'
1513 IDECLARATION : "var" T_IDENTIFIER {
1514     syntaxerror("variable declarations not allowed in interfaces");
1515 }
1516 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1517     $1 |= FLAG_PUBLIC;
1518     if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1519         syntaxerror("invalid method modifiers: interface methods always need to be public");
1520     }
1521     startfunction(0,$1,$3,$4,&$6,$8);
1522     endfunction(0,$1,$3,$4,&$6,$8, 0);
1523 }
1524
1525 /* ------------ classes and interfaces (body, slots ) ------- */
1526
1527 VARCONST: "var" | "const"
1528
1529 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1530     int flags = $1;
1531     memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1532     info->type = $4;
1533     info->flags = flags;
1534     trait_t*t=0;
1535
1536     namespace_t mname_ns = {flags2access(flags), ""};
1537     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1538
1539     if(!(flags&FLAG_STATIC)) {
1540         if($4) {
1541             MULTINAME(m, $4);
1542             t=abc_class_slot(state->cls->abc, &mname, &m);
1543         } else {
1544             t=abc_class_slot(state->cls->abc, &mname, 0);
1545         }
1546         info->slot = t->slot_id;
1547     } else {
1548         if($4) {
1549             MULTINAME(m, $4);
1550             t=abc_class_staticslot(state->cls->abc, &mname, &m);
1551         } else {
1552             t=abc_class_staticslot(state->cls->abc, &mname, 0);
1553         }
1554         info->slot = t->slot_id;
1555     }
1556     if($5.c && !is_pushundefined($5.c)) {
1557         code_t*c = 0;
1558         c = abc_getlocal_0(c);
1559         c = code_append(c, $5.c);
1560         c = converttype(c, $5.t, $4);
1561         c = abc_setslot(c, t->slot_id);
1562         if(!(flags&FLAG_STATIC))
1563             state->cls->init = code_append(state->cls->init, c);
1564         else
1565             state->cls->static_init = code_append(state->cls->static_init, c);
1566     }
1567     if($2==KW_CONST) {
1568         t->kind= TRAIT_CONST;
1569     }
1570 }
1571
1572 /* ------------ constants -------------------------------------- */
1573
1574 MAYBESTATICCONSTANT: {$$=0;}
1575 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1576
1577 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1578 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1579 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1580 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1581 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1582 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1583 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1584 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1585 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1586
1587 /* ------------ classes and interfaces (body, functions) ------- */
1588
1589 // non-vararg version
1590 MAYBE_PARAM_LIST: {
1591     memset(&$$,0,sizeof($$));
1592 }
1593 MAYBE_PARAM_LIST: PARAM_LIST {
1594     $$=$1;
1595 }
1596
1597 // vararg version
1598 MAYBE_PARAM_LIST: "..." PARAM {
1599     memset(&$$,0,sizeof($$));
1600     $$.varargs=1;
1601     list_append($$.list, $2);
1602 }
1603 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1604     $$ =$1;
1605     $$.varargs=1;
1606     list_append($$.list, $4);
1607 }
1608
1609 // non empty
1610 PARAM_LIST: PARAM_LIST ',' PARAM {
1611     $$ = $1;
1612     list_append($$.list, $3);
1613 }
1614 PARAM_LIST: PARAM {
1615     memset(&$$,0,sizeof($$));
1616     list_append($$.list, $1);
1617 }
1618
1619 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1620      $$ = malloc(sizeof(param_t));
1621      $$->name=$1;
1622      $$->type = $3;
1623      $$->value = $4;
1624 }
1625 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1626      $$ = malloc(sizeof(param_t));
1627      $$->name=$1;
1628      $$->type = TYPE_ANY;
1629      $$->value = $2;
1630 }
1631 GETSET : "get" {$$=$1;}
1632        | "set" {$$=$1;}
1633        |       {$$=0;}
1634
1635 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1636                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1637 {
1638     code_t*c = 0;
1639     if(state->method->late_binding) {
1640         c = abc_getlocal_0(c);
1641         c = abc_pushscope(c);
1642     }
1643     if(state->method->is_constructor && !state->method->has_super) {
1644         // call default constructor
1645         c = abc_getlocal_0(c);
1646         c = abc_constructsuper(c, 0);
1647     }
1648     c = wrap_function(c, state->method->initcode, $11);
1649     endfunction(0,$1,$3,$4,&$6,$8,c);
1650 }
1651
1652 /* ------------- package + class ids --------------- */
1653
1654 CLASS: T_IDENTIFIER {
1655
1656     /* try current package */
1657     $$ = find_class($1);
1658     if(!$$) syntaxerror("Could not find class %s\n", $1);
1659 }
1660
1661 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1662     $$ = registry_findclass($1, $3);
1663     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1664 }
1665
1666 QNAME: PACKAGEANDCLASS
1667      | CLASS
1668
1669 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1670 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1671
1672 TYPE : QNAME      {$$=$1;}
1673      | '*'        {$$=registry_getanytype();}
1674      | "void"     {$$=registry_getanytype();}
1675     /*
1676      |  "String"  {$$=registry_getstringclass();}
1677      |  "int"     {$$=registry_getintclass();}
1678      |  "uint"    {$$=registry_getuintclass();}
1679      |  "Boolean" {$$=registry_getbooleanclass();}
1680      |  "Number"  {$$=registry_getnumberclass();}
1681     */
1682
1683 MAYBETYPE: ':' TYPE {$$=$2;}
1684 MAYBETYPE:          {$$=0;}
1685
1686 /* ----------function calls, delete, constructor calls ------ */
1687
1688 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1689 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1690
1691 MAYBE_EXPRESSION_LIST : {$$=0;}
1692 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1693 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1694                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1695                                                   *t = $1;
1696                                                   list_append($$, t);}
1697 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1698                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1699                                                   *t = $3;
1700                                                   list_append($$, t);}
1701
1702 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1703     MULTINAME(m, $2);
1704     $$.c = code_new();
1705
1706     if($2->slot) {
1707         $$.c = abc_getglobalscope($$.c);
1708         $$.c = abc_getslot($$.c, $2->slot);
1709     } else {
1710         $$.c = abc_findpropstrict2($$.c, &m);
1711     }
1712
1713     typedcode_list_t*l = $3;
1714     int len = 0;
1715     while(l) {
1716         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1717         l = l->next;
1718         len ++;
1719     }
1720     if($2->slot)
1721         $$.c = abc_construct($$.c, len);
1722     else
1723         $$.c = abc_constructprop2($$.c, &m, len);
1724     $$.t = $2;
1725 }
1726
1727 /* TODO: use abc_call (for calling local variables),
1728          abc_callstatic (for calling own methods) 
1729          call (for closures)
1730 */
1731 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1732     typedcode_list_t*l = $3;
1733     int len = 0;
1734     code_t*paramcode = 0;
1735     while(l) {
1736         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1737         l = l->next;
1738         len ++;
1739     }
1740        
1741     $$.c = $1.c;
1742     if($$.c->opcode == OPCODE_COERCE_A) {
1743         $$.c = code_cutlast($$.c);
1744     }
1745
1746     $$.t = TYPE_ANY;
1747     multiname_t*name = 0;
1748     if($$.c->opcode == OPCODE_GETPROPERTY) {
1749         name = multiname_clone($$.c->data[0]);
1750         $$.c = code_cutlast($$.c);
1751         $$.c = code_append($$.c, paramcode);
1752         $$.c = abc_callproperty2($$.c, name, len);
1753     } else if($$.c->opcode == OPCODE_GETSLOT) {
1754         int slot = (int)(ptroff_t)$$.c->data[0];
1755         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1756         if(t->kind!=TRAIT_METHOD) {
1757             //ok: flash allows to assign closures to members.
1758         }
1759         name = t->name;
1760         $$.c = code_cutlast($$.c);
1761         $$.c = code_append($$.c, paramcode);
1762         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1763         $$.c = abc_callproperty2($$.c, name, len);
1764     } else if($$.c->opcode == OPCODE_GETSUPER) {
1765         name = multiname_clone($$.c->data[0]);
1766         $$.c = code_cutlast($$.c);
1767         $$.c = code_append($$.c, paramcode);
1768         $$.c = abc_callsuper2($$.c, name, len);
1769     } else {
1770         $$.c = abc_getlocal_0($$.c);
1771         $$.c = code_append($$.c, paramcode);
1772         $$.c = abc_call($$.c, len);
1773     }
1774    
1775     memberinfo_t*f = 0;
1776    
1777     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1778         $$.t = $1.t->function->return_type;
1779     } else {
1780         $$.c = abc_coerce_a($$.c);
1781         $$.t = TYPE_ANY;
1782     }
1783 }
1784 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1785     if(!state->cls) syntaxerror("super() not allowed outside of a class");
1786     if(!state->method) syntaxerror("super() not allowed outside of a function");
1787     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1788
1789     $$.c = code_new();
1790     $$.c = abc_getlocal_0($$.c);
1791     typedcode_list_t*l = 0;
1792     int len = 0;
1793     for(l=$3;l;l=l->next) {
1794         $$.c = code_append($$.c, l->typedcode->c);len++;
1795     }
1796     /*
1797     this is dependent on the control path, check this somewhere else
1798     if(state->method->has_super)
1799         syntaxerror("constructor may call super() only once");
1800     */
1801     state->method->has_super = 1;
1802     $$.c = abc_constructsuper($$.c, len);
1803     $$.c = abc_pushundefined($$.c);
1804     $$.t = TYPE_ANY;
1805 }
1806
1807 DELETE: "delete" E {
1808     $$.c = $2.c;
1809     if($$.c->opcode == OPCODE_COERCE_A) {
1810         $$.c = code_cutlast($$.c);
1811     }
1812     multiname_t*name = 0;
1813     if($$.c->opcode == OPCODE_GETPROPERTY) {
1814         $$.c->opcode = OPCODE_DELETEPROPERTY;
1815     } else if($$.c->opcode == OPCODE_GETSLOT) {
1816         int slot = (int)(ptroff_t)$$.c->data[0];
1817         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1818         $$.c = code_cutlast($$.c);
1819         $$.c = abc_deleteproperty2($$.c, name);
1820     } else {
1821         $$.c = abc_getlocal_0($$.c);
1822         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1823         $$.c = abc_deleteproperty2($$.c, &m);
1824     }
1825     $$.t = TYPE_BOOLEAN;
1826 }
1827
1828 RETURN: "return" %prec prec_none {
1829     $$ = abc_returnvoid(0);
1830 }
1831 RETURN: "return" EXPRESSION {
1832     $$ = $2.c;
1833     $$ = abc_returnvalue($$);
1834 }
1835
1836 // ----------------------- expression types -------------------------------------
1837
1838 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
1839 EXPRESSION : E                %prec below_minus {$$ = $1;}
1840 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1841     $$.c = $1.c;
1842     $$.c = cut_last_push($$.c);
1843     $$.c = code_append($$.c,$3.c);
1844     $$.t = $3.t;
1845 }
1846 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1847     $$=cut_last_push($1.c);
1848 }
1849
1850 // ----------------------- expression evaluation -------------------------------------
1851
1852 E : CONSTANT
1853 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1854 E : NEW                         {$$ = $1;}
1855 E : DELETE                      {$$ = $1;}
1856 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1857                                  $$.t = TYPE_ANY;
1858                                 }
1859
1860 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1861                    //MULTINAME(m, registry_getintclass());
1862                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1863                    $$.t = TYPE_INT;
1864                   }
1865 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1866                     $$.t = TYPE_INT;
1867                    }
1868 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1869                   $$.t = TYPE_INT;
1870                  }
1871 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1872                    $$.t = TYPE_UINT;
1873                   }
1874 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1875                     $$.t = TYPE_FLOAT;
1876                    }
1877 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1878                      $$.t = TYPE_STRING;
1879                     }
1880 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1881                     $$.t = TYPE_ANY;
1882                    }
1883 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1884                     $$.t = TYPE_BOOLEAN;
1885                    }
1886 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1887                      $$.t = TYPE_BOOLEAN;
1888                     }
1889 CONSTANT : "null" {$$.c = abc_pushnull(0);
1890                     $$.t = TYPE_NULL;
1891                    }
1892
1893 E : FUNCTIONCALL
1894 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1895              $$.t = TYPE_BOOLEAN;
1896             }
1897 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1898              $$.t = TYPE_BOOLEAN;
1899             }
1900 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1901               $$.t = TYPE_BOOLEAN;
1902              }
1903 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1904               $$.t = TYPE_BOOLEAN;
1905              }
1906 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1907               $$.t = TYPE_BOOLEAN;
1908              }
1909 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1910               $$.t = TYPE_BOOLEAN;
1911               }
1912 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1913               $$.t = TYPE_BOOLEAN;
1914              }
1915 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1916               $$.t = TYPE_BOOLEAN;
1917              }
1918
1919 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1920               $$.c = $1.c;
1921               $$.c = converttype($$.c, $1.t, $$.t);
1922               $$.c = abc_dup($$.c);
1923               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1924               $$.c = cut_last_push($$.c);
1925               $$.c = code_append($$.c,$3.c);
1926               $$.c = converttype($$.c, $3.t, $$.t);
1927               code_t*label = $$.c = abc_label($$.c);
1928               jmp->branch = label;
1929              }
1930 E : E "&&" E {
1931               $$.t = join_types($1.t, $3.t, 'A');
1932               /*printf("%08x:\n",$1.t);
1933               code_dump($1.c, 0, 0, "", stdout);
1934               printf("%08x:\n",$3.t);
1935               code_dump($3.c, 0, 0, "", stdout);
1936               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1937               $$.c = $1.c;
1938               $$.c = converttype($$.c, $1.t, $$.t);
1939               $$.c = abc_dup($$.c);
1940               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1941               $$.c = cut_last_push($$.c);
1942               $$.c = code_append($$.c,$3.c);
1943               $$.c = converttype($$.c, $3.t, $$.t);
1944               code_t*label = $$.c = abc_label($$.c);
1945               jmp->branch = label;              
1946              }
1947
1948 E : '!' E    {$$.c=$2.c;
1949               $$.c = abc_not($$.c);
1950               $$.t = TYPE_BOOLEAN;
1951              }
1952
1953 E : '~' E    {$$.c=$2.c;
1954               $$.c = abc_bitnot($$.c);
1955               $$.t = TYPE_INT;
1956              }
1957
1958 E : E '&' E {$$.c = code_append($1.c,$3.c);
1959              $$.c = abc_bitand($$.c);
1960              $$.t = TYPE_INT;
1961             }
1962
1963 E : E '^' E {$$.c = code_append($1.c,$3.c);
1964              $$.c = abc_bitxor($$.c);
1965              $$.t = TYPE_INT;
1966             }
1967
1968 E : E '|' E {$$.c = code_append($1.c,$3.c);
1969              $$.c = abc_bitor($$.c);
1970              $$.t = TYPE_INT;
1971             }
1972
1973 E : E '-' E {$$.c = code_append($1.c,$3.c);
1974              if(BOTH_INT($1,$3)) {
1975                 $$.c = abc_subtract_i($$.c);
1976                 $$.t = TYPE_INT;
1977              } else {
1978                 $$.c = abc_subtract($$.c);
1979                 $$.t = TYPE_NUMBER;
1980              }
1981             }
1982 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1983              $$.c = abc_rshift($$.c);
1984              $$.t = TYPE_INT;
1985             }
1986 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1987              $$.c = abc_urshift($$.c);
1988              $$.t = TYPE_INT;
1989             }
1990 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1991              $$.c = abc_lshift($$.c);
1992              $$.t = TYPE_INT;
1993             }
1994
1995 E : E '/' E {$$.c = code_append($1.c,$3.c);
1996              $$.c = abc_divide($$.c);
1997              $$.t = TYPE_NUMBER;
1998             }
1999 E : E '+' E {$$.c = code_append($1.c,$3.c);
2000              $$.c = abc_add($$.c);
2001              $$.t = TYPE_NUMBER;
2002             }
2003 E : E '%' E {$$.c = code_append($1.c,$3.c);
2004              $$.c = abc_modulo($$.c);
2005              $$.t = TYPE_NUMBER;
2006             }
2007 E : E '*' E {$$.c = code_append($1.c,$3.c);
2008              if(BOTH_INT($1,$3)) {
2009                 $$.c = abc_multiply_i($$.c);
2010                 $$.t = TYPE_INT;
2011              } else {
2012                 $$.c = abc_multiply($$.c);
2013                 $$.t = TYPE_NUMBER;
2014              }
2015             }
2016
2017 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2018               if(use_astype && TYPE_IS_CLASS($3.t)) {
2019                 MULTINAME(m,$3.t->cls);
2020                 $$.c = abc_astype2($1.c, &m);
2021                 $$.t = $3.t->cls;
2022               } else {
2023                 $$.c = code_append($1.c, $3.c);
2024                 $$.c = abc_astypelate($$.c);
2025                 $$.t = TYPE_ANY;
2026               }
2027              }
2028
2029 E : E "instanceof" E 
2030              {$$.c = code_append($1.c, $3.c);
2031               $$.c = abc_instanceof($$.c);
2032               $$.t = TYPE_BOOLEAN;
2033              }
2034
2035 E : E "is" E {$$.c = code_append($1.c, $3.c);
2036               $$.c = abc_istypelate($$.c);
2037               $$.t = TYPE_BOOLEAN;
2038              }
2039
2040 E : "typeof" '(' E ')' {
2041               $$.c = $3.c;
2042               $$.c = abc_typeof($$.c);
2043               $$.t = TYPE_STRING;
2044              }
2045
2046 E : "void" E {
2047               $$.c = cut_last_push($2.c);
2048               $$.c = abc_pushundefined($$.c);
2049               $$.t = TYPE_ANY;
2050              }
2051
2052 E : "void" { $$.c = abc_pushundefined(0);
2053              $$.t = TYPE_ANY;
2054            }
2055
2056 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2057
2058 E : '-' E {
2059   $$=$2;
2060   if(IS_INT($2)) {
2061    $$.c=abc_negate_i($$.c);
2062    $$.t = TYPE_INT;
2063   } else {
2064    $$.c=abc_negate($$.c);
2065    $$.t = TYPE_NUMBER;
2066   }
2067 }
2068
2069 E : E '[' E ']' {
2070   $$.c = $1.c;
2071   $$.c = code_append($$.c, $3.c);
2072  
2073   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2074   $$.c = abc_getproperty2($$.c, &m);
2075   $$.t = 0; // array elements have unknown type
2076 }
2077
2078 E : '[' MAYBE_EXPRESSION_LIST ']' {
2079     $$.c = code_new();
2080     typedcode_list_t*l = 0;
2081     int len = 0;
2082     for(l=$2;l;l=l->next) {
2083         $$.c = code_append($$.c, l->typedcode->c);len++;
2084     }
2085     $$.c = abc_newarray($$.c, len);
2086     $$.t = registry_getarrayclass();
2087 }
2088
2089 MAYBE_EXPRPAIR_LIST : {$$=0;}
2090 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2091
2092 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2093     typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $1;
2094     typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $3;
2095     $$ = 0;
2096     list_append($$, t1);
2097     list_append($$, t2);
2098 }
2099 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2100     $$=$1;
2101     typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $3;
2102     typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $5;
2103     list_append($$, t1);
2104     list_append($$, t2);
2105 }
2106 //MAYBECOMMA: ','
2107 //MAYBECOMMA:
2108
2109 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2110     $$.c = code_new();
2111     typedcode_list_t*l = 0;
2112     int len = 0;
2113     for(l=$2;l;l=l->next) {
2114         $$.c = code_append($$.c, l->typedcode->c);len++;
2115     }
2116     $$.c = abc_newobject($$.c, len/2);
2117     $$.t = registry_getobjectclass();
2118 }
2119
2120 E : E "*=" E { 
2121                code_t*c = $3.c;
2122                if(BOTH_INT($1,$3)) {
2123                 c=abc_multiply_i(c);
2124                } else {
2125                 c=abc_multiply(c);
2126                }
2127                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2128                $$.c = toreadwrite($1.c, c, 0, 0);
2129                $$.t = $1.t;
2130               }
2131
2132 E : E "%=" E { 
2133                code_t*c = abc_modulo($3.c);
2134                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2135                $$.c = toreadwrite($1.c, c, 0, 0);
2136                $$.t = $1.t;
2137               }
2138 E : E "<<=" E { 
2139                code_t*c = abc_lshift($3.c);
2140                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2141                $$.c = toreadwrite($1.c, c, 0, 0);
2142                $$.t = $1.t;
2143               }
2144 E : E ">>=" E { 
2145                code_t*c = abc_rshift($3.c);
2146                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2147                $$.c = toreadwrite($1.c, c, 0, 0);
2148                $$.t = $1.t;
2149               }
2150 E : E ">>>=" E { 
2151                code_t*c = abc_urshift($3.c);
2152                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2153                $$.c = toreadwrite($1.c, c, 0, 0);
2154                $$.t = $1.t;
2155               }
2156 E : E "/=" E { 
2157                code_t*c = abc_divide($3.c);
2158                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2159                $$.c = toreadwrite($1.c, c, 0, 0);
2160                $$.t = $1.t;
2161               }
2162 E : E "+=" E { 
2163                code_t*c = $3.c;
2164                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2165                 c=abc_add_i(c);
2166                } else {
2167                 c=abc_add(c);
2168                }
2169                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2170                
2171                $$.c = toreadwrite($1.c, c, 0, 0);
2172                $$.t = $1.t;
2173               }
2174 E : E "-=" E { code_t*c = $3.c; 
2175                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2176                 c=abc_subtract_i(c);
2177                } else {
2178                 c=abc_subtract(c);
2179                }
2180                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2181                
2182                $$.c = toreadwrite($1.c, c, 0, 0);
2183                $$.t = $1.t;
2184              }
2185 E : E '=' E { code_t*c = 0;
2186               c = code_append(c, $3.c);
2187               c = converttype(c, $3.t, $1.t);
2188               $$.c = toreadwrite($1.c, c, 1, 0);
2189               $$.t = $1.t;
2190             }
2191
2192 E : E '?' E ':' E %prec below_assignment { 
2193               $$.c = $1.c;
2194               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2195               $$.c = code_append($$.c, $3.c);
2196               code_t*j2 = $$.c = abc_jump($$.c, 0);
2197               $$.c = j1->branch = abc_label($$.c);
2198               $$.c = code_append($$.c, $5.c);
2199               $$.c = j2->branch = abc_label($$.c);
2200               $$.t = join_types($3.t,$5.t,'?');
2201             }
2202
2203 // TODO: use inclocal where appropriate
2204 E : E "++" { code_t*c = 0;
2205              classinfo_t*type = $1.t;
2206              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2207                  c=abc_increment_i(c);
2208                  type = TYPE_INT;
2209              } else {
2210                  c=abc_increment(c);
2211                  type = TYPE_NUMBER;
2212              }
2213              c=converttype(c, type, $1.t);
2214              $$.c = toreadwrite($1.c, c, 0, 1);
2215              $$.t = $1.t;
2216            }
2217 E : E "--" { code_t*c = 0;
2218              classinfo_t*type = $1.t;
2219              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2220                  c=abc_decrement_i(c);
2221                  type = TYPE_INT;
2222              } else {
2223                  c=abc_decrement(c);
2224                  type = TYPE_NUMBER;
2225              }
2226              c=converttype(c, type, $1.t);
2227              $$.c = toreadwrite($1.c, c, 0, 1);
2228              $$.t = $1.t;
2229             }
2230
2231 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2232              classinfo_t*type = $2.t;
2233              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2234                  c=abc_increment_i(c);
2235                  type = TYPE_INT;
2236              } else {
2237                  c=abc_increment(c);
2238                  type = TYPE_NUMBER;
2239              }
2240              c=converttype(c, type, $2.t);
2241              $$.c = toreadwrite($2.c, c, 0, 0);
2242              $$.t = $2.t;
2243            }
2244
2245 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2246              classinfo_t*type = $2.t;
2247              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2248                  c=abc_decrement_i(c);
2249                  type = TYPE_INT;
2250              } else {
2251                  c=abc_decrement(c);
2252                  type = TYPE_NUMBER;
2253              }
2254              c=converttype(c, type, $2.t);
2255              $$.c = toreadwrite($2.c, c, 0, 0);
2256              $$.t = $2.t;
2257            }
2258
2259 E : "super" '.' T_IDENTIFIER 
2260            { if(!state->cls->info)
2261                   syntaxerror("super keyword not allowed outside a class");
2262               classinfo_t*t = state->cls->info->superclass;
2263               if(!t) t = TYPE_OBJECT;
2264
2265               memberinfo_t*f = registry_findmember(t, $3);
2266               namespace_t ns = {flags2access(f->flags), ""};
2267               MEMBER_MULTINAME(m, f, $3);
2268               $$.c = 0;
2269               $$.c = abc_getlocal_0($$.c);
2270               $$.c = abc_getsuper2($$.c, &m);
2271               $$.t = memberinfo_gettype(f);
2272            }
2273
2274 E : E '.' T_IDENTIFIER
2275             {$$.c = $1.c;
2276              classinfo_t*t = $1.t;
2277              char is_static = 0;
2278              if(TYPE_IS_CLASS(t) && t->cls) {
2279                  t = t->cls;
2280                  is_static = 1;
2281              }
2282              if(t) {
2283                  memberinfo_t*f = registry_findmember(t, $3);
2284                  char noslot = 0;
2285                  if(f && !is_static != !(f->flags&FLAG_STATIC))
2286                     noslot=1;
2287                  if(f && f->slot && !noslot) {
2288                      $$.c = abc_getslot($$.c, f->slot);
2289                  } else {
2290                      MEMBER_MULTINAME(m, f, $3);
2291                      $$.c = abc_getproperty2($$.c, &m);
2292                  }
2293                  /* determine type */
2294                  $$.t = memberinfo_gettype(f);
2295                  if(!$$.t)
2296                     $$.c = abc_coerce_a($$.c);
2297              } else {
2298                  /* when resolving a property on an unknown type, we do know the
2299                     name of the property (and don't seem to need the package), but
2300                     we need to make avm2 try out all access modes */
2301                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2302                  $$.c = abc_getproperty2($$.c, &m);
2303                  $$.c = abc_coerce_a($$.c);
2304                  $$.t = registry_getanytype();
2305              }
2306             }
2307
2308 VAR_READ : T_IDENTIFIER {
2309     $$.t = 0;
2310     $$.c = 0;
2311     int i;
2312     classinfo_t*a = 0;
2313     memberinfo_t*f = 0;
2314
2315     /* look at variables */
2316     if((i = find_variable($1, &$$.t)) >= 0) {
2317         // $1 is a local variable
2318         $$.c = abc_getlocal($$.c, i);
2319
2320     /* look at current class' members */
2321     } else if((f = registry_findmember(state->cls->info, $1))) {
2322         // $1 is a function in this class
2323         int var_is_static = (f->flags&FLAG_STATIC);
2324         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2325         if(var_is_static != i_am_static) {
2326             /* there doesn't seem to be any "static" way to access
2327                static properties of a class */
2328             state->method->late_binding = 1;
2329             $$.t = f->type;
2330             namespace_t ns = {flags2access(f->flags), ""};
2331             multiname_t m = {QNAME, &ns, 0, $1};
2332             $$.c = abc_findpropstrict2($$.c, &m);
2333             $$.c = abc_getproperty2($$.c, &m);
2334         } else {
2335             if(f->slot>0) {
2336                 $$.c = abc_getlocal_0($$.c);
2337                 $$.c = abc_getslot($$.c, f->slot);
2338             } else {
2339                 namespace_t ns = {flags2access(f->flags), ""};
2340                 multiname_t m = {QNAME, &ns, 0, $1};
2341                 $$.c = abc_getlocal_0($$.c);
2342                 $$.c = abc_getproperty2($$.c, &m);
2343             }
2344         }
2345         if(f->kind == MEMBER_METHOD) {
2346             $$.t = TYPE_FUNCTION(f);
2347         } else {
2348             $$.t = f->type;
2349         }
2350     
2351     /* look at classes in the current package and imported classes */
2352     } else if((a = find_class($1))) {
2353         if(a->flags & FLAG_METHOD) {
2354             MULTINAME(m, a);
2355             $$.c = abc_findpropstrict2($$.c, &m);
2356             $$.c = abc_getproperty2($$.c, &m);
2357             $$.t = TYPE_FUNCTION(a->function);
2358         } else {
2359             if(a->slot) {
2360                 $$.c = abc_getglobalscope($$.c);
2361                 $$.c = abc_getslot($$.c, a->slot);
2362             } else {
2363                 MULTINAME(m, a);
2364                 $$.c = abc_getlex2($$.c, &m);
2365             }
2366             $$.t = TYPE_CLASS(a);
2367         }
2368
2369     /* unknown object, let the avm2 resolve it */
2370     } else {
2371         if(strcmp($1,"trace"))
2372             warning("Couldn't resolve '%s', doing late binding", $1);
2373         state->method->late_binding = 1;
2374                 
2375         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2376
2377         $$.t = 0;
2378         $$.c = abc_findpropstrict2($$.c, &m);
2379         $$.c = abc_getproperty2($$.c, &m);
2380     }
2381 }
2382
2383 //TODO: 
2384 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2385 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2386 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2387
2388 // ----------------- namespaces -------------------------------------------------
2389
2390 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2391 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2392 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2393
2394 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
2395