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