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