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