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