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