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