ea4da6b0c4050ceeeb582116db645746733b2f19
[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     state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
629
630     token_list_t*t=0;
631     classinfo_list_t*mlist=0;
632
633     if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
634         syntaxerror("invalid modifier(s)");
635
636     if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
637         syntaxerror("public and internal not supported at the same time.");
638
639     /* create the class name, together with the proper attributes */
640     int access=0;
641     char*package=0;
642
643     if(!(flags&FLAG_PUBLIC) && !state->package) {
644         access = ACCESS_PRIVATE; package = current_filename;
645     } else if(!(flags&FLAG_PUBLIC) && state->package) {
646         access = ACCESS_PACKAGEINTERNAL; package = state->package;
647     } else if(state->package) {
648         access = ACCESS_PACKAGE; package = state->package;
649     } else {
650         syntaxerror("public classes only allowed inside a package");
651     }
652
653     if(registry_findclass(package, classname)) {
654         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
655     }
656    
657
658     /* build info struct */
659     int num_interfaces = (list_length(implements));
660     state->cls->info = classinfo_register(access, package, classname, num_interfaces);
661     state->cls->info->superclass = extends?extends:TYPE_OBJECT;
662     int pos = 0;
663     classinfo_list_t*l = implements;
664     for(l=implements;l;l=l->next) {
665         state->cls->info->interfaces[pos++] = l->classinfo;
666     }
667     
668     multiname_t*extends2 = sig2mname(extends);
669
670     MULTINAME(classname2,state->cls->info);
671
672     /*if(extends) {
673         state->cls_init = abc_getlocal_0(state->cls_init);
674         state->cls_init = abc_constructsuper(state->cls_init, 0);
675     }*/
676
677     state->cls->abc = abc_class_new(global->file, &classname2, extends2);
678     if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
679     if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
680     if(interface) {
681         state->cls->info->flags |= CLASS_INTERFACE;
682         abc_class_interface(state->cls->abc);
683     }
684
685     abc_class_protectedNS(state->cls->abc, classname);
686
687     for(mlist=implements;mlist;mlist=mlist->next) {
688         MULTINAME(m, mlist->classinfo);
689         abc_class_add_interface(state->cls->abc, &m);
690     }
691
692     /* now write the construction code for this class */
693     int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
694
695     abc_method_body_t*m = global->init->method->body;
696     __ getglobalscope(m);
697     classinfo_t*s = extends;
698
699     int count=0;
700     
701     while(s) {
702         //TODO: take a look at the current scope stack, maybe 
703         //      we can re-use something
704         s = s->superclass;
705         if(!s) 
706         break;
707        
708         multiname_t*s2 = sig2mname(s);
709         __ getlex2(m, s2);
710         multiname_destroy(s2);
711
712         __ pushscope(m); count++;
713         m->code = m->code->prev->prev; // invert
714     }
715     /* continue appending after last op end */
716     while(m->code && m->code->next) m->code = m->code->next; 
717
718     /* TODO: if this is one of *our* classes, we can also 
719              do a getglobalscope/getslot <nr> (which references
720              the init function's slots) */
721     if(extends2) {
722         __ getlex2(m, extends2);
723         __ dup(m);
724         /* notice: we get a Verify Error #1107 if the top elemnt on the scope
725            stack is not the superclass */
726         __ pushscope(m);count++;
727     } else {
728         __ pushnull(m);
729         /* notice: we get a verify error #1107 if the top element on the scope 
730            stack is not the global object */
731         __ getlocal_0(m);
732         __ pushscope(m);count++;
733     }
734     __ newclass(m,state->cls->abc);
735     while(count--) {
736         __ popscope(m);
737     }
738     __ setslot(m, slotindex);
739
740     /* flash.display.MovieClip handling */
741     if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
742         if(state->package && state->package[0]) {
743             globalclass = concat3(state->package, ".", classname);
744         } else {
745             globalclass = strdup(classname);
746         }
747     }
748     multiname_destroy(extends2);
749 }
750
751 static void endclass()
752 {
753     if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
754         code_t*c = 0;
755         c = abc_getlocal_0(c);
756         c = abc_constructsuper(c, 0);
757         state->cls->init = code_append(state->cls->init, c);
758     }
759     if(!state->method->late_binding) {
760         // class initialization code uses late binding
761         code_t*c = 0;
762         c = abc_getlocal_0(c);
763         c = abc_pushscope(c);
764         state->cls->static_init = code_append(c, state->cls->static_init);
765     }
766
767     if(state->cls->init) {
768         abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
769         m->body->code = wrap_function(0, state->cls->init, m->body->code);
770     }
771     if(state->cls->static_init) {
772         abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
773         m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
774     }
775
776     free(state->cls);state->cls=0;
777     free(state->method);state->method=0;
778     old_state();
779 }
780
781 void check_code_for_break(code_t*c)
782 {
783     while(c) {
784         if(c->opcode == OPCODE___BREAK__) {
785             char*name = string_cstr(c->data[0]);
786             syntaxerror("Unresolved \"break %s\"", name);
787         }
788         if(c->opcode == OPCODE___CONTINUE__) {
789             char*name = string_cstr(c->data[0]);
790             syntaxerror("Unresolved \"continue %s\"", name);
791         }
792         c=c->prev;
793     }
794 }
795
796
797 static void check_constant_against_type(classinfo_t*t, constant_t*c)
798 {
799 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
800    if(TYPE_IS_NUMBER(t)) {
801         xassert(c->type == CONSTANT_FLOAT
802              || c->type == CONSTANT_INT
803              || c->type == CONSTANT_UINT);
804    } else if(TYPE_IS_UINT(t)) {
805         xassert(c->type == CONSTANT_UINT ||
806                (c->type == CONSTANT_INT && c->i>0));
807    } else if(TYPE_IS_INT(t)) {
808         xassert(c->type == CONSTANT_INT);
809    } else if(TYPE_IS_BOOLEAN(t)) {
810         xassert(c->type == CONSTANT_TRUE
811              || c->type == CONSTANT_FALSE);
812    }
813 }
814
815
816 static int flags2access(int flags)
817 {
818     int access = 0;
819     if(flags&FLAG_PUBLIC)  {
820         if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
821             syntaxerror("invalid combination of access levels");
822         access = ACCESS_PACKAGE;
823     } else if(flags&FLAG_PRIVATE) {
824         if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
825             syntaxerror("invalid combination of access levels");
826         access = ACCESS_PRIVATE;
827     } else if(flags&FLAG_PROTECTED) {
828         if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL)) 
829             syntaxerror("invalid combination of access levels");
830         access = ACCESS_PROTECTED;
831     } else {
832         access = ACCESS_PACKAGEINTERNAL;
833     }
834     return access;
835 }
836
837
838 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
839 {
840     memberinfo_t*minfo = 0;
841     if(!state->cls) {
842         //package method
843         minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
844         minfo->return_type = return_type;
845     } else if(getset != KW_GET && getset != KW_SET) {
846         //class method
847         if((minfo = registry_findmember(state->cls->info, name, 0))) {
848             if(minfo->parent == state->cls->info) {
849                 syntaxerror("class already contains a member/method called '%s'", name);
850             } else if(!minfo->parent) {
851                 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
852             } else {
853                 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
854                     syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
855             }
856         }
857         minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
858         minfo->return_type = return_type;
859         // getslot on a member slot only returns "undefined", so no need
860         // to actually store these
861         //state->minfo->slot = state->method->abc->method->trait->slot_id;
862     } else {
863         //class getter/setter
864         int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
865         classinfo_t*type=0;
866         if(getset == KW_GET)
867             type = return_type;
868         else if(params->list)
869             type = params->list->param->type;
870         // not sure wether to look into superclasses here, too
871         if((minfo=registry_findmember(state->cls->info, name, 0))) {
872             if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
873                 syntaxerror("class already contains a member or method called '%s'", name);
874             if(minfo->kind & gs)
875                 syntaxerror("getter/setter for '%s' already defined", name);
876             /* make a setter or getter into a getset */
877             minfo->kind |= gs;
878             if(!minfo->type) 
879                 minfo->type = type;
880             else
881                 if(type && minfo->type != type)
882                     syntaxerror("different type in getter and setter");
883         } else {
884             minfo = memberinfo_register(state->cls->info, name, gs);
885             minfo->type = type;
886         }
887         /* can't assign a slot as getter and setter might have different slots */
888         //minfo->slot = slot;
889     }
890     if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
891     if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
892     if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
893     if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
894     if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
895     if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
896     return minfo;
897 }
898
899 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
900                           params_t*params, classinfo_t*return_type)
901 {
902     if(state->method && state->method->info) {
903         syntaxerror("not able to start another method scope");
904     }
905     new_state();
906     global->variable_count = 0;
907     state->method = rfx_calloc(sizeof(methodstate_t));
908     state->method->has_super = 0;
909
910     if(state->cls) {
911         state->method->is_constructor = !strcmp(state->cls->info->name,name);
912         state->cls->has_constructor |= state->method->is_constructor;
913         
914         new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
915     } else {
916         state->method->is_global = 1;
917         state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
918
919         new_variable("globalscope", 0, 0);
920     }
921
922     /* state->vars is initialized by state_new */
923
924     param_list_t*p=0;
925     for(p=params->list;p;p=p->next) {
926         new_variable(p->param->name, p->param->type, 0);
927     }
928     if(state->method->is_constructor)
929         name = "__as3_constructor__";
930     state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
931 }
932
933 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
934                           params_t*params, classinfo_t*return_type, code_t*body)
935 {
936     abc_method_t*f = 0;
937
938     multiname_t*type2 = sig2mname(return_type);
939     int slot = 0;
940     if(state->method->is_constructor) {
941         f = abc_class_getconstructor(state->cls->abc, type2);
942     } else if(!state->method->is_global) {
943         namespace_t mname_ns = flags2namespace(flags, "");
944         multiname_t mname = {QNAME, &mname_ns, 0, name};
945
946         if(flags&FLAG_STATIC)
947             f = abc_class_staticmethod(state->cls->abc, type2, &mname);
948         else
949             f = abc_class_method(state->cls->abc, type2, &mname);
950         slot = f->trait->slot_id;
951     } else {
952         namespace_t mname_ns = flags2namespace(flags, state->package);
953         multiname_t mname = {QNAME, &mname_ns, 0, name};
954
955         f = abc_method_new(global->file, type2, 1);
956         trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
957         //abc_code_t*c = global->init->method->body->code;
958     }
959     //flash doesn't seem to allow us to access function slots
960     //state->method->info->slot = slot;
961
962     if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
963     if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
964     if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
965     if(params->varargs) f->flags |= METHOD_NEED_REST;
966
967     char opt=0;
968     param_list_t*p=0;
969     for(p=params->list;p;p=p->next) {
970         if(params->varargs && !p->next) {
971             break; //varargs: omit last parameter in function signature
972         }
973         multiname_t*m = sig2mname(p->param->type);
974         list_append(f->parameters, m);
975         if(p->param->value) {
976             check_constant_against_type(p->param->type, p->param->value);
977             opt=1;list_append(f->optional_parameters, p->param->value);
978         } else if(opt) {
979             syntaxerror("non-optional parameter not allowed after optional parameters");
980         }
981     }
982     check_code_for_break(body);
983
984     if(f->body) {
985         f->body->code = body;
986         f->body->exceptions = state->method->exceptions;
987     } else { //interface
988         if(body)
989             syntaxerror("interface methods can't have a method body");
990     }
991        
992     free(state->method);state->method=0;
993     old_state();
994 }
995
996
997
998 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
999 {
1000     return 1; // FIXME
1001 }
1002
1003 void breakjumpsto(code_t*c, char*name, code_t*jump) 
1004 {
1005     while(c) {
1006         if(c->opcode == OPCODE___BREAK__) {
1007             string_t*name2 = c->data[0];
1008             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1009                 c->opcode = OPCODE_JUMP;
1010                 c->branch = jump;
1011             }
1012         }
1013         c=c->prev;
1014     }
1015 }
1016 void continuejumpsto(code_t*c, char*name, code_t*jump) 
1017 {
1018     while(c) {
1019         if(c->opcode == OPCODE___CONTINUE__) {
1020             string_t*name2 = c->data[0];
1021             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1022                 c->opcode = OPCODE_JUMP;
1023                 c->branch = jump;
1024             }
1025         }
1026         c = c->prev;
1027     }
1028 }
1029
1030 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1031 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1032 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1033
1034 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1035 {
1036     if(!type1 || !type2) 
1037         return registry_getanytype();
1038     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1039         return registry_getanytype();
1040
1041     if(op=='+') {
1042         if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1043             return TYPE_NUMBER;
1044         } else {
1045             return TYPE_ANY;
1046         }
1047     }
1048
1049     if(type1 == type2)
1050         return type1;
1051     return registry_getanytype();
1052 }
1053 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1054 {
1055     if(from==to)
1056         return c;
1057     if(!to) {
1058         return abc_coerce_a(c);
1059     }
1060     MULTINAME(m, to);
1061     if(!from) {
1062         // cast an "any" type to a specific type. subject to
1063         // runtime exceptions
1064         return abc_coerce2(c, &m);
1065     }
1066     
1067     if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1068        (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1069         // allow conversion between number types
1070         return abc_coerce2(c, &m);
1071     }
1072     //printf("%s.%s\n", from.package, from.name);
1073     //printf("%s.%s\n", to.package, to.name);
1074
1075     classinfo_t*supertype = from;
1076     while(supertype) {
1077         if(supertype == to) {
1078              // target type is one of from's superclasses
1079              return abc_coerce2(c, &m);
1080         }
1081         int t=0;
1082         while(supertype->interfaces[t]) {
1083             if(supertype->interfaces[t]==to) {
1084                 // target type is one of from's interfaces
1085                 return abc_coerce2(c, &m);
1086             }
1087             t++;
1088         }
1089         supertype = supertype->superclass;
1090     }
1091     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1092         return c;
1093     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1094         return c;
1095     syntaxerror("can't convert type %s to %s", from->name, to->name);
1096 }
1097
1098 code_t*defaultvalue(code_t*c, classinfo_t*type)
1099 {
1100     if(TYPE_IS_INT(type)) {
1101        c = abc_pushbyte(c, 0);
1102     } else if(TYPE_IS_UINT(type)) {
1103        c = abc_pushuint(c, 0);
1104     } else if(TYPE_IS_FLOAT(type)) {
1105        c = abc_pushnan(c);
1106     } else if(TYPE_IS_BOOLEAN(type)) {
1107        c = abc_pushfalse(c);
1108     } else if(!type) {
1109        //c = abc_pushundefined(c);
1110     } else {
1111        c = abc_pushnull(c);
1112        MULTINAME(m, type);
1113        c = abc_coerce2(c, &m);
1114     }
1115     return c;
1116 }
1117
1118 char is_pushundefined(code_t*c)
1119 {
1120     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1121 }
1122
1123 void parserassert(int b)
1124 {
1125     if(!b) syntaxerror("internal error: assertion failed");
1126 }
1127
1128 static classinfo_t* find_class(char*name)
1129 {
1130     classinfo_t*c=0;
1131
1132     c = registry_findclass(state->package, name);
1133     if(c) return c;
1134
1135     /* try explicit imports */
1136     dictentry_t* e = dict_get_slot(state->imports, name);
1137     if(c) return c;
1138     while(e) {
1139         if(!strcmp(e->key, name)) {
1140             c = (classinfo_t*)e->data;
1141             if(c) return c;
1142         }
1143         e = e->next;
1144     }
1145
1146     /* try package.* imports */
1147     import_list_t*l = state->wildcard_imports;
1148     while(l) {
1149         //printf("does package %s contain a class %s?\n", l->import->package, name);
1150         c = registry_findclass(l->import->package, name);
1151         if(c) return c;
1152         l = l->next;
1153     }
1154
1155     /* try global package */
1156     c = registry_findclass("", name);
1157     if(c) return c;
1158    
1159     /* try local "filename" package */
1160     c = registry_findclass(current_filename, name);
1161     if(c) return c;
1162
1163     return 0;
1164 }
1165
1166 static char is_getlocal(code_t*c)
1167 {
1168     if(!c || c->prev || c->next)
1169         return 0;
1170     return(c->opcode == OPCODE_GETLOCAL
1171         || c->opcode == OPCODE_GETLOCAL_0
1172         || c->opcode == OPCODE_GETLOCAL_1
1173         || c->opcode == OPCODE_GETLOCAL_2
1174         || c->opcode == OPCODE_GETLOCAL_3);
1175 }
1176 static int getlocalnr(code_t*c)
1177 {
1178     if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1179     else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1180     else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1181     else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1182     else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1183     else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1184 }
1185
1186 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1187 {
1188     /* converts this:
1189
1190        [prefix code] [read instruction]
1191
1192        to this:
1193
1194        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1195     */
1196     
1197     if(in && in->opcode == OPCODE_COERCE_A) {
1198         in = code_cutlast(in);
1199     }
1200     if(in->next)
1201         syntaxerror("internal error");
1202
1203     /* chop off read instruction */
1204     code_t*prefix = in;
1205     code_t*r = in;
1206     if(r->prev) {
1207         prefix = r->prev;r->prev = 0;
1208         prefix->next=0;
1209     } else {
1210         prefix = 0;
1211     }
1212
1213     char use_temp_var = readbefore;
1214
1215     /* generate the write instruction, and maybe append a dup to the prefix code */
1216     code_t* write = abc_nop(0);
1217     if(r->opcode == OPCODE_GETPROPERTY) {
1218         write->opcode = OPCODE_SETPROPERTY;
1219         multiname_t*m = (multiname_t*)r->data[0];
1220         write->data[0] = multiname_clone(m);
1221         if(m->type == QNAME || m->type == MULTINAME) {
1222             if(!justassign) {
1223                 prefix = abc_dup(prefix); // we need the object, too
1224             }
1225             use_temp_var = 1;
1226         } else if(m->type == MULTINAMEL) {
1227             if(!justassign) {
1228                 /* dupping two values on the stack requires 5 operations and one register- 
1229                    couldn't adobe just have given us a dup2? */
1230                 int temp = gettempvar();
1231                 prefix = abc_setlocal(prefix, temp);
1232                 prefix = abc_dup(prefix);
1233                 prefix = abc_getlocal(prefix, temp);
1234                 prefix = abc_swap(prefix);
1235                 prefix = abc_getlocal(prefix, temp);
1236                 if(!use_temp_var);
1237                     prefix = abc_kill(prefix, temp);
1238             }
1239             use_temp_var = 1;
1240         } else {
1241             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1242         }
1243     } else if(r->opcode == OPCODE_GETSLOT) {
1244         write->opcode = OPCODE_SETSLOT;
1245         write->data[0] = r->data[0];
1246         if(!justassign) {
1247             prefix = abc_dup(prefix); // we need the object, too
1248         }
1249         use_temp_var = 1;
1250     } else if(r->opcode == OPCODE_GETLOCAL) { 
1251         write->opcode = OPCODE_SETLOCAL;
1252         write->data[0] = r->data[0];
1253     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1254         write->opcode = OPCODE_SETLOCAL_0;
1255     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1256         write->opcode = OPCODE_SETLOCAL_1;
1257     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1258         write->opcode = OPCODE_SETLOCAL_2;
1259     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1260         write->opcode = OPCODE_SETLOCAL_3;
1261     } else {
1262         code_dump(r, 0, 0, "", stdout);
1263         syntaxerror("illegal lvalue: can't assign a value to this expression");
1264     }
1265     code_t* c = 0;
1266     
1267     int temp = -1;
1268     if(!justassign) {
1269         if(use_temp_var) {
1270             /* with getproperty/getslot, we have to be extra careful not
1271                to execute the read code twice, as it might have side-effects
1272                (e.g. if the property is in fact a setter/getter combination)
1273
1274                So read the value, modify it, and write it again,
1275                using prefix only once and making sure (by using a temporary
1276                register) that the return value is what we just wrote */
1277             temp = gettempvar();
1278             c = code_append(c, prefix);
1279             c = code_append(c, r);
1280             if(readbefore) {
1281                 c = abc_dup(c);
1282                 c = abc_setlocal(c, temp);
1283             }
1284             c = code_append(c, middlepart);
1285             if(!readbefore) {
1286                 c = abc_dup(c);
1287                 c = abc_setlocal(c, temp);
1288             }
1289             c = code_append(c, write);
1290             c = abc_getlocal(c, temp);
1291             c = abc_kill(c, temp);
1292         } else {
1293             /* if we're allowed to execute the read code twice *and*
1294                the middlepart doesn't modify the code, things are easier.
1295             */
1296             code_t* r2 = code_dup(r);
1297             //c = code_append(c, prefix);
1298             parserassert(!prefix);
1299             c = code_append(c, r);
1300             c = code_append(c, middlepart);
1301             c = code_append(c, write);
1302             c = code_append(c, r2);
1303         }
1304     } else {
1305         /* even smaller version: overwrite the value without reading
1306            it out first */
1307         if(!use_temp_var) {
1308             if(prefix) {
1309                 c = code_append(c, prefix);
1310                 c = abc_dup(c);
1311             }
1312             c = code_append(c, middlepart);
1313             c = code_append(c, write);
1314             c = code_append(c, r);
1315         } else {
1316             temp = gettempvar();
1317             if(prefix) {
1318                 c = code_append(c, prefix);
1319             }
1320             c = code_append(c, middlepart);
1321             c = abc_dup(c);
1322             c = abc_setlocal(c, temp);
1323             c = code_append(c, write);
1324             c = abc_getlocal(c, temp);
1325             c = abc_kill(c, temp);
1326         }
1327     }
1328
1329     return c;
1330 }
1331
1332
1333 %}
1334
1335
1336 %%
1337
1338 /* ------------ code blocks / statements ---------------- */
1339
1340 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1341
1342 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST 
1343 PROGRAM_CODE_LIST: PROGRAM_CODE 
1344                  | PROGRAM_CODE_LIST PROGRAM_CODE
1345
1346 PROGRAM_CODE: PACKAGE_DECLARATION 
1347             | INTERFACE_DECLARATION 
1348             | CLASS_DECLARATION
1349             | FUNCTION_DECLARATION
1350             | SLOT_DECLARATION
1351             | PACKAGE_INITCODE
1352             | ';'
1353
1354 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1355 INPACKAGE_CODE_LIST: INPACKAGE_CODE 
1356                    | INPACKAGE_CODE_LIST INPACKAGE_CODE
1357
1358 INPACKAGE_CODE: INTERFACE_DECLARATION 
1359               | CLASS_DECLARATION
1360               | FUNCTION_DECLARATION
1361               | SLOT_DECLARATION
1362               | PACKAGE_INITCODE
1363               | ';'
1364
1365 MAYBECODE: CODE {$$=$1;}
1366 MAYBECODE: {$$=code_new();}
1367
1368 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1369 CODE: CODEPIECE {$$=$1;}
1370
1371 // code which also may appear outside a method
1372 CODE_STATEMENT: IMPORT 
1373 CODE_STATEMENT: VOIDEXPRESSION 
1374 CODE_STATEMENT: FOR 
1375 CODE_STATEMENT: FOR_IN 
1376 CODE_STATEMENT: WHILE 
1377 CODE_STATEMENT: DO_WHILE 
1378 CODE_STATEMENT: SWITCH 
1379 CODE_STATEMENT: IF
1380 CODE_STATEMENT: WITH
1381 CODE_STATEMENT: TRY
1382
1383 // code which may appear anywhere
1384 CODEPIECE: ';' {$$=0;}
1385 CODEPIECE: VARIABLE_DECLARATION
1386 CODEPIECE: CODE_STATEMENT
1387 CODEPIECE: BREAK
1388 CODEPIECE: CONTINUE
1389 CODEPIECE: RETURN
1390 CODEPIECE: THROW
1391
1392 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1393 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=0;}
1394
1395 CODEBLOCK :  '{' CODE '}' {$$=$2;}
1396 CODEBLOCK :  '{' '}'      {$$=0;}
1397 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1398 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1399
1400 /* ------------ package init code ------------------- */
1401
1402 PACKAGE_INITCODE: CODE_STATEMENT {
1403     if($1) warning("code ignored");
1404 }
1405
1406 /* ------------ variables --------------------------- */
1407
1408 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1409                 |                {$$.c=abc_pushundefined(0);
1410                                   $$.t=TYPE_ANY;
1411                                  }
1412
1413 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1414 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1415
1416 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1417 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1418
1419 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1420 {
1421     if(variable_exists($1))
1422         syntaxerror("Variable %s already defined", $1);
1423    
1424     if(!is_subtype_of($3.t, $2)) {
1425         syntaxerror("Can't convert %s to %s", $3.t->name, 
1426                                               $2->name);
1427     }
1428
1429     int index = new_variable($1, $2, 1);
1430     
1431     if($2) {
1432         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1433             $$ = $3.c;
1434             $$ = converttype($$, $3.t, $2);
1435             $$ = abc_setlocal($$, index);
1436         } else {
1437             $$ = defaultvalue(0, $2);
1438             $$ = abc_setlocal($$, index);
1439         }
1440     } else {
1441         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1442             $$ = $3.c;
1443             $$ = abc_coerce_a($$);
1444             $$ = abc_setlocal($$, index);
1445         } else {
1446             $$ = code_new();
1447         }
1448     }
1449     
1450     /* that's the default for a local register, anyway
1451         else {
1452         state->method->initcode = abc_pushundefined(state->method->initcode);
1453         state->method->initcode = abc_setlocal(state->method->initcode, index);
1454     }*/
1455     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1456 }
1457
1458 /* ------------ control flow ------------------------- */
1459
1460 MAYBEELSE:  %prec below_else {$$ = code_new();}
1461 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1462 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1463
1464 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1465      
1466     $$ = code_new();
1467     $$ = code_append($$, $4.c);
1468     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1469    
1470     $$ = code_append($$, $6);
1471     if($7) {
1472         myjmp = $$ = abc_jump($$, 0);
1473     }
1474     myif->branch = $$ = abc_nop($$);
1475     if($7) {
1476         $$ = code_append($$, $7);
1477         myjmp->branch = $$ = abc_nop($$);
1478     }
1479     $$ = var_block($$);
1480     old_state();
1481 }
1482
1483 FOR_INIT : {$$=code_new();}
1484 FOR_INIT : VARIABLE_DECLARATION
1485 FOR_INIT : VOIDEXPRESSION
1486 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1487     $$=$2;new_variable($2,$3,1);
1488 }
1489 FOR_IN_INIT : T_IDENTIFIER {
1490     $$=$1;
1491 }
1492
1493 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1494 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1495
1496 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1497     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1498     $$ = code_new();
1499     $$ = code_append($$, $2);
1500     code_t*loopstart = $$ = abc_label($$);
1501     $$ = code_append($$, $4.c);
1502     code_t*myif = $$ = abc_iffalse($$, 0);
1503     $$ = code_append($$, $8);
1504     code_t*cont = $$ = abc_nop($$);
1505     $$ = code_append($$, $6);
1506     $$ = abc_jump($$, loopstart);
1507     code_t*out = $$ = abc_nop($$);
1508     breakjumpsto($$, $1.name, out);
1509     continuejumpsto($$, $1.name, cont);
1510     myif->branch = out;
1511
1512     $$ = var_block($$);
1513     old_state();
1514 }
1515
1516 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1517     variable_t*var = find_variable($2);
1518     char*tmp1name = concat2($2, "__tmp1__");
1519     int it = new_variable(tmp1name, TYPE_INT, 0);
1520     char*tmp2name = concat2($2, "__array__");
1521     int array = new_variable(tmp1name, 0, 0);
1522
1523     $$ = code_new();
1524     $$ = code_append($$, $4.c);
1525     $$ = abc_coerce_a($$);
1526     $$ = abc_setlocal($$, array);
1527     $$ = abc_pushbyte($$, 0);
1528     $$ = abc_setlocal($$, it);
1529
1530     code_t*loopstart = $$ = abc_label($$);
1531     
1532     $$ = abc_hasnext2($$, array, it);
1533     code_t*myif = $$ = abc_iffalse($$, 0);
1534     $$ = abc_getlocal($$, array);
1535     $$ = abc_getlocal($$, it);
1536     if(!$1.each)
1537         $$ = abc_nextname($$);
1538     else
1539         $$ = abc_nextvalue($$);
1540     $$ = converttype($$, 0, var->type);
1541     $$ = abc_setlocal($$, var->index);
1542
1543     $$ = code_append($$, $6);
1544     $$ = abc_jump($$, loopstart);
1545     
1546     code_t*out = $$ = abc_nop($$);
1547     breakjumpsto($$, $1.name, out);
1548     continuejumpsto($$, $1.name, loopstart);
1549     
1550     myif->branch = out;
1551
1552     $$ = var_block($$);
1553     old_state();
1554
1555     free(tmp1name);
1556     free(tmp2name);
1557 }
1558
1559 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1560
1561     $$ = code_new();
1562
1563     code_t*myjmp = $$ = abc_jump($$, 0);
1564     code_t*loopstart = $$ = abc_label($$);
1565     $$ = code_append($$, $6);
1566     code_t*cont = $$ = abc_nop($$);
1567     myjmp->branch = cont;
1568     $$ = code_append($$, $4.c);
1569     $$ = abc_iftrue($$, loopstart);
1570     code_t*out = $$ = abc_nop($$);
1571     breakjumpsto($$, $1, out);
1572     continuejumpsto($$, $1, cont);
1573
1574     $$ = var_block($$);
1575     old_state();
1576 }
1577
1578 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1579     $$ = code_new();
1580     code_t*loopstart = $$ = abc_label($$);
1581     $$ = code_append($$, $3);
1582     code_t*cont = $$ = abc_nop($$);
1583     $$ = code_append($$, $6.c);
1584     $$ = abc_iftrue($$, loopstart);
1585     code_t*out = $$ = abc_nop($$);
1586     breakjumpsto($$, $1, out);
1587     continuejumpsto($$, $1, cont);
1588     
1589     $$ = var_block($$);
1590     old_state();
1591 }
1592
1593 BREAK : "break" %prec prec_none {
1594     $$ = abc___break__(0, "");
1595 }
1596 BREAK : "break" T_IDENTIFIER {
1597     $$ = abc___break__(0, $2);
1598 }
1599 CONTINUE : "continue" %prec prec_none {
1600     $$ = abc___continue__(0, "");
1601 }
1602 CONTINUE : "continue" T_IDENTIFIER {
1603     $$ = abc___continue__(0, $2);
1604 }
1605
1606 MAYBE_CASE_LIST :           {$$=0;}
1607 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1608 MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
1609 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1610 CASE_LIST: CASE             {$$=$1}
1611 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
1612
1613 CASE: "case" E ':' MAYBECODE {
1614     $$ = abc_dup(0);
1615     $$ = code_append($$, $2.c);
1616     code_t*j = $$ = abc_ifne($$, 0);
1617     $$ = code_append($$, $4);
1618     if($$->opcode != OPCODE___BREAK__) {
1619         $$ = abc___fallthrough__($$, "");
1620     }
1621     code_t*e = $$ = abc_nop($$);
1622     j->branch = e;
1623 }
1624 DEFAULT: "default" ':' MAYBECODE {
1625     $$ = $3;
1626 }
1627 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1628     $$=$4.c;
1629     $$ = code_append($$, $7);
1630     code_t*out = $$ = abc_pop($$);
1631     breakjumpsto($$, $1, out);
1632     
1633     code_t*c = $$,*lastblock=0;
1634     while(c) {
1635         if(c->opcode == OPCODE_IFNE) {
1636             if(!c->next) syntaxerror("internal error in fallthrough handling");
1637             lastblock=c->next;
1638         } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1639             if(lastblock) {
1640                 c->opcode = OPCODE_JUMP;
1641                 c->branch = lastblock;
1642             } else {
1643                 /* fall through end of switch */
1644                 c->opcode = OPCODE_NOP;
1645             }
1646         }
1647         c=c->prev;
1648     }
1649    
1650     $$ = var_block($$);
1651     old_state();
1652 }
1653
1654 /* ------------ try / catch /finally ---------------- */
1655
1656 FINALLY: "finally" '{' CODE '}'
1657 MAYBE_FINALLY: | FINALLY 
1658
1659 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);} 
1660         '{' CODE '}' {
1661     namespace_t name_ns = {ACCESS_PACKAGE, ""};
1662     multiname_t name = {QNAME, &name_ns, 0, $3};
1663     
1664     NEW(abc_exception_t, e)
1665     e->exc_type = sig2mname($4);
1666     e->var_name = multiname_clone(&name);
1667     $$ = e;
1668
1669     code_t*c = 0;
1670     int i = find_variable_safe($3)->index;
1671     e->target = c = abc_setlocal(0, i);
1672     c = code_append(c, $8);
1673     c = abc_kill(c, i);
1674
1675     c = var_block(c);
1676     old_state();
1677     
1678 }
1679
1680 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1681 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1682
1683 TRY : "try" '{' {new_state();} CODE '}' CATCH_LIST MAYBE_FINALLY {
1684     code_t*start = code_start($4);
1685     $$=$4;
1686
1687     code_t*out = abc_nop(0);
1688     code_t*jmp = $$ = abc_jump($$, out);
1689
1690     abc_exception_list_t*l = $6;
1691     while(l) {
1692         abc_exception_t*e = l->abc_exception;
1693         e->from = start;
1694         e->to = jmp;
1695         $$ = code_append($$, e->target);
1696         $$ = abc_jump($$, out);
1697         l = l->next;
1698     }
1699     $$ = code_append($$, out);
1700     jmp->branch = out;
1701         
1702     list_concat(state->method->exceptions, $6);
1703    
1704     $$ = var_block($$);
1705     old_state();
1706 }
1707
1708 /* ------------ throw ------------------------------- */
1709
1710 THROW : "throw" EXPRESSION {
1711     $$=$2.c;
1712     $$=abc_throw($$);
1713 }
1714 THROW : "throw" %prec prec_none {
1715     if(!state->exception_name)
1716         syntaxerror("re-throw only possible within a catch block");
1717     variable_t*v = find_variable(state->exception_name);
1718     $$=code_new();
1719     $$=abc_getlocal($$, v->index);
1720     $$=abc_throw($$);
1721 }
1722
1723 /* ------------ with -------------------------------- */
1724
1725 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1726      $$ = $3.c;
1727      $$ = abc_pushscope($$);
1728      $$ = code_append($$, $5);
1729      $$ = abc_popscope($$);
1730 }
1731
1732 /* ------------ packages and imports ---------------- */
1733
1734 X_IDENTIFIER: T_IDENTIFIER
1735             | "package" {$$="package";}
1736
1737 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1738 PACKAGE: X_IDENTIFIER             {$$=strdup($1);}
1739
1740 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1741 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1742
1743 IMPORT : "import" QNAME {
1744        classinfo_t*c = $2;
1745        if(!c) 
1746             syntaxerror("Couldn't import class\n");
1747        state_has_imports();
1748        dict_put(state->imports, c->name, c);
1749        $$=0;
1750 }
1751 IMPORT : "import" PACKAGE '.' '*' {
1752        NEW(import_t,i);
1753        i->package = $2;
1754        state_has_imports();
1755        list_append(state->wildcard_imports, i);
1756        $$=0;
1757 }
1758
1759 /* ------------ classes and interfaces (header) -------------- */
1760
1761 MAYBE_MODIFIERS : {$$=0;}
1762 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1763 MODIFIER_LIST : MODIFIER               {$$=$1;}
1764 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1765
1766 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1767          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1768          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1769          | KW_STATIC {$$=FLAG_STATIC;}
1770          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1771          | KW_FINAL {$$=FLAG_FINAL;}
1772          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1773          | KW_NATIVE {$$=FLAG_NATIVE;}
1774          | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1775
1776 EXTENDS : {$$=registry_getobjectclass();}
1777 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1778
1779 EXTENDS_LIST : {$$=list_new();}
1780 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1781
1782 IMPLEMENTS_LIST : {$$=list_new();}
1783 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1784
1785 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1786                               EXTENDS IMPLEMENTS_LIST 
1787                               '{' {startclass($1,$3,$4,$5, 0);} 
1788                               MAYBE_CLASS_BODY 
1789                               '}' {endclass();$$=0;}
1790
1791 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1792                               EXTENDS_LIST 
1793                               '{' {startclass($1,$3,0,$4,1);}
1794                               MAYBE_INTERFACE_BODY 
1795                               '}' {endclass();$$=0;}
1796
1797 /* ------------ classes and interfaces (body) -------------- */
1798
1799 MAYBE_CLASS_BODY : 
1800 MAYBE_CLASS_BODY : CLASS_BODY
1801 CLASS_BODY : CLASS_BODY_ITEM
1802 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1803 CLASS_BODY_ITEM : ';'
1804 CLASS_BODY_ITEM : SLOT_DECLARATION
1805 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1806
1807 CLASS_BODY_ITEM : CODE_STATEMENT {
1808     code_t*c = state->cls->static_init;
1809     c = code_append(c, $1);  
1810     state->cls->static_init = c;
1811 }
1812
1813 MAYBE_INTERFACE_BODY : 
1814 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1815 INTERFACE_BODY : IDECLARATION
1816 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1817 IDECLARATION : ';'
1818 IDECLARATION : "var" T_IDENTIFIER {
1819     syntaxerror("variable declarations not allowed in interfaces");
1820 }
1821 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1822     $1 |= FLAG_PUBLIC;
1823     if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
1824         syntaxerror("invalid method modifiers: interface methods always need to be public");
1825     }
1826     startfunction(0,$1,$3,$4,&$6,$8);
1827     endfunction(0,$1,$3,$4,&$6,$8, 0);
1828 }
1829
1830 /* ------------ classes and interfaces (body, slots ) ------- */
1831
1832 VARCONST: "var" | "const"
1833
1834 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1835     int flags = $1;
1836     memberinfo_t* info = state->cls?
1837             memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1838             memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1839
1840     info->type = $4;
1841     info->flags = flags;
1842
1843     /* slot name */
1844     namespace_t mname_ns = {flags2access(flags), ""};
1845     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1846   
1847     trait_list_t**traits;
1848     code_t**code;
1849     if(!state->cls) {
1850         // global variable
1851         traits = &global->init->traits;
1852         code = &global->init->method->body->code;
1853     } else if(flags&FLAG_STATIC) {
1854         // static variable
1855         traits = &state->cls->abc->static_traits;
1856         code = &state->cls->static_init;
1857     } else {
1858         // instance variable
1859         traits = &state->cls->abc->traits;
1860         code = &state->cls->init;
1861     }
1862     
1863     trait_t*t=0;
1864     if($4) {
1865         MULTINAME(m, $4);
1866         t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1867     } else {
1868         t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1869     }
1870     info->slot = t->slot_id;
1871     
1872     /* initalization code (if needed) */
1873     code_t*c = 0;
1874     if($5.c && !is_pushundefined($5.c)) {
1875         c = abc_getlocal_0(c);
1876         c = code_append(c, $5.c);
1877         c = converttype(c, $5.t, $4);
1878         c = abc_setslot(c, t->slot_id);
1879     }
1880
1881     *code = code_append(*code, c);
1882
1883     if($2==KW_CONST) {
1884         t->kind= TRAIT_CONST;
1885     }
1886
1887     $$=0;
1888 }
1889
1890 /* ------------ constants -------------------------------------- */
1891
1892 MAYBESTATICCONSTANT: {$$=0;}
1893 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1894
1895 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1896 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1897 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1898 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1899 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1900 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1901 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1902 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1903 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1904
1905 /* ------------ classes and interfaces (body, functions) ------- */
1906
1907 // non-vararg version
1908 MAYBE_PARAM_LIST: {
1909     memset(&$$,0,sizeof($$));
1910 }
1911 MAYBE_PARAM_LIST: PARAM_LIST {
1912     $$=$1;
1913 }
1914
1915 // vararg version
1916 MAYBE_PARAM_LIST: "..." PARAM {
1917     memset(&$$,0,sizeof($$));
1918     $$.varargs=1;
1919     list_append($$.list, $2);
1920 }
1921 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1922     $$ =$1;
1923     $$.varargs=1;
1924     list_append($$.list, $4);
1925 }
1926
1927 // non empty
1928 PARAM_LIST: PARAM_LIST ',' PARAM {
1929     $$ = $1;
1930     list_append($$.list, $3);
1931 }
1932 PARAM_LIST: PARAM {
1933     memset(&$$,0,sizeof($$));
1934     list_append($$.list, $1);
1935 }
1936
1937 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1938      $$ = malloc(sizeof(param_t));
1939      $$->name=$1;
1940      $$->type = $3;
1941      $$->value = $4;
1942 }
1943 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1944      $$ = malloc(sizeof(param_t));
1945      $$->name=$1;
1946      $$->type = TYPE_ANY;
1947      $$->value = $2;
1948 }
1949 GETSET : "get" {$$=$1;}
1950        | "set" {$$=$1;}
1951        |       {$$=0;}
1952
1953 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1954                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1955 {
1956     code_t*c = 0;
1957     if(state->method->late_binding) {
1958         c = abc_getlocal_0(c);
1959         c = abc_pushscope(c);
1960     }
1961     if(state->method->is_constructor && !state->method->has_super) {
1962         // call default constructor
1963         c = abc_getlocal_0(c);
1964         c = abc_constructsuper(c, 0);
1965     }
1966     c = wrap_function(c, 0, $11);
1967     endfunction(0,$1,$3,$4,&$6,$8,c);
1968     $$=0;
1969 }
1970
1971 /* ------------- package + class ids --------------- */
1972
1973 CLASS: T_IDENTIFIER {
1974
1975     /* try current package */
1976     $$ = find_class($1);
1977     if(!$$) syntaxerror("Could not find class %s\n", $1);
1978 }
1979
1980 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1981     $$ = registry_findclass($1, $3);
1982     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1983     free($1);$1=0;
1984 }
1985
1986 QNAME: PACKAGEANDCLASS
1987      | CLASS
1988
1989 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1990 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1991
1992 TYPE : QNAME      {$$=$1;}
1993      | '*'        {$$=registry_getanytype();}
1994      | "void"     {$$=registry_getanytype();}
1995     /*
1996      |  "String"  {$$=registry_getstringclass();}
1997      |  "int"     {$$=registry_getintclass();}
1998      |  "uint"    {$$=registry_getuintclass();}
1999      |  "Boolean" {$$=registry_getbooleanclass();}
2000      |  "Number"  {$$=registry_getnumberclass();}
2001     */
2002
2003 MAYBETYPE: ':' TYPE {$$=$2;}
2004 MAYBETYPE:          {$$=0;}
2005
2006 /* ----------function calls, delete, constructor calls ------ */
2007
2008 MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.len=0;}
2009 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
2010
2011 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2012 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2013 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.len=1;
2014                                                   $$.cc = $1.c;
2015                                                  }
2016 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2017                                                   $$.len= $1.len+1;
2018                                                   $$.cc = code_append($1.cc, $3.c);
2019                                                   }
2020
2021 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2022     MULTINAME(m, $2);
2023     $$.c = code_new();
2024
2025     if($2->slot) {
2026         $$.c = abc_getglobalscope($$.c);
2027         $$.c = abc_getslot($$.c, $2->slot);
2028     } else {
2029         $$.c = abc_findpropstrict2($$.c, &m);
2030     }
2031
2032     $$.c = code_append($$.c, $3.cc);
2033
2034     if($2->slot)
2035         $$.c = abc_construct($$.c, $3.len);
2036     else
2037         $$.c = abc_constructprop2($$.c, &m, $3.len);
2038     $$.t = $2;
2039 }
2040
2041 /* TODO: use abc_call (for calling local variables),
2042          abc_callstatic (for calling own methods) 
2043          call (for closures)
2044 */
2045 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2046     
2047     $$.c = $1.c;
2048     if($$.c->opcode == OPCODE_COERCE_A) {
2049         $$.c = code_cutlast($$.c);
2050     }
2051     code_t*paramcode = $3.cc;
2052
2053     $$.t = TYPE_ANY;
2054     if($$.c->opcode == OPCODE_GETPROPERTY) {
2055         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2056         $$.c = code_cutlast($$.c);
2057         $$.c = code_append($$.c, paramcode);
2058         $$.c = abc_callproperty2($$.c, name, $3.len);
2059         multiname_destroy(name);
2060     } else if($$.c->opcode == OPCODE_GETSLOT) {
2061         int slot = (int)(ptroff_t)$$.c->data[0];
2062         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2063         if(t->kind!=TRAIT_METHOD) {
2064             //ok: flash allows to assign closures to members.
2065         }
2066         multiname_t*name = t->name;
2067         $$.c = code_cutlast($$.c);
2068         $$.c = code_append($$.c, paramcode);
2069         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2070         $$.c = abc_callproperty2($$.c, name, $3.len);
2071     } else if($$.c->opcode == OPCODE_GETSUPER) {
2072         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2073         $$.c = code_cutlast($$.c);
2074         $$.c = code_append($$.c, paramcode);
2075         $$.c = abc_callsuper2($$.c, name, $3.len);
2076         multiname_destroy(name);
2077     } else {
2078         $$.c = abc_getlocal_0($$.c);
2079         $$.c = code_append($$.c, paramcode);
2080         $$.c = abc_call($$.c, $3.len);
2081     }
2082    
2083     memberinfo_t*f = 0;
2084    
2085     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2086         $$.t = $1.t->function->return_type;
2087     } else {
2088         $$.c = abc_coerce_a($$.c);
2089         $$.t = TYPE_ANY;
2090     }
2091
2092 }
2093 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2094     if(!state->cls) syntaxerror("super() not allowed outside of a class");
2095     if(!state->method) syntaxerror("super() not allowed outside of a function");
2096     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2097
2098     $$.c = code_new();
2099     $$.c = abc_getlocal_0($$.c);
2100
2101     $$.c = code_append($$.c, $3.cc);
2102     /*
2103     this is dependent on the control path, check this somewhere else
2104     if(state->method->has_super)
2105         syntaxerror("constructor may call super() only once");
2106     */
2107     state->method->has_super = 1;
2108     $$.c = abc_constructsuper($$.c, $3.len);
2109     $$.c = abc_pushundefined($$.c);
2110     $$.t = TYPE_ANY;
2111 }
2112
2113 DELETE: "delete" E {
2114     $$.c = $2.c;
2115     if($$.c->opcode == OPCODE_COERCE_A) {
2116         $$.c = code_cutlast($$.c);
2117     }
2118     multiname_t*name = 0;
2119     if($$.c->opcode == OPCODE_GETPROPERTY) {
2120         $$.c->opcode = OPCODE_DELETEPROPERTY;
2121     } else if($$.c->opcode == OPCODE_GETSLOT) {
2122         int slot = (int)(ptroff_t)$$.c->data[0];
2123         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2124         $$.c = code_cutlast($$.c);
2125         $$.c = abc_deleteproperty2($$.c, name);
2126     } else {
2127         $$.c = abc_getlocal_0($$.c);
2128         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2129         $$.c = abc_deleteproperty2($$.c, &m);
2130     }
2131     $$.t = TYPE_BOOLEAN;
2132 }
2133
2134 RETURN: "return" %prec prec_none {
2135     $$ = abc_returnvoid(0);
2136 }
2137 RETURN: "return" EXPRESSION {
2138     $$ = $2.c;
2139     $$ = abc_returnvalue($$);
2140 }
2141
2142 // ----------------------- expression types -------------------------------------
2143
2144 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
2145 EXPRESSION : E                %prec below_minus {$$ = $1;}
2146 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2147     $$.c = $1.c;
2148     $$.c = cut_last_push($$.c);
2149     $$.c = code_append($$.c,$3.c);
2150     $$.t = $3.t;
2151 }
2152 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2153     $$=cut_last_push($1.c);
2154 }
2155
2156 // ----------------------- expression evaluation -------------------------------------
2157
2158 //V : CONSTANT                    {$$ = 0;}
2159 E : CONSTANT
2160 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2161 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2162 //V : NEW                         {$$ = $1.c;}
2163 E : NEW                         {$$ = $1;}
2164 //V : DELETE                      {$$ = $1.c;}
2165 E : DELETE                      {$$ = $1;}
2166
2167 E : T_REGEXP {
2168     $$.c = 0;
2169     namespace_t ns = {ACCESS_PACKAGE, ""};
2170     multiname_t m = {QNAME, &ns, 0, "RegExp"};
2171     if(!$1.options) {
2172         $$.c = abc_getlex2($$.c, &m);
2173         $$.c = abc_pushstring($$.c, $1.pattern);
2174         $$.c = abc_construct($$.c, 1);
2175     } else {
2176         $$.c = abc_getlex2($$.c, &m);
2177         $$.c = abc_pushstring($$.c, $1.pattern);
2178         $$.c = abc_pushstring($$.c, $1.options);
2179         $$.c = abc_construct($$.c, 2);
2180     }
2181     $$.t = TYPE_REGEXP;
2182 }
2183
2184 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2185                    //MULTINAME(m, registry_getintclass());
2186                    //$$.c = abc_coerce2($$.c, &m); // FIXME
2187                    $$.t = TYPE_INT;
2188                   }
2189 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2190                     $$.t = TYPE_INT;
2191                    }
2192 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2193                   $$.t = TYPE_INT;
2194                  }
2195 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2196                    $$.t = TYPE_UINT;
2197                   }
2198 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2199                     $$.t = TYPE_FLOAT;
2200                    }
2201 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2202                      $$.t = TYPE_STRING;
2203                     }
2204 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2205                     $$.t = TYPE_ANY;
2206                    }
2207 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2208                     $$.t = TYPE_BOOLEAN;
2209                    }
2210 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2211                      $$.t = TYPE_BOOLEAN;
2212                     }
2213 CONSTANT : "null" {$$.c = abc_pushnull(0);
2214                     $$.t = TYPE_NULL;
2215                    }
2216
2217 E : FUNCTIONCALL
2218 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2219              $$.t = TYPE_BOOLEAN;
2220             }
2221 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2222              $$.t = TYPE_BOOLEAN;
2223             }
2224 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2225               $$.t = TYPE_BOOLEAN;
2226              }
2227 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2228               $$.t = TYPE_BOOLEAN;
2229              }
2230 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2231               $$.t = TYPE_BOOLEAN;
2232              }
2233 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2234               $$.t = TYPE_BOOLEAN;
2235               }
2236 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2237               $$.t = TYPE_BOOLEAN;
2238              }
2239 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2240               $$.t = TYPE_BOOLEAN;
2241              }
2242
2243 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2244               $$.c = $1.c;
2245               $$.c = converttype($$.c, $1.t, $$.t);
2246               $$.c = abc_dup($$.c);
2247               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2248               $$.c = cut_last_push($$.c);
2249               $$.c = code_append($$.c,$3.c);
2250               $$.c = converttype($$.c, $3.t, $$.t);
2251               code_t*label = $$.c = abc_label($$.c);
2252               jmp->branch = label;
2253              }
2254 E : E "&&" E {
2255               $$.t = join_types($1.t, $3.t, 'A');
2256               /*printf("%08x:\n",$1.t);
2257               code_dump($1.c, 0, 0, "", stdout);
2258               printf("%08x:\n",$3.t);
2259               code_dump($3.c, 0, 0, "", stdout);
2260               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2261               $$.c = $1.c;
2262               $$.c = converttype($$.c, $1.t, $$.t);
2263               $$.c = abc_dup($$.c);
2264               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2265               $$.c = cut_last_push($$.c);
2266               $$.c = code_append($$.c,$3.c);
2267               $$.c = converttype($$.c, $3.t, $$.t);
2268               code_t*label = $$.c = abc_label($$.c);
2269               jmp->branch = label;              
2270              }
2271
2272 E : '!' E    {$$.c=$2.c;
2273               $$.c = abc_not($$.c);
2274               $$.t = TYPE_BOOLEAN;
2275              }
2276
2277 E : '~' E    {$$.c=$2.c;
2278               $$.c = abc_bitnot($$.c);
2279               $$.t = TYPE_INT;
2280              }
2281
2282 E : E '&' E {$$.c = code_append($1.c,$3.c);
2283              $$.c = abc_bitand($$.c);
2284              $$.t = TYPE_INT;
2285             }
2286
2287 E : E '^' E {$$.c = code_append($1.c,$3.c);
2288              $$.c = abc_bitxor($$.c);
2289              $$.t = TYPE_INT;
2290             }
2291
2292 E : E '|' E {$$.c = code_append($1.c,$3.c);
2293              $$.c = abc_bitor($$.c);
2294              $$.t = TYPE_INT;
2295             }
2296
2297 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2298              $$.c = abc_rshift($$.c);
2299              $$.t = TYPE_INT;
2300             }
2301 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2302              $$.c = abc_urshift($$.c);
2303              $$.t = TYPE_INT;
2304             }
2305 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2306              $$.c = abc_lshift($$.c);
2307              $$.t = TYPE_INT;
2308             }
2309
2310 E : E '/' E {$$.c = code_append($1.c,$3.c);
2311              $$.c = abc_divide($$.c);
2312              $$.t = TYPE_NUMBER;
2313             }
2314 E : E '%' E {$$.c = code_append($1.c,$3.c);
2315              $$.c = abc_modulo($$.c);
2316              $$.t = TYPE_NUMBER;
2317             }
2318 E : E '+' E {$$.c = code_append($1.c,$3.c);
2319              if(BOTH_INT($1.t, $3.t)) {
2320                 $$.c = abc_add_i($$.c);
2321                 $$.t = TYPE_INT;
2322              } else {
2323                 $$.c = abc_add($$.c);
2324                 $$.t = join_types($1.t,$3.t,'+');
2325              }
2326             }
2327 E : E '-' E {$$.c = code_append($1.c,$3.c);
2328              if(BOTH_INT($1.t,$3.t)) {
2329                 $$.c = abc_subtract_i($$.c);
2330                 $$.t = TYPE_INT;
2331              } else {
2332                 $$.c = abc_subtract($$.c);
2333                 $$.t = TYPE_NUMBER;
2334              }
2335             }
2336 E : E '*' E {$$.c = code_append($1.c,$3.c);
2337              if(BOTH_INT($1.t,$3.t)) {
2338                 $$.c = abc_multiply_i($$.c);
2339                 $$.t = TYPE_INT;
2340              } else {
2341                 $$.c = abc_multiply($$.c);
2342                 $$.t = TYPE_NUMBER;
2343              }
2344             }
2345
2346 E : E "in" E {$$.c = code_append($1.c,$3.c);
2347               $$.c = abc_in($$.c);
2348               $$.t = TYPE_BOOLEAN;
2349              }
2350
2351 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2352               if(use_astype && TYPE_IS_CLASS($3.t)) {
2353                 MULTINAME(m,$3.t->cls);
2354                 $$.c = abc_astype2($1.c, &m);
2355                 $$.t = $3.t->cls;
2356               } else {
2357                 $$.c = code_append($1.c, $3.c);
2358                 $$.c = abc_astypelate($$.c);
2359                 $$.t = TYPE_ANY;
2360               }
2361              }
2362
2363 E : E "instanceof" E 
2364              {$$.c = code_append($1.c, $3.c);
2365               $$.c = abc_instanceof($$.c);
2366               $$.t = TYPE_BOOLEAN;
2367              }
2368
2369 E : E "is" E {$$.c = code_append($1.c, $3.c);
2370               $$.c = abc_istypelate($$.c);
2371               $$.t = TYPE_BOOLEAN;
2372              }
2373
2374 E : "typeof" '(' E ')' {
2375               $$.c = $3.c;
2376               $$.c = abc_typeof($$.c);
2377               $$.t = TYPE_STRING;
2378              }
2379
2380 E : "void" E {
2381               $$.c = cut_last_push($2.c);
2382               $$.c = abc_pushundefined($$.c);
2383               $$.t = TYPE_ANY;
2384              }
2385
2386 E : "void" { $$.c = abc_pushundefined(0);
2387              $$.t = TYPE_ANY;
2388            }
2389
2390 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2391
2392 E : '-' E {
2393   $$=$2;
2394   if(IS_INT($2.t)) {
2395    $$.c=abc_negate_i($$.c);
2396    $$.t = TYPE_INT;
2397   } else {
2398    $$.c=abc_negate($$.c);
2399    $$.t = TYPE_NUMBER;
2400   }
2401 }
2402
2403 E : E '[' E ']' {
2404   $$.c = $1.c;
2405   $$.c = code_append($$.c, $3.c);
2406  
2407   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2408   $$.c = abc_getproperty2($$.c, &m);
2409   $$.t = 0; // array elements have unknown type
2410 }
2411
2412 E : '[' MAYBE_EXPRESSION_LIST ']' {
2413     $$.c = code_new();
2414     $$.c = code_append($$.c, $2.cc);
2415     $$.c = abc_newarray($$.c, $2.len);
2416     $$.t = registry_getarrayclass();
2417 }
2418
2419 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2420 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2421
2422 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2423     $$.cc = 0;
2424     $$.cc = code_append($$.cc, $1.c);
2425     $$.cc = code_append($$.cc, $3.c);
2426     $$.len = 2;
2427 }
2428 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2429     $$.cc = $1.cc;
2430     $$.len = $1.len+2;
2431     $$.cc = code_append($$.cc, $3.c);
2432     $$.cc = code_append($$.cc, $5.c);
2433 }
2434 //MAYBECOMMA: ','
2435 //MAYBECOMMA:
2436
2437 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2438     $$.c = code_new();
2439     $$.c = code_append($$.c, $2.cc);
2440     $$.c = abc_newobject($$.c, $2.len/2);
2441     $$.t = registry_getobjectclass();
2442 }
2443
2444 E : E "*=" E { 
2445                code_t*c = $3.c;
2446                if(BOTH_INT($1.t,$3.t)) {
2447                 c=abc_multiply_i(c);
2448                } else {
2449                 c=abc_multiply(c);
2450                }
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
2456 E : E "%=" E { 
2457                code_t*c = abc_modulo($3.c);
2458                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2459                $$.c = toreadwrite($1.c, c, 0, 0);
2460                $$.t = $1.t;
2461               }
2462 E : E "<<=" E { 
2463                code_t*c = abc_lshift($3.c);
2464                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2465                $$.c = toreadwrite($1.c, c, 0, 0);
2466                $$.t = $1.t;
2467               }
2468 E : E ">>=" E { 
2469                code_t*c = abc_rshift($3.c);
2470                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2471                $$.c = toreadwrite($1.c, c, 0, 0);
2472                $$.t = $1.t;
2473               }
2474 E : E ">>>=" E { 
2475                code_t*c = abc_urshift($3.c);
2476                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2477                $$.c = toreadwrite($1.c, c, 0, 0);
2478                $$.t = $1.t;
2479               }
2480 E : E "/=" E { 
2481                code_t*c = abc_divide($3.c);
2482                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2483                $$.c = toreadwrite($1.c, c, 0, 0);
2484                $$.t = $1.t;
2485               }
2486 E : E "|=" E { 
2487                code_t*c = abc_bitor($3.c);
2488                c=converttype(c, TYPE_INT, $1.t);
2489                $$.c = toreadwrite($1.c, c, 0, 0);
2490                $$.t = $1.t;
2491               }
2492 E : E "+=" E { 
2493                code_t*c = $3.c;
2494
2495                if(TYPE_IS_INT($1.t)) {
2496                 c=abc_add_i(c);
2497                } else {
2498                 c=abc_add(c);
2499                 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2500                }
2501                
2502                $$.c = toreadwrite($1.c, c, 0, 0);
2503                $$.t = $1.t;
2504               }
2505 E : E "-=" E { code_t*c = $3.c; 
2506                if(TYPE_IS_INT($1.t)) {
2507                 c=abc_subtract_i(c);
2508                } else {
2509                 c=abc_subtract(c);
2510                 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2511                }
2512                
2513                $$.c = toreadwrite($1.c, c, 0, 0);
2514                $$.t = $1.t;
2515              }
2516 E : E '=' E { code_t*c = 0;
2517               c = code_append(c, $3.c);
2518               c = converttype(c, $3.t, $1.t);
2519               $$.c = toreadwrite($1.c, c, 1, 0);
2520               $$.t = $1.t;
2521             }
2522
2523 E : E '?' E ':' E %prec below_assignment { 
2524               $$.t = join_types($3.t,$5.t,'?');
2525               $$.c = $1.c;
2526               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2527               $$.c = code_append($$.c, $3.c);
2528               $$.c = converttype($$.c, $3.t, $$.t);
2529               code_t*j2 = $$.c = abc_jump($$.c, 0);
2530               $$.c = j1->branch = abc_label($$.c);
2531               $$.c = code_append($$.c, $5.c);
2532               $$.c = converttype($$.c, $3.t, $$.t);
2533               $$.c = j2->branch = abc_label($$.c);
2534             }
2535
2536 E : E "++" { code_t*c = 0;
2537              classinfo_t*type = $1.t;
2538              if(is_getlocal($1.c) && TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t)) {
2539                  int nr = getlocalnr($1.c);
2540                  code_free($1.c);$1.c=0;
2541                  if(TYPE_IS_INT($1.t)) {
2542                     $$.c = abc_getlocal(0, nr);
2543                     $$.c = abc_inclocal_i($$.c, nr);
2544                  } else if(TYPE_IS_NUMBER($1.t)) {
2545                     $$.c = abc_getlocal(0, nr);
2546                     $$.c = abc_inclocal($$.c, nr);
2547                  } else syntaxerror("internal error");
2548              } else {
2549                  if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2550                      c=abc_increment_i(c);
2551                      type = TYPE_INT;
2552                  } else {
2553                      c=abc_increment(c);
2554                      type = TYPE_NUMBER;
2555                  }
2556                  c=converttype(c, type, $1.t);
2557                  $$.c = toreadwrite($1.c, c, 0, 1);
2558                  $$.t = $1.t;
2559              }
2560            }
2561
2562 // TODO: use inclocal, like with ++
2563 E : E "--" { code_t*c = 0;
2564              classinfo_t*type = $1.t;
2565              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2566                  c=abc_decrement_i(c);
2567                  type = TYPE_INT;
2568              } else {
2569                  c=abc_decrement(c);
2570                  type = TYPE_NUMBER;
2571              }
2572              c=converttype(c, type, $1.t);
2573              $$.c = toreadwrite($1.c, c, 0, 1);
2574              $$.t = $1.t;
2575             }
2576
2577 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2578              classinfo_t*type = $2.t;
2579              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2580                  c=abc_increment_i(c);
2581                  type = TYPE_INT;
2582              } else {
2583                  c=abc_increment(c);
2584                  type = TYPE_NUMBER;
2585              }
2586              c=converttype(c, type, $2.t);
2587              $$.c = toreadwrite($2.c, c, 0, 0);
2588              $$.t = $2.t;
2589            }
2590
2591 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2592              classinfo_t*type = $2.t;
2593              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2594                  c=abc_decrement_i(c);
2595                  type = TYPE_INT;
2596              } else {
2597                  c=abc_decrement(c);
2598                  type = TYPE_NUMBER;
2599              }
2600              c=converttype(c, type, $2.t);
2601              $$.c = toreadwrite($2.c, c, 0, 0);
2602              $$.t = $2.t;
2603            }
2604
2605 E : "super" '.' T_IDENTIFIER 
2606            { if(!state->cls->info)
2607                   syntaxerror("super keyword not allowed outside a class");
2608               classinfo_t*t = state->cls->info->superclass;
2609               if(!t) t = TYPE_OBJECT;
2610
2611               memberinfo_t*f = registry_findmember(t, $3, 1);
2612               namespace_t ns = flags2namespace(f->flags, "");
2613               MEMBER_MULTINAME(m, f, $3);
2614               $$.c = 0;
2615               $$.c = abc_getlocal_0($$.c);
2616               $$.c = abc_getsuper2($$.c, &m);
2617               $$.t = memberinfo_gettype(f);
2618            }
2619
2620 E : E '.' T_IDENTIFIER
2621             {$$.c = $1.c;
2622              classinfo_t*t = $1.t;
2623              char is_static = 0;
2624              if(TYPE_IS_CLASS(t) && t->cls) {
2625                  t = t->cls;
2626                  is_static = 1;
2627              }
2628              if(t) {
2629                  memberinfo_t*f = registry_findmember(t, $3, 1);
2630                  char noslot = 0;
2631                  if(f && !is_static != !(f->flags&FLAG_STATIC))
2632                     noslot=1;
2633                  if(f && f->slot && !noslot) {
2634                      $$.c = abc_getslot($$.c, f->slot);
2635                  } else {
2636                      MEMBER_MULTINAME(m, f, $3);
2637                      $$.c = abc_getproperty2($$.c, &m);
2638                  }
2639                  /* determine type */
2640                  $$.t = memberinfo_gettype(f);
2641                  if(!$$.t)
2642                     $$.c = abc_coerce_a($$.c);
2643              } else {
2644                  /* when resolving a property on an unknown type, we do know the
2645                     name of the property (and don't seem to need the package), but
2646                     we need to make avm2 try out all access modes */
2647                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2648                  $$.c = abc_getproperty2($$.c, &m);
2649                  $$.c = abc_coerce_a($$.c);
2650                  $$.t = registry_getanytype();
2651              }
2652             }
2653
2654 VAR_READ : T_IDENTIFIER {
2655     $$.t = 0;
2656     $$.c = 0;
2657     classinfo_t*a = 0;
2658     memberinfo_t*f = 0;
2659
2660     variable_t*v;
2661     /* look at variables */
2662     if((v = find_variable($1))) {
2663         // $1 is a local variable
2664         $$.c = abc_getlocal($$.c, v->index);
2665         $$.t = v->type;
2666
2667     /* look at current class' members */
2668     } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2669         // $1 is a function in this class
2670         int var_is_static = (f->flags&FLAG_STATIC);
2671         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2672         if(var_is_static != i_am_static) {
2673             /* there doesn't seem to be any "static" way to access
2674                static properties of a class */
2675             state->method->late_binding = 1;
2676             $$.t = f->type;
2677             namespace_t ns = {flags2access(f->flags), ""};
2678             multiname_t m = {QNAME, &ns, 0, $1};
2679             $$.c = abc_findpropstrict2($$.c, &m);
2680             $$.c = abc_getproperty2($$.c, &m);
2681         } else {
2682             if(f->slot>0) {
2683                 $$.c = abc_getlocal_0($$.c);
2684                 $$.c = abc_getslot($$.c, f->slot);
2685             } else {
2686                 namespace_t ns = {flags2access(f->flags), ""};
2687                 multiname_t m = {QNAME, &ns, 0, $1};
2688                 $$.c = abc_getlocal_0($$.c);
2689                 $$.c = abc_getproperty2($$.c, &m);
2690             }
2691         }
2692         if(f->kind == MEMBER_METHOD) {
2693             $$.t = TYPE_FUNCTION(f);
2694         } else {
2695             $$.t = f->type;
2696         }
2697     
2698     /* look at actual classes, in the current package and imported */
2699     } else if((a = find_class($1))) {
2700         if(a->flags & FLAG_METHOD) {
2701             MULTINAME(m, a);
2702             $$.c = abc_findpropstrict2($$.c, &m);
2703             $$.c = abc_getproperty2($$.c, &m);
2704             $$.t = TYPE_FUNCTION(a->function);
2705         } else {
2706             if(a->slot) {
2707                 $$.c = abc_getglobalscope($$.c);
2708                 $$.c = abc_getslot($$.c, a->slot);
2709             } else {
2710                 MULTINAME(m, a);
2711                 $$.c = abc_getlex2($$.c, &m);
2712             }
2713             $$.t = TYPE_CLASS(a);
2714         }
2715
2716     /* unknown object, let the avm2 resolve it */
2717     } else {
2718         if(strcmp($1,"trace"))
2719             warning("Couldn't resolve '%s', doing late binding", $1);
2720         state->method->late_binding = 1;
2721                 
2722         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2723
2724         $$.t = 0;
2725         $$.c = abc_findpropstrict2($$.c, &m);
2726         $$.c = abc_getproperty2($$.c, &m);
2727     }
2728 }
2729
2730 //TODO: 
2731 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2732 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2733 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2734
2735 // ----------------- namespaces -------------------------------------------------
2736
2737 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2738 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2739 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2740
2741 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}
2742