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