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