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