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