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