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