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