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