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