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