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