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