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