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