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