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