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