3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
31 #include "tokenizer.h"
48 enum yytokentype token;
50 classinfo_t*classinfo;
51 classinfo_list_t*classinfo_list;
53 slotinfo_list_t*slotinfo_list;
56 unsigned int number_uint;
60 //typedcode_list_t*value_list;
61 codeandnumber_t value_list;
67 for_start_t for_start;
68 abc_exception_t *exception;
71 namespace_decl_t* namespace_decl;
74 abc_exception_list_t *l;
80 %token<id> T_IDENTIFIER T_NAMESPACE
82 %token<regexp> T_REGEXP
84 %token<number_int> T_INT
85 %token<number_uint> T_UINT
86 %token<number_float> T_FLOAT
88 %token<id> T_FOR "for"
89 %token<id> T_WHILE "while"
91 %token<id> T_SWITCH "switch"
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"
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 ">>"
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
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
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
206 %type <classinfo> MAYBETYPE
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
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
231 // precedence: from low to high
235 %left below_semicolon
238 %nonassoc below_assignment // for ?:, contrary to spec
239 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
246 %nonassoc "==" "!=" "===" "!=="
247 %nonassoc "is" "as" "in"
249 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
250 %left "<<" ">>" ">>>"
254 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
256 %nonassoc below_curly
260 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
262 %left T_IDENTIFIER "arguments"
263 %left above_identifier
267 // needed for "return" precedence:
268 %nonassoc T_STRING T_REGEXP
269 %nonassoc T_INT T_UINT T_FLOAT KW_NAN
271 %nonassoc "false" "true" "null" "undefined" "super" "function"
277 static int a3_error(char*s)
279 syntaxerror("%s", s);
280 return 0; //make gcc happy
283 static void parsererror(const char*file, int line, const char*f)
285 syntaxerror("internal error in %s, %s:%d", f, file, line);
288 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
291 static char* concat2(const char* t1, const char* t2)
295 char*text = malloc(l1+l2+1);
296 memcpy(text , t1, l1);
297 memcpy(text+l1, t2, l2);
301 static char* concat3(const char* t1, const char* t2, const char* 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);
314 typedef struct _import {
317 DECLARE_LIST(import);
319 DECLARE(methodstate);
320 DECLARE_LIST(methodstate);
322 typedef struct _classstate {
328 methodstate_t*static_init;
330 //code_t*static_init;
331 parsedclass_t*dependencies;
333 char has_constructor;
336 struct _methodstate {
347 dict_t*unresolved_variables;
350 char uses_parent_function;
351 char no_variable_scoping;
359 int var_index; // for inner methods
360 int slot_index; // for inner methods
361 char is_a_slot; // for inner methods
366 abc_exception_list_t*exceptions;
368 methodstate_list_t*innerfunctions;
371 void methodstate_destroy(methodstate_t*m)
373 dict_destroy(m->unresolved_variables);
374 m->unresolved_variables = 0;
375 list_free(m->innerfunctions);m->innerfunctions=0;
378 typedef struct _state {
383 import_list_t*wildcard_imports;
384 dict_t*import_toplevel_packages;
387 namespace_list_t*active_namespace_urls;
389 char has_own_imports;
390 char new_vars; // e.g. transition between two functions
391 char xmlfilter; // are we inside a xmlobj..() filter?
394 methodstate_t*method;
401 dict_t*allvars; // also contains variables from sublevels
404 typedef struct _global {
407 parsedclass_list_t*classes;
408 abc_script_t*classinit;
410 abc_script_t*init; //package-level code
413 dict_t*file2token2info;
416 static global_t*global = 0;
417 static state_t* state = 0;
421 /* protected handling here is a big hack: we just assume the protectedns
422 is package:class. the correct approach would be to add the proper
423 namespace to all protected members in the registry, even though that
424 would slow down searching */
425 #define MEMBER_MULTINAME(m,f,n) \
429 m##_ns.access = ((slotinfo_t*)(f))->access; \
430 if(m##_ns.access == ACCESS_NAMESPACE) \
431 m##_ns.name = ((slotinfo_t*)(f))->package; \
432 else if(m##_ns.access == ACCESS_PROTECTED && (f)->parent) \
433 m##_ns.name = concat3((f)->parent->package,":",(f)->parent->name); \
438 m.namespace_set = 0; \
439 m.name = ((slotinfo_t*)(f))->name; \
441 m.type = MULTINAME; \
443 m.namespace_set = &nopackage_namespace_set; \
447 /* warning: list length of namespace set is undefined */
448 #define MULTINAME_LATE(m, access, package) \
449 namespace_t m##_ns = {access, package}; \
450 namespace_set_t m##_nsset; \
451 namespace_list_t m##_l;m##_l.next = 0; \
452 m##_nsset.namespaces = &m##_l; \
453 m##_nsset = m##_nsset; \
454 m##_l.namespace = &m##_ns; \
455 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
457 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
458 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
459 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
460 static namespace_t stdns = {ACCESS_PACKAGE, ""};
461 static namespace_list_t nl4 = {&stdns,0};
462 static namespace_list_t nl3 = {&ns3,&nl4};
463 static namespace_list_t nl2 = {&ns2,&nl3};
464 static namespace_list_t nl1 = {&ns1,&nl2};
465 static namespace_set_t nopackage_namespace_set = {&nl1};
467 static dict_t*definitions=0;
468 void as3_set_define(const char*c)
471 definitions = dict_new();
472 if(!dict_contains(definitions,c))
473 dict_put(definitions,c,0);
476 static void new_state()
479 state_t*oldstate = state;
481 memcpy(s, state, sizeof(state_t)); //shallow copy
483 s->imports = dict_new();
485 if(!s->import_toplevel_packages) {
486 s->import_toplevel_packages = dict_new();
490 state->has_own_imports = 0;
491 state->vars = dict_new();
492 state->old = oldstate;
495 trie_remember(active_namespaces);
498 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
501 static void state_destroy(state_t*state)
503 if(state->has_own_imports) {
504 list_free(state->wildcard_imports);
505 dict_destroy(state->imports);state->imports=0;
507 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
508 dict_destroy(state->imports);state->imports=0;
511 dict_destroy(state->vars);state->vars=0;
513 if(state->new_vars && state->allvars) {
514 parserassert(!state->old || state->old->allvars != state->allvars);
515 DICT_ITERATE_DATA(state->allvars, void*, data) {
518 dict_destroy(state->allvars);
521 list_free(state->active_namespace_urls)
522 state->active_namespace_urls = 0;
527 static void old_state()
529 trie_rollback(active_namespaces);
531 if(!state || !state->old)
532 syntaxerror("invalid nesting");
533 state_t*leaving = state;
537 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
538 methodstate_destroy(leaving->method);leaving->method=0;
540 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
545 state_destroy(leaving);
548 static code_t* method_header(methodstate_t*m);
549 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
550 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0);
553 static char* internal_filename_package = 0;
554 void initialize_file(char*filename)
557 syntaxerror("invalid call to initialize_file during parsing of another file");
560 active_namespaces = trie_new();
563 state->package = internal_filename_package = strdup(filename);
564 state->allvars = dict_new();
566 global->token2info = dict_lookup(global->file2token2info,
567 current_filename // use long version
569 if(!global->token2info) {
570 global->token2info = dict_new2(&ptr_type);
571 dict_put(global->file2token2info, current_filename, global->token2info);
575 state->method = rfx_calloc(sizeof(methodstate_t));
576 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
577 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
579 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
580 state->method->variable_count = 0;
582 syntaxerror("internal error: skewed tokencount");
583 function_initvars(state->method, 0, 0, 0, 1);
590 if(!state || state->level!=1) {
591 syntaxerror("unexpected end of file in pass %d", as3_pass);
595 dict_del(global->file2token2info, current_filename);
596 code_t*header = method_header(state->method);
597 //if(global->init->method->body->code || global->init->traits) {
599 code_t*c = wrap_function(header, 0, global->init->method->body->code);
600 global->init->method->body->code = abc_returnvoid(c);
601 free(state->method);state->method=0;
605 //free(state->package);state->package=0; // used in registry
606 state_destroy(state);state=0;
609 void initialize_parser()
611 global = rfx_calloc(sizeof(global_t));
612 global->file = abc_file_new();
613 global->file->flags &= ~ABCFILE_LAZY;
614 global->file2token2info = dict_new();
615 global->token2info = 0;
616 global->classinit = abc_initscript(global->file);
619 void* finish_parser()
621 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
622 global->token2info=0;
624 initcode_add_classlist(global->classinit, global->classes);
629 typedef struct _variable {
635 methodstate_t*is_inner_method;
638 static variable_t* find_variable(state_t*s, char*name)
640 if(s->method->no_variable_scoping) {
641 return dict_lookup(s->allvars, name);
646 v = dict_lookup(s->vars, name);
648 if(s->new_vars) break;
654 static variable_t* find_slot(methodstate_t*m, const char*name)
657 return dict_lookup(m->slots, name);
661 static variable_t* find_variable_safe(state_t*s, char*name)
663 variable_t* v = find_variable(s, name);
665 syntaxerror("undefined variable: %s", name);
669 static char variable_exists(char*name)
671 return dict_contains(state->vars, name);
674 static code_t*defaultvalue(code_t*c, classinfo_t*type)
676 if(TYPE_IS_INT(type)) {
677 c = abc_pushbyte(c, 0);
678 } else if(TYPE_IS_UINT(type)) {
679 c = abc_pushuint(c, 0);
680 } else if(TYPE_IS_FLOAT(type)) {
682 } else if(TYPE_IS_BOOLEAN(type)) {
683 c = abc_pushfalse(c);
684 } else if(TYPE_IS_STRING(type)) {
688 //c = abc_pushundefined(c);
689 syntaxerror("internal error: can't generate default value for * type");
693 c = abc_coerce2(c, &m);
698 static int alloc_local()
700 return state->method->variable_count++;
703 static variable_t* new_variable2(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
706 variable_t*v = find_slot(method, name);
714 v->index = alloc_local();
716 v->init = v->kill = init;
719 if(!method->no_variable_scoping)
721 if(dict_contains(state->vars, name)) {
723 syntaxerror("variable %s already defined", name);
725 dict_put(state->vars, name, v);
727 if(method->no_variable_scoping &&
729 dict_contains(state->allvars, name))
731 variable_t*v = dict_lookup(state->allvars, name);
733 syntaxerror("variable %s already defined.", name);
736 dict_put(state->allvars, name, v);
741 static int new_variable(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
743 return new_variable2(method, name, type, init, maybeslot)->index;
746 #define TEMPVARNAME "__as3_temp__"
749 variable_t*v = find_variable(state, TEMPVARNAME);
754 i = new_variable(state->method, TEMPVARNAME, 0, 0, 0);
759 static code_t* var_block(code_t*body, dict_t*vars)
764 DICT_ITERATE_DATA(vars, variable_t*, v) {
765 if(v->type && v->init) {
766 c = defaultvalue(c, v->type);
767 c = abc_setlocal(c, v->index);
769 if(v->type && v->kill) {
770 k = abc_kill(k, v->index);
777 if(x->opcode== OPCODE___BREAK__ ||
778 x->opcode== OPCODE___CONTINUE__) {
779 /* link kill code before break/continue */
780 code_t*e = code_dup(k);
781 code_t*s = code_start(e);
793 c = code_append(c, body);
794 c = code_append(c, k);
798 static void unknown_variable(char*name)
800 if(!state->method->unresolved_variables)
801 state->method->unresolved_variables = dict_new();
802 if(!dict_contains(state->method->unresolved_variables, name))
803 dict_put(state->method->unresolved_variables, name, 0);
806 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
808 if(m->uses_slots || m->innerfunctions || (m->late_binding && !m->inner)) {
809 c = abc_getlocal_0(c);
810 c = abc_pushscope(c);
813 /* FIXME: this alloc_local() causes variable indexes to be
814 different in pass2 than in pass1 */
815 if(!m->activation_var) {
816 m->activation_var = alloc_local();
819 c = abc_newactivation(c);
821 c = abc_pushscope(c);
822 c = abc_setlocal(c, m->activation_var);
824 c = abc_getlocal(c, m->activation_var);
825 c = abc_pushscope(c);
831 static code_t* method_header(methodstate_t*m)
835 c = add_scope_code(c, m, 1);
837 methodstate_list_t*l = m->innerfunctions;
839 parserassert(l->methodstate->abc);
840 if(m->uses_slots && l->methodstate->is_a_slot) {
841 c = abc_getscopeobject(c, 1);
842 c = abc_newfunction(c, l->methodstate->abc);
844 c = abc_setlocal(c, l->methodstate->var_index);
845 c = abc_setslot(c, l->methodstate->slot_index);
847 c = abc_newfunction(c, l->methodstate->abc);
848 c = abc_setlocal(c, l->methodstate->var_index);
850 free(l->methodstate);l->methodstate=0;
854 c = code_append(c, m->header);
857 if(m->is_constructor && !m->has_super) {
858 // call default constructor
859 c = abc_getlocal_0(c);
860 c = abc_constructsuper(c, 0);
864 /* all parameters that are used by inner functions
865 need to be copied from local to slot */
866 parserassert(m->activation_var);
867 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
868 if(v->is_parameter) {
869 c = abc_getlocal(c, m->activation_var);
870 c = abc_getlocal(c, v->index);
871 c = abc_setslot(c, v->index);
875 list_free(m->innerfunctions);
876 m->innerfunctions = 0;
881 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
883 c = code_append(c, header);
884 c = code_append(c, var_block(body, state->method->no_variable_scoping?state->allvars:state->vars));
885 /* append return if necessary */
886 if(!c || (c->opcode != OPCODE_RETURNVOID &&
887 c->opcode != OPCODE_RETURNVALUE)) {
888 c = abc_returnvoid(c);
893 static void startpackage(char*name)
896 state->package = strdup(name);
898 static void endpackage()
900 //used e.g. in classinfo_register:
901 //free(state->package);state->package=0;
905 #define FLAG_PUBLIC 256
906 #define FLAG_PROTECTED 512
907 #define FLAG_PRIVATE 1024
908 #define FLAG_PACKAGEINTERNAL 2048
909 #define FLAG_NAMESPACE 4096
911 static namespace_t modifiers2access(modifiers_t*mod)
916 if(mod->flags&FLAG_NAMESPACE) {
917 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
918 syntaxerror("invalid combination of access levels and namespaces");
919 ns.access = ACCESS_NAMESPACE;
921 const char*url = (const char*)trie_lookup(active_namespaces, (unsigned char*)mod->ns);
923 /* shouldn't happen- the tokenizer only reports something as a namespace
924 if it was already registered */
925 trie_dump(active_namespaces);
926 syntaxerror("unknown namespace: %s", mod->ns);
929 } else if(mod->flags&FLAG_PUBLIC) {
930 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
931 syntaxerror("invalid combination of access levels");
932 ns.access = ACCESS_PACKAGE;
933 } else if(mod->flags&FLAG_PRIVATE) {
934 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
935 syntaxerror("invalid combination of access levels");
936 ns.access = ACCESS_PRIVATE;
937 } else if(mod->flags&FLAG_PROTECTED) {
938 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
939 syntaxerror("invalid combination of access levels");
940 ns.access = ACCESS_PROTECTED;
942 ns.access = ACCESS_PACKAGEINTERNAL;
946 static slotinfo_t* find_class(const char*name);
948 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
950 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
953 static void innerfunctions2vars(methodstate_t*m)
955 methodstate_list_t*l = m->innerfunctions;
957 methodstate_t*m = l->methodstate;
959 variable_t* v = new_variable2(state->method, m->info->name, TYPE_FUNCTION(m->info), 0, 0);
960 m->var_index = v->index;
962 m->slot_index = m->is_a_slot;
963 v->is_inner_method = m;
968 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
973 index = new_variable(m, "this", 0, 0, 0);
974 else if(!m->is_global)
975 index = new_variable(m, (flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
977 index = new_variable(m, "globalscope", 0, 0, 0);
979 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
980 printf("%s %d\n", name, v->index);
983 parserassert(!index);
988 for(p=params->list;p;p=p->next) {
989 variable_t*v = new_variable2(m, p->param->name, p->param->type, 0, 1);
992 if(as3_pass==2 && m->need_arguments) {
993 /* arguments can never be used by an innerfunction (the inner functions
994 have their own arguments var), so it's ok to not initialize this until
995 pass 2. (We don't know whether we need it before, anyway) */
996 variable_t*v = new_variable2(m, "arguments", TYPE_ARRAY, 0, 0);
997 m->need_arguments = v->index;
1001 innerfunctions2vars(m);
1004 m->scope_code = add_scope_code(m->scope_code, m, 0);
1006 /* exchange unresolved identifiers with the actual objects */
1007 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
1008 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
1009 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
1010 if(!type || type->kind != INFOTYPE_CLASS) {
1011 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
1021 char*as3_globalclass=0;
1022 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
1025 syntaxerror("inner classes now allowed");
1030 classinfo_list_t*mlist=0;
1032 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
1033 syntaxerror("invalid modifier(s)");
1035 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
1036 syntaxerror("public and internal not supported at the same time.");
1038 if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
1039 syntaxerror("protected and static not supported at the same time.");
1041 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1042 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1043 // all classes extend object
1044 extends = registry_getobjectclass();
1047 /* create the class name, together with the proper attributes */
1051 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
1052 access = ACCESS_PRIVATE; package = internal_filename_package;
1053 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
1054 access = ACCESS_PACKAGEINTERNAL; package = state->package;
1055 } else if(state->package!=internal_filename_package) {
1056 access = ACCESS_PACKAGE; package = state->package;
1058 syntaxerror("public classes only allowed inside a package");
1062 state->cls = rfx_calloc(sizeof(classstate_t));
1063 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1064 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1065 state->cls->static_init->is_static=FLAG_STATIC;
1066 /* notice: we make no effort to initialize the top variable (local0) here,
1067 even though it has special meaning. We just rely on the fact
1068 that pass 1 won't do anything with variables */
1070 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1072 /* set current method to constructor- all code within the class-level (except
1073 static variable initializations) will be executed during construction time */
1074 state->method = state->cls->init;
1076 if(registry_find(package, classname)) {
1077 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1079 /* build info struct */
1080 int num_interfaces = (list_length(implements));
1081 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1082 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1083 state->cls->info->superclass = extends;
1086 classinfo_list_t*l = implements;
1087 for(l=implements;l;l=l->next) {
1088 state->cls->info->interfaces[pos++] = l->classinfo;
1093 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1095 parserassert(state->cls && state->cls->info);
1097 state->method = state->cls->static_init;
1099 function_initvars(state->cls->init, 0, 0, 0, 1);
1100 state->cls->static_init->variable_count=1;
1101 function_initvars(state->cls->static_init, 0, 0, 0, 0);
1103 if(extends && (extends->flags & FLAG_FINAL))
1104 syntaxerror("Can't extend final class '%s'", extends->name);
1107 while(state->cls->info->interfaces[pos]) {
1108 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1109 syntaxerror("'%s' is not an interface",
1110 state->cls->info->interfaces[pos]->name);
1114 /* generate the abc code for this class */
1115 MULTINAME(classname2,state->cls->info);
1116 multiname_t*extends2 = sig2mname(extends);
1118 /* don't add the class to the class index just yet- that will be done later
1120 state->cls->abc = abc_class_new(0, &classname2, extends2);
1121 state->cls->abc->file = global->file;
1123 multiname_destroy(extends2);
1124 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1125 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1126 if(state->cls->info->flags&FLAG_INTERFACE) {
1127 abc_class_interface(state->cls->abc);
1130 for(mlist=implements;mlist;mlist=mlist->next) {
1131 MULTINAME(m, mlist->classinfo);
1132 abc_class_add_interface(state->cls->abc, &m);
1135 state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
1136 list_append(global->classes, state->cls->dependencies);
1138 /* flash.display.MovieClip handling */
1139 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1140 if(state->package && state->package[0]) {
1141 as3_globalclass = concat3(state->package, ".", classname);
1143 as3_globalclass = strdup(classname);
1149 static void endclass()
1152 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1154 c = abc_getlocal_0(c);
1155 c = abc_constructsuper(c, 0);
1156 state->cls->init->header = code_append(state->cls->init->header, c);
1157 state->cls->has_constructor=1;
1159 if(state->cls->init) {
1160 if(state->cls->info->flags&FLAG_INTERFACE) {
1161 if(state->cls->init->header)
1162 syntaxerror("interface can not have class-level code");
1164 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1165 code_t*c = method_header(state->cls->init);
1166 m->body->code = wrap_function(c, 0, m->body->code);
1169 if(state->cls->static_init) {
1170 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1171 code_t*c = method_header(state->cls->static_init);
1172 m->body->code = wrap_function(c, 0, m->body->code);
1175 trait_list_t*trait = state->cls->abc->traits;
1176 /* switch all protected members to the protected ns of this class */
1178 trait_t*t = trait->trait;
1179 if(t->name->ns->access == ACCESS_PROTECTED) {
1180 if(!state->cls->abc->protectedNS) {
1181 char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
1182 state->cls->abc->protectedNS = namespace_new_protected(n);
1183 state->cls->abc->flags |= CLASS_PROTECTED_NS;
1185 t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
1187 trait = trait->next;
1194 void check_code_for_break(code_t*c)
1197 if(c->opcode == OPCODE___BREAK__) {
1198 char*name = string_cstr(c->data[0]);
1199 syntaxerror("Unresolved \"break %s\"", name);
1201 if(c->opcode == OPCODE___CONTINUE__) {
1202 char*name = string_cstr(c->data[0]);
1203 syntaxerror("Unresolved \"continue %s\"", name);
1205 if(c->opcode == OPCODE___RETHROW__) {
1206 syntaxerror("Unresolved \"rethrow\"");
1208 if(c->opcode == OPCODE___FALLTHROUGH__) {
1209 syntaxerror("Unresolved \"fallthrough\"");
1211 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1212 char*name = string_cstr(c->data[0]);
1213 syntaxerror("Can't reference a package (%s) as such", name);
1219 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1221 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1222 if(TYPE_IS_NUMBER(t)) {
1223 xassert(c->type == CONSTANT_FLOAT
1224 || c->type == CONSTANT_INT
1225 || c->type == CONSTANT_UINT);
1226 } else if(TYPE_IS_UINT(t)) {
1227 xassert(c->type == CONSTANT_UINT ||
1228 (c->type == CONSTANT_INT && c->i>=0));
1229 } else if(TYPE_IS_INT(t)) {
1230 xassert(c->type == CONSTANT_INT);
1231 } else if(TYPE_IS_BOOLEAN(t)) {
1232 xassert(c->type == CONSTANT_TRUE
1233 || c->type == CONSTANT_FALSE);
1237 static void check_override(memberinfo_t*m, int flags)
1241 if(m->parent == state->cls->info)
1242 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1244 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1245 if(m->access==ACCESS_PRIVATE)
1247 if(m->flags & FLAG_FINAL)
1248 syntaxerror("can't override final member %s", m->name);
1250 /* allow this. it's no issue.
1251 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1252 syntaxerror("can't override static member %s", m->name);*/
1254 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1255 syntaxerror("can't override non-static member %s with static declaration", m->name);
1257 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1258 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1259 if(m->kind == INFOTYPE_METHOD)
1260 syntaxerror("can't override without explicit 'override' declaration");
1262 syntaxerror("can't override '%s'", m->name);
1267 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1269 methodinfo_t*minfo = 0;
1270 namespace_t ns = modifiers2access(mod);
1273 minfo = methodinfo_register_global(ns.access, state->package, name);
1274 minfo->return_type = return_type;
1275 } else if(getset != KW_GET && getset != KW_SET) {
1277 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1279 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1281 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1282 minfo->return_type = return_type;
1283 // getslot on a member slot only returns "undefined", so no need
1284 // to actually store these
1285 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1287 //class getter/setter
1288 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1290 if(getset == KW_GET) {
1292 } else if(params->list && params->list->param && !params->list->next) {
1293 type = params->list->param->type;
1295 syntaxerror("setter function needs to take exactly one argument");
1296 // not sure wether to look into superclasses here, too
1297 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1299 if(minfo->kind!=INFOTYPE_VAR)
1300 syntaxerror("class already contains a method called '%s'", name);
1301 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1302 syntaxerror("class already contains a field called '%s'", name);
1303 if(minfo->subtype & gs)
1304 syntaxerror("getter/setter for '%s' already defined", name);
1305 /* make a setter or getter into a getset */
1306 minfo->subtype |= gs;
1309 FIXME: this check needs to be done in pass 2
1311 if((!minfo->return_type != !type) ||
1312 (minfo->return_type && type &&
1313 !strcmp(minfo->return_type->name, type->name))) {
1314 syntaxerror("different type in getter and setter: %s and %s",
1315 minfo->return_type?minfo->return_type->name:"*",
1316 type?type->name:"*");
1319 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1320 minfo->kind = INFOTYPE_VAR; //hack
1321 minfo->subtype = gs;
1322 minfo->return_type = type;
1325 /* can't assign a slot as getter and setter might have different slots */
1326 //minfo->slot = slot;
1328 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1329 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1330 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1335 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1337 //parserassert(state->method && state->method->info);
1339 methodstate_t*parent_method = state->method;
1343 return_type = 0; // not valid in pass 1
1345 v = new_variable2(parent_method, name, 0, 0, 0);
1350 state->new_vars = 1;
1351 state->allvars = dict_new();
1354 state->method = rfx_calloc(sizeof(methodstate_t));
1355 state->method->inner = 1;
1356 state->method->is_static = parent_method->is_static;
1357 state->method->variable_count = 0;
1358 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1360 v->is_inner_method = state->method;
1363 NEW(methodinfo_t,minfo);
1364 minfo->kind = INFOTYPE_METHOD;
1365 minfo->access = ACCESS_PACKAGEINTERNAL;
1367 state->method->info = minfo;
1370 list_append(parent_method->innerfunctions, state->method);
1372 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1374 function_initvars(state->method, 1, params, 0, 1);
1378 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1379 state->method->variable_count = 0;
1380 parserassert(state->method);
1382 state->method->info->return_type = return_type;
1383 function_initvars(state->method, 1, params, 0, 1);
1387 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1388 params_t*params, classinfo_t*return_type)
1390 if(state->method && state->method->info) {
1391 syntaxerror("not able to start another method scope");
1394 state->new_vars = 1;
1395 state->allvars = dict_new();
1398 state->method = rfx_calloc(sizeof(methodstate_t));
1399 state->method->has_super = 0;
1400 state->method->is_static = mod->flags&FLAG_STATIC;
1403 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1405 state->method->is_global = 1;
1406 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1408 if(state->method->is_constructor)
1409 name = "__as3_constructor__";
1411 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1413 function_initvars(state->method, 1, params, mod->flags, 1);
1415 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1419 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1420 state->method->variable_count = 0;
1421 parserassert(state->method);
1424 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1425 check_override(m, mod->flags);
1429 state->cls->has_constructor |= state->method->is_constructor;
1432 function_initvars(state->method, 1, params, mod->flags, 1);
1436 static void insert_unresolved(methodstate_t*m, dict_t*xvars, dict_t*allvars)
1438 parserassert(m->inner);
1439 if(m->unresolved_variables) {
1440 dict_t*d = m->unresolved_variables;
1442 DICT_ITERATE_KEY(d, char*, id) {
1443 /* check parent method's variables */
1445 if(dict_contains(allvars, id)) {
1446 m->uses_parent_function = 1;
1447 state->method->uses_slots = 1;
1448 dict_put(xvars, id, 0);
1452 methodstate_list_t*ml = m->innerfunctions;
1454 insert_unresolved(ml->methodstate, xvars, allvars);
1459 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1460 params_t*params, classinfo_t*return_type, code_t*body)
1463 dict_t*xvars = dict_new();
1465 if(state->method->unresolved_variables) {
1466 DICT_ITERATE_KEY(state->method->unresolved_variables, char*, vname) {
1467 if(!state->method->no_variable_scoping && dict_contains(state->allvars, vname)) {
1468 variable_t*v = dict_lookup(state->allvars, vname);
1469 if(!v->is_inner_method) {
1470 state->method->no_variable_scoping = 1;
1471 as3_warning("function %s uses forward or outer block variable references (%s): switching into compatiblity mode", name, vname);
1477 methodstate_list_t*ml = state->method->innerfunctions;
1479 insert_unresolved(ml->methodstate, xvars, state->allvars);
1483 if(state->method->uses_slots) {
1484 state->method->slots = dict_new();
1486 DICT_ITERATE_ITEMS(state->allvars, char*, name, variable_t*, v) {
1487 if(!name) syntaxerror("internal error");
1488 if(v->index && dict_contains(xvars, name)) {
1489 v->init = v->kill = 0;
1491 if(v->is_inner_method) {
1492 v->is_inner_method->is_a_slot = i;
1495 dict_put(state->method->slots, name, v);
1498 state->method->uses_slots = i;
1499 dict_destroy(state->vars);state->vars = 0;
1500 parserassert(state->new_vars);
1501 dict_destroy(state->allvars);state->allvars = 0;
1508 /*if(state->method->uses_parent_function){
1509 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1514 multiname_t*type2 = sig2mname(return_type);
1516 if(state->method->inner) {
1517 f = state->method->abc;
1518 abc_method_init(f, global->file, type2, 1);
1519 } else if(state->method->is_constructor) {
1520 f = abc_class_getconstructor(state->cls->abc, type2);
1521 } else if(!state->method->is_global) {
1522 namespace_t ns = modifiers2access(mod);
1523 multiname_t mname = {QNAME, &ns, 0, name};
1524 if(mod->flags&FLAG_STATIC)
1525 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1527 f = abc_class_method(state->cls->abc, type2, &mname);
1528 slot = f->trait->slot_id;
1530 namespace_t mname_ns = {state->method->info->access, state->package};
1531 multiname_t mname = {QNAME, &mname_ns, 0, name};
1533 f = abc_method_new(global->file, type2, 1);
1534 if(!global->init) global->init = abc_initscript(global->file);
1535 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1536 //abc_code_t*c = global->init->method->body->code;
1538 //flash doesn't seem to allow us to access function slots
1539 //state->method->info->slot = slot;
1541 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1542 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1543 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1544 if(params->varargs) f->flags |= METHOD_NEED_REST;
1545 if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
1549 for(p=params->list;p;p=p->next) {
1550 if(params->varargs && !p->next) {
1551 break; //varargs: omit last parameter in function signature
1553 multiname_t*m = sig2mname(p->param->type);
1554 list_append(f->parameters, m);
1555 if(p->param->value) {
1556 check_constant_against_type(p->param->type, p->param->value);
1557 opt=1;list_append(f->optional_parameters, p->param->value);
1559 syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
1562 if(state->method->slots) {
1563 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1565 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1566 multiname_t*type = sig2mname(v->type);
1567 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1568 t->slot_id = v->index;
1573 check_code_for_break(body);
1575 /* Seems this works now.
1576 if(state->method->exceptions && state->method->uses_slots) {
1577 as3_warning("try/catch and activation not supported yet within the same method");
1581 f->body->code = body;
1582 f->body->exceptions = state->method->exceptions;
1583 } else { //interface
1585 syntaxerror("interface methods can't have a method body");
1595 void breakjumpsto(code_t*c, char*name, code_t*jump)
1598 if(c->opcode == OPCODE___BREAK__) {
1599 string_t*name2 = c->data[0];
1600 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1601 c->opcode = OPCODE_JUMP;
1608 void continuejumpsto(code_t*c, char*name, code_t*jump)
1611 if(c->opcode == OPCODE___CONTINUE__) {
1612 string_t*name2 = c->data[0];
1613 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1614 c->opcode = OPCODE_JUMP;
1622 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1627 return abc_coerce_a(c);
1631 // cast an "any" type to a specific type. subject to
1632 // runtime exceptions
1633 return abc_coerce2(c, &m);
1636 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1637 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1638 // allow conversion between number types
1639 if(TYPE_IS_UINT(to))
1640 return abc_convert_u(c);
1641 else if(TYPE_IS_INT(to))
1642 return abc_convert_i(c);
1643 else if(TYPE_IS_NUMBER(to))
1644 return abc_convert_d(c);
1645 return abc_coerce2(c, &m);
1648 if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
1651 if(TYPE_IS_BOOLEAN(to))
1652 return abc_convert_b(c);
1653 if(TYPE_IS_STRING(to))
1654 return abc_convert_s(c);
1655 if(TYPE_IS_OBJECT(to))
1656 return abc_coerce2(c, &m);
1657 if(TYPE_IS_OBJECT(from) && TYPE_IS_XMLLIST(to))
1658 return abc_coerce2(c, &m);
1659 if(TYPE_IS_OBJECT(from) && TYPE_IS_ARRAY(to))
1660 return abc_coerce2(c, &m);
1662 classinfo_t*supertype = from;
1664 if(supertype == to) {
1665 /* target type is one of from's superclasses.
1666 (not sure we need this coerce - as far as the verifier
1667 is concerned, object==object (i think) */
1668 return abc_coerce2(c, &m);
1671 while(supertype->interfaces[t]) {
1672 if(supertype->interfaces[t]==to) {
1673 // target type is one of from's interfaces
1674 return abc_coerce2(c, &m);
1678 supertype = supertype->superclass;
1680 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1682 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1684 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1687 as3_error("can't convert type %s%s%s to %s%s%s",
1688 from->package, from->package[0]?".":"", from->name,
1689 to->package, to->package[0]?".":"", to->name);
1693 code_t* coerce_to_type(code_t*c, classinfo_t*t)
1696 return abc_coerce_a(c);
1697 } else if(TYPE_IS_STRING(t)) {
1698 return abc_coerce_s(c);
1701 return abc_coerce2(c, &m);
1705 char is_pushundefined(code_t*c)
1707 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1710 static const char* get_package_from_name(const char*name)
1712 /* try explicit imports */
1713 dictentry_t* e = dict_get_slot(state->imports, name);
1715 if(!strcmp(e->key, name)) {
1716 slotinfo_t*c = (slotinfo_t*)e->data;
1717 if(c) return c->package;
1723 static namespace_list_t*get_current_imports()
1725 namespace_list_t*searchlist = 0;
1727 list_append(searchlist, namespace_new_package(state->package));
1729 import_list_t*l = state->wildcard_imports;
1731 namespace_t*ns = namespace_new_package(l->import->package);
1732 list_append(searchlist, ns);
1735 list_append(searchlist, namespace_new_package(""));
1736 list_append(searchlist, namespace_new_package(internal_filename_package));
1740 static slotinfo_t* find_class(const char*name)
1744 c = registry_find(state->package, name);
1747 /* try explicit imports */
1748 dictentry_t* e = dict_get_slot(state->imports, name);
1751 if(!strcmp(e->key, name)) {
1752 c = (slotinfo_t*)e->data;
1758 /* try package.* imports */
1759 import_list_t*l = state->wildcard_imports;
1761 //printf("does package %s contain a class %s?\n", l->import->package, name);
1762 c = registry_find(l->import->package, name);
1767 /* try global package */
1768 c = registry_find("", name);
1771 /* try local "filename" package */
1772 c = registry_find(internal_filename_package, name);
1777 typedcode_t push_class(slotinfo_t*a)
1782 if(a->access == ACCESS_PACKAGEINTERNAL &&
1783 strcmp(a->package, state->package) &&
1784 strcmp(a->package, internal_filename_package)
1786 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1787 infotypename(a), a->name, a->package, state->package);
1791 if(a->kind != INFOTYPE_CLASS) {
1793 x.c = abc_findpropstrict2(x.c, &m);
1794 x.c = abc_getproperty2(x.c, &m);
1795 if(a->kind == INFOTYPE_METHOD) {
1796 methodinfo_t*f = (methodinfo_t*)a;
1797 x.t = TYPE_FUNCTION(f);
1799 varinfo_t*v = (varinfo_t*)a;
1804 if(state->cls && state->method == state->cls->static_init) {
1805 /* we're in the static initializer.
1806 record the fact that we're using this class here */
1807 parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
1809 classinfo_t*c = (classinfo_t*)a;
1811 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1812 x.c = abc_getglobalscope(x.c);
1813 x.c = abc_getslot(x.c, c->slot);
1816 x.c = abc_getlex2(x.c, &m);
1818 x.t = TYPE_CLASS(c);
1824 char is_break_or_jump(code_t*c)
1828 if(c->opcode == OPCODE_JUMP ||
1829 c->opcode == OPCODE___BREAK__ ||
1830 c->opcode == OPCODE___CONTINUE__ ||
1831 c->opcode == OPCODE_THROW ||
1832 c->opcode == OPCODE_RETURNVOID ||
1833 c->opcode == OPCODE_RETURNVALUE) {
1839 #define IS_FINALLY_TARGET(op) \
1840 ((op) == OPCODE___CONTINUE__ || \
1841 (op) == OPCODE___BREAK__ || \
1842 (op) == OPCODE_RETURNVOID || \
1843 (op) == OPCODE_RETURNVALUE || \
1844 (op) == OPCODE___RETHROW__)
1846 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1848 #define NEED_EXTRA_STACK_ARG
1849 code_t*finally_label = abc_nop(0);
1850 NEW(lookupswitch_t, l);
1856 code_t*prev = i->prev;
1857 if(IS_FINALLY_TARGET(i->opcode)) {
1860 if(i->opcode == OPCODE___RETHROW__ ||
1861 i->opcode == OPCODE_RETURNVALUE) {
1862 if(i->opcode == OPCODE___RETHROW__)
1863 i->opcode = OPCODE_THROW;
1865 p = abc_coerce_a(p);
1866 p = abc_setlocal(p, tempvar);
1868 p = abc_pushbyte(p, count++);
1869 p = abc_jump(p, finally_label);
1870 code_t*target = p = abc_label(p);
1871 #ifdef NEED_EXTRA_STACK_ARG
1875 p = abc_getlocal(p, tempvar);
1878 p->next = i;i->prev = p;
1879 list_append(l->targets, target);
1885 c = abc_pushbyte(c, -1);
1886 c = code_append(c, finally_label);
1887 c = code_append(c, finally);
1889 #ifdef NEED_EXTRA_STACK_ARG
1892 c = abc_lookupswitch(c, l);
1893 c = l->def = abc_label(c);
1894 #ifdef NEED_EXTRA_STACK_ARG
1901 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1905 code_t*prev = i->prev;
1906 if(IS_FINALLY_TARGET(i->opcode)) {
1907 if(i->opcode == OPCODE___RETHROW__)
1908 i->opcode = OPCODE_THROW;
1909 code_t*end = code_dup(finally);
1910 code_t*start = code_start(end);
1911 if(prev) prev->next = start;
1918 return code_append(c, finally);
1921 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1927 int num_insertion_points=0;
1929 if(IS_FINALLY_TARGET(i->opcode))
1930 num_insertion_points++;
1937 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1942 int simple_version_cost = (1+num_insertion_points)*code_size;
1943 int lookup_version_cost = 4*num_insertion_points + 5;
1945 if(cantdup || simple_version_cost > lookup_version_cost) {
1946 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1947 return insert_finally_lookup(c, finally, tempvar);
1949 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1950 return insert_finally_simple(c, finally, tempvar);
1954 #define PASS1 }} if(as3_pass == 1) {{
1955 #define PASS1END }} if(as3_pass == 2) {{
1956 #define PASS2 }} if(as3_pass == 2) {{
1957 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1958 #define PASS12END }} if(as3_pass == 2) {{
1959 #define PASS_ALWAYS }} {{
1965 /* ------------ code blocks / statements ---------------- */
1967 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1969 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1970 PROGRAM_CODE_LIST: PROGRAM_CODE
1971 | PROGRAM_CODE_LIST PROGRAM_CODE
1973 PROGRAM_CODE: PACKAGE_DECLARATION
1974 | INTERFACE_DECLARATION
1976 | FUNCTION_DECLARATION
1979 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1982 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1983 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1984 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1986 INPACKAGE_CODE: INTERFACE_DECLARATION
1988 | FUNCTION_DECLARATION
1991 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1992 | '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
1995 MAYBECODE: CODE {$$=$1;}
1996 MAYBECODE: {$$=code_new();}
1998 CODE: CODE CODEPIECE {
1999 $$=code_append($1,$2);
2001 CODE: CODEPIECE {$$=$1;}
2003 // code which may appear outside of methods
2004 CODE_STATEMENT: DEFAULT_NAMESPACE
2005 CODE_STATEMENT: IMPORT
2007 CODE_STATEMENT: FOR_IN
2008 CODE_STATEMENT: WHILE
2009 CODE_STATEMENT: DO_WHILE
2010 CODE_STATEMENT: SWITCH
2012 CODE_STATEMENT: WITH
2014 CODE_STATEMENT: VOIDEXPRESSION
2015 CODE_STATEMENT: USE_NAMESPACE
2016 CODE_STATEMENT: NAMESPACE_DECLARATION
2017 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
2018 CODE_STATEMENT: '{' '}' {$$=0;}
2020 // code which may appear in methods (includes the above)
2021 CODEPIECE: ';' {$$=0;}
2022 CODEPIECE: CODE_STATEMENT
2023 CODEPIECE: VARIABLE_DECLARATION
2028 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
2038 //CODEBLOCK : '{' CODE '}' {$$=$2;}
2039 //CODEBLOCK : '{' '}' {$$=0;}
2040 CODEBLOCK : CODEPIECE ';' {$$=$1;}
2041 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
2043 /* ------------ package init code ------------------- */
2045 PACKAGE_INITCODE: CODE_STATEMENT {
2048 global->init = abc_initscript(global->file);
2049 code_t**cc = &global->init->method->body->code;
2050 *cc = code_append(*cc, $1);
2054 /* ------------ embed code ------------- */
2056 EMBED_START: %prec above_function {
2062 /* ------------ conditional compilation ------------- */
2064 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
2067 char*key = concat3($1,"::",$3);
2068 if(!definitions || !dict_contains(definitions, key)) {
2074 /* ------------ variables --------------------------- */
2077 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
2081 char do_init_variable(char*name)
2083 if(!state->method->no_variable_scoping)
2085 if(!state->new_vars)
2091 MAYBEEXPRESSION : '=' E {$$=$2;}
2092 | {$$=mkdummynode();}
2094 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2095 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2097 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2098 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2100 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2103 if(variable_exists($1))
2104 syntaxerror("Variable %s already defined", $1);
2106 new_variable(state->method, $1, 0, 1, 0);
2112 if(state->method->uses_slots) {
2113 v = find_slot(state->method, $1);
2115 // this variable is stored in a slot
2122 v = new_variable2(state->method, $1, $2, 1, 0);
2125 $$ = slot?abc_getscopeobject(0, 1):0;
2127 typedcode_t val = node_read($3);
2128 if(!is_subtype_of(val.t, $2)) {
2129 syntaxerror("Can't convert %s to %s", val.t->name, $2->name);
2132 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2133 $$ = code_append($$, val.c);
2134 $$ = converttype($$, val.t, $2);
2137 $$ = defaultvalue($$, $2);
2140 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2141 $$ = code_append($$, val.c);
2142 $$ = abc_coerce_a($$);
2144 // don't do anything
2152 $$ = abc_setslot($$, v->index);
2154 $$ = abc_setlocal($$, v->index);
2155 v->init = do_init_variable($1);
2159 /* ------------ control flow ------------------------- */
2161 IF_CODEBLOCK: {PASS12 new_state();} CODEBLOCK {
2162 $$ = var_block($2, state->vars);
2165 MAYBEELSE: %prec below_else {$$ = code_new();}
2166 MAYBEELSE: "else" IF_CODEBLOCK {$$=$2;}
2167 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2169 IF : "if" '(' EXPRESSION ')' IF_CODEBLOCK MAYBEELSE {
2171 $$ = code_append($$, $3.c);
2172 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2174 $$ = code_append($$, $5);
2176 myjmp = $$ = abc_jump($$, 0);
2178 myif->branch = $$ = abc_nop($$);
2180 $$ = code_append($$, $6);
2181 myjmp->branch = $$ = abc_nop($$);
2185 FOR_INIT : {$$=code_new();}
2186 FOR_INIT : VARIABLE_DECLARATION
2187 FOR_INIT : VOIDEXPRESSION
2189 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2190 // (I don't see any easy way to revolve this conflict otherwise, as we
2191 // can't touch VAR_READ without upsetting the precedence about "return")
2192 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2193 PASS1 $$=$2;new_variable(state->method, $2,0,1,0);
2194 PASS2 $$=$2;new_variable(state->method, $2,$3,1,0);
2196 FOR_IN_INIT : T_IDENTIFIER {
2201 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2202 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2204 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' IF_CODEBLOCK {
2205 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2207 $$ = code_append($$, $2);
2208 code_t*loopstart = $$ = abc_label($$);
2209 $$ = code_append($$, $4.c);
2210 code_t*myif = $$ = abc_iffalse($$, 0);
2211 $$ = code_append($$, $8);
2212 code_t*cont = $$ = abc_nop($$);
2213 $$ = code_append($$, $6);
2214 $$ = abc_jump($$, loopstart);
2215 code_t*out = $$ = abc_nop($$);
2216 breakjumpsto($$, $1.name, out);
2217 continuejumpsto($$, $1.name, cont);
2220 $$ = var_block($$, state->vars);
2224 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' IF_CODEBLOCK {
2225 node_t*n = resolve_identifier($2);
2226 typedcode_t w = node_write(n);
2228 int it = alloc_local();
2229 int array = alloc_local();
2232 $$ = code_append($$, $4.c);
2233 $$ = abc_coerce_a($$);
2234 $$ = abc_setlocal($$, array);
2235 $$ = abc_pushbyte($$, 0);
2236 $$ = abc_setlocal($$, it);
2238 code_t*loopstart = $$ = abc_label($$);
2240 $$ = abc_hasnext2($$, array, it);
2241 code_t*myif = $$ = abc_iffalse($$, 0);
2242 $$ = abc_getlocal($$, array);
2243 $$ = abc_getlocal($$, it);
2245 $$ = abc_nextname($$);
2247 $$ = abc_nextvalue($$);
2249 $$ = converttype($$, 0, w.t);
2250 $$ = code_append($$, w.c);
2252 $$ = code_append($$, $6);
2253 $$ = abc_jump($$, loopstart);
2255 code_t*out = $$ = abc_nop($$);
2256 breakjumpsto($$, $1.name, out);
2257 continuejumpsto($$, $1.name, loopstart);
2261 $$ = abc_kill($$, it);
2262 $$ = abc_kill($$, array);
2264 $$ = var_block($$, state->vars);
2268 WHILE : T_WHILE '(' EXPRESSION ')' IF_CODEBLOCK {
2272 code_t*myjmp = $$ = abc_jump($$, 0);
2273 code_t*loopstart = $$ = abc_label($$);
2274 $$ = code_append($$, $5);
2275 code_t*cont = $$ = abc_nop($$);
2276 myjmp->branch = cont;
2277 $$ = code_append($$, $3.c);
2278 $$ = abc_iftrue($$, loopstart);
2279 code_t*out = $$ = abc_nop($$);
2280 breakjumpsto($$, $1, out);
2281 continuejumpsto($$, $1, cont);
2284 DO_WHILE : T_DO IF_CODEBLOCK "while" '(' EXPRESSION ')' {
2286 code_t*loopstart = $$ = abc_label($$);
2287 $$ = code_append($$, $2);
2288 code_t*cont = $$ = abc_nop($$);
2289 $$ = code_append($$, $5.c);
2290 $$ = abc_iftrue($$, loopstart);
2291 code_t*out = $$ = abc_nop($$);
2292 breakjumpsto($$, $1, out);
2293 continuejumpsto($$, $1, cont);
2296 BREAK : "break" %prec prec_none {
2297 $$ = abc___break__(0, "");
2299 BREAK : "break" T_IDENTIFIER {
2300 $$ = abc___break__(0, $2);
2302 CONTINUE : "continue" %prec prec_none {
2303 $$ = abc___continue__(0, "");
2305 CONTINUE : "continue" T_IDENTIFIER {
2306 $$ = abc___continue__(0, $2);
2309 MAYBE_CASE_LIST : {$$=0;}
2310 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2311 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2312 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2313 CASE_LIST: CASE {$$=$1;}
2314 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2316 CASE: "case" E ':' MAYBECODE {
2317 $$ = abc_getlocal(0, state->switch_var);
2318 $$ = code_append($$, node_read($2).c);
2319 code_t*j = $$ = abc_ifne($$, 0);
2320 $$ = code_append($$, $4);
2321 if($$->opcode != OPCODE___BREAK__) {
2322 $$ = abc___fallthrough__($$, "");
2324 code_t*e = $$ = abc_nop($$);
2327 DEFAULT: "default" ':' MAYBECODE {
2330 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2331 $$ = node_read($4).c;
2332 $$ = abc_setlocal($$, state->switch_var);
2333 $$ = code_append($$, $7);
2335 code_t*out = $$ = abc_kill($$, state->switch_var);
2336 breakjumpsto($$, $1, out);
2338 code_t*c = $$,*lastblock=0;
2340 if(c->opcode == OPCODE_IFNE) {
2341 if(!c->next) syntaxerror("internal error in fallthrough handling");
2343 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2345 c->opcode = OPCODE_JUMP;
2346 c->branch = lastblock;
2348 /* fall through end of switch */
2349 c->opcode = OPCODE_NOP;
2355 $$ = var_block($$, state->vars);
2359 /* ------------ try / catch /finally ---------------- */
2361 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2362 state->exception_name=$3;
2363 PASS1 new_variable(state->method, $3, 0, 0, 0);
2364 PASS2 new_variable(state->method, $3, $4, 0, 0);
2367 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2368 multiname_t name = {QNAME, &name_ns, 0, $3};
2370 NEW(abc_exception_t, e)
2371 e->exc_type = sig2mname($4);
2372 e->var_name = multiname_clone(&name);
2376 int i = find_variable_safe(state, $3)->index;
2377 e->target = c = abc_nop(0);
2378 c = abc_setlocal(c, i);
2379 c = code_append(c, code_dup(state->method->scope_code));
2380 c = code_append(c, $8);
2383 c = var_block(c, state->vars);
2386 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2387 $4 = var_block($4, state->vars);
2391 NEW(abc_exception_t, e)
2392 e->exc_type = 0; //all exceptions
2393 e->var_name = 0; //no name
2396 e->to = code_append(e->to, $4);
2402 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2403 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2404 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2405 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2409 list_append($$.l,$2);
2410 $$.finally = $2->to;$2->to=0;
2413 CATCH_FINALLY_LIST: FINALLY {
2417 list_append($$.l,$1);
2418 $$.finally = $1->to;$1->to=0;
2422 TRY : "try" '{' {PASS12 new_state();
2423 state->method->has_exceptions=1;
2424 state->method->late_binding=1;//for invariant scope_code
2425 } MAYBECODE '}' CATCH_FINALLY_LIST {
2426 code_t*out = abc_nop(0);
2428 code_t*start = abc_nop(0);
2429 $$ = code_append(start, $4);
2430 if(!is_break_or_jump($4)) {
2431 $$ = abc_jump($$, out);
2433 code_t*end = $$ = abc_nop($$);
2437 tmp = alloc_local();
2439 abc_exception_list_t*l = $6.l;
2442 abc_exception_t*e = l->abc_exception;
2444 $$ = code_append($$, e->target);
2445 $$ = abc_jump($$, out);
2447 parserassert((ptroff_t)$6.finally);
2449 e->target = $$ = abc_nop($$);
2450 $$ = code_append($$, code_dup(state->method->scope_code));
2451 $$ = abc___rethrow__($$);
2459 $$ = code_append($$, out);
2461 $$ = insert_finally($$, $6.finally, tmp);
2463 list_concat(state->method->exceptions, $6.l);
2465 $$ = var_block($$, state->vars);
2469 /* ------------ throw ------------------------------- */
2471 THROW : "throw" EXPRESSION {
2475 THROW : "throw" %prec prec_none {
2476 if(!state->exception_name)
2477 syntaxerror("re-throw only possible within a catch block");
2478 variable_t*v = find_variable(state, state->exception_name);
2480 $$=abc_getlocal($$, v->index);
2484 /* ------------ with -------------------------------- */
2486 WITH_HEAD : "with" '(' EXPRESSION ')' {
2488 if(state->method->has_exceptions) {
2489 int v = alloc_local();
2490 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2491 state->method->scope_code = abc_pushwith(state->method->scope_code);
2496 WITH : WITH_HEAD CODEBLOCK {
2497 /* remove getlocal;pushwith from scope code again */
2498 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2501 if(state->method->has_exceptions) {
2503 $$ = abc_setlocal($$, $1.number);
2505 $$ = abc_pushwith($$);
2506 $$ = code_append($$, $2);
2507 $$ = abc_popscope($$);
2511 /* ------------ packages and imports ---------------- */
2513 X_IDENTIFIER: T_IDENTIFIER
2514 | "package" {PASS12 $$="package";}
2515 | "namespace" {PASS12 $$="namespace";}
2516 | "NaN" {PASS12 $$="NaN";}
2517 | T_NAMESPACE {PASS12 $$=$1;}
2519 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2520 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2522 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2523 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2524 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2525 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2528 static void state_has_imports()
2530 state->wildcard_imports = list_clone(state->wildcard_imports);
2531 state->imports = dict_clone(state->imports);
2532 state->has_own_imports = 1;
2534 static void import_toplevel(const char*package)
2536 char* s = strdup(package);
2538 dict_put(state->import_toplevel_packages, s, 0);
2539 char*x = strrchr(s, '.');
2548 IMPORT : "import" T_IDENTIFIER {
2550 slotinfo_t*s = registry_find(state->package, $2);
2551 if(!s && as3_pass==1) {as3_schedule_class(state->package, $2);}
2552 state_has_imports();
2553 dict_put(state->imports, state->package, $2);
2556 IMPORT : "import" PACKAGEANDCLASS {
2558 slotinfo_t*s = registry_find($2->package, $2->name);
2559 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2560 as3_schedule_class($2->package, $2->name);
2562 state_has_imports();
2563 dict_put(state->imports, $2->name, $2);
2564 import_toplevel($2->package);
2567 IMPORT : "import" PACKAGE '.' '*' {
2569 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2570 as3_schedule_package($2);
2575 state_has_imports();
2576 list_append(state->wildcard_imports, i);
2577 import_toplevel(i->package);
2581 /* ------------ classes and interfaces (header) -------------- */
2583 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2584 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2585 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2586 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2588 $$.flags=$1.flags|$2.flags;
2589 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2590 $$.ns=$1.ns?$1.ns:$2.ns;
2593 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2594 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2595 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2596 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2597 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2598 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2599 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2600 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2601 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2602 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2606 EXTENDS : {PASS12 $$=0;}
2607 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2609 EXTENDS_LIST : {PASS12 $$=list_new();}
2610 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2612 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2613 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2615 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2616 EXTENDS IMPLEMENTS_LIST
2617 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2619 '}' {PASS12 endclass();$$=0;}
2621 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2623 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2624 startclass(&$1,$3,0,$4);}
2625 MAYBE_INTERFACE_BODY
2626 '}' {PASS12 endclass();$$=0;}
2628 /* ------------ classes and interfaces (body) -------------- */
2631 MAYBE_CLASS_BODY : CLASS_BODY
2632 CLASS_BODY : CLASS_BODY_ITEM
2633 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2634 CLASS_BODY_ITEM : ';'
2635 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2636 CLASS_BODY_ITEM : SLOT_DECLARATION
2637 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2639 CLASS_BODY_ITEM : CODE_STATEMENT {
2640 code_t*c = state->cls->static_init->header;
2641 c = code_append(c, $1);
2642 state->cls->static_init->header = c;
2645 MAYBE_INTERFACE_BODY :
2646 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2647 INTERFACE_BODY : IDECLARATION
2648 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2650 IDECLARATION : "var" T_IDENTIFIER {
2651 syntaxerror("variable declarations not allowed in interfaces");
2653 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2655 $1.flags |= FLAG_PUBLIC;
2656 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2657 syntaxerror("invalid method modifiers: interface methods always need to be public");
2659 startfunction(&$1,$3,$4,&$6,$8);
2660 endfunction(&$1,$3,$4,&$6,$8, 0);
2661 list_deep_free($6.list);
2664 /* ------------ classes and interfaces (body, slots ) ------- */
2667 static int slotstate_varconst = 0;
2668 static modifiers_t*slotstate_flags = 0;
2669 static void setslotstate(modifiers_t* flags, int varconst)
2671 slotstate_varconst = varconst;
2672 slotstate_flags = flags;
2675 if(flags->flags&FLAG_STATIC) {
2676 state->method = state->cls->static_init;
2678 state->method = state->cls->init;
2681 // reset to "default" state (all in class code is static by default) */
2682 state->method = state->cls->static_init;
2685 parserassert(state->method);
2688 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2690 int flags = modifiers->flags;
2691 namespace_t ns = modifiers2access(modifiers);
2694 multiname_t mname = {QNAME, &ns, 0, name};
2696 trait_list_t**traits;
2700 if(!global->init) global->init = abc_initscript(global->file);
2701 ns.name = state->package;
2702 traits = &global->init->traits;
2703 code = &global->init->method->body->code;
2704 } else if(flags&FLAG_STATIC) {
2706 traits = &state->cls->abc->static_traits;
2707 code = &state->cls->static_init->header;
2709 // instance variable
2710 traits = &state->cls->abc->traits;
2711 code = &state->cls->init->header;
2713 if(ns.access == ACCESS_PROTECTED) {
2714 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2720 *m = *multiname_clone(&mname);
2722 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2726 VARCONST: "var" | "const"
2728 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2730 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2731 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2733 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2736 int flags = slotstate_flags->flags;
2737 namespace_t ns = modifiers2access(slotstate_flags);
2741 varinfo_t* info = 0;
2743 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2745 check_override(i, flags);
2747 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2749 slotinfo_t*i = registry_find(state->package, $1);
2751 syntaxerror("package %s already contains '%s'", state->package, $1);
2753 if(ns.name && ns.name[0]) {
2754 syntaxerror("namespaces not allowed on package-level variables");
2756 info = varinfo_register_global(ns.access, state->package, $1);
2760 info->flags = flags;
2762 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2766 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2770 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2774 t->type_name = multiname_clone(&m);
2776 info->slot = t->slot_id;
2778 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2779 FIXME: is there a way to use slots and still don't have conflicting overrides?
2781 info->slot = t->slot_id = 0;
2783 constant_t cval = $3->type->eval($3);
2784 if(cval.type!=CONSTANT_UNKNOWN) {
2785 /* compile time constant */
2786 t->value = malloc(sizeof(constant_t));
2787 memcpy(t->value, &cval, sizeof(constant_t));
2788 info->value = constant_clone(t->value);
2790 typedcode_t v = node_read($3);
2791 /* initalization code (if needed) */
2793 if(v.c && !is_pushundefined(v.c)) {
2794 c = abc_getlocal_0(c);
2795 c = code_append(c, v.c);
2796 c = converttype(c, v.t, $2);
2798 c = abc_initproperty2(c, &mname);
2800 c = abc_setslot(c, t->slot_id);
2803 *code = code_append(*code, c);
2806 if(slotstate_varconst==KW_CONST) {
2807 t->kind= TRAIT_CONST;
2808 info->flags |= FLAG_CONST;
2815 /* ------------ constants -------------------------------------- */
2817 MAYBECONSTANT: {$$=0;}
2818 MAYBECONSTANT: '=' E {
2819 $$ = malloc(sizeof(constant_t));
2820 *$$ = node_eval($2);
2821 if($$->type == CONSTANT_UNKNOWN) {
2822 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2826 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2827 CONSTANT : T_INT {$$ = constant_new_int($1);}
2829 $$ = constant_new_uint($1);
2831 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2832 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2833 CONSTANT : "true" {$$ = constant_new_true($1);}
2834 CONSTANT : "false" {$$ = constant_new_false($1);}
2835 CONSTANT : "null" {$$ = constant_new_null($1);}
2836 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2837 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2839 /*CONSTANT : T_NAMESPACE {
2841 $$ = constant_new_namespace(namespace_new_namespace($1.url));
2844 /* ---------------------------xml ------------------------------ */
2847 static int xml_level = 0;
2851 multiname_t m = {QNAME, &stdns, 0, "XML"};
2854 v.c = abc_getlex2(v.c, &m);
2855 v.c = code_append(v.c, node_read($1).c);
2856 v.c = abc_construct(v.c, 1);
2861 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2862 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2863 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2865 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2868 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2871 XMLTEXT : {$$=mkstringnode("");}
2872 XMLTEXT : XMLTEXT XMLEXPR1 {
2873 $$ = mkaddnode($1,$2);
2875 XMLTEXT : XMLTEXT T_STRING {
2876 char* str = string_cstr(&$2);
2877 $$ = mkaddnode($1,mkstringnode(str));
2880 XMLTEXT : XMLTEXT '>' {
2881 $$ = mkaddnode($1, mkstringnode(">"));
2883 XML2 : XMLNODE XMLTEXT {
2884 $$ = mkaddnode($1,$2);
2886 XML2 : XML2 XMLNODE XMLTEXT {
2887 $$ = mkaddnode($1, mkaddnode($2,$3));
2889 XML_ID_OR_EXPR: T_IDENTIFIER {
2890 $$ = mkstringnode($1);
2892 XML_ID_OR_EXPR: XMLEXPR2 {
2896 MAYBE_XMLATTRIBUTES: {
2897 $$ = mkstringnode("");
2899 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {
2900 $$ = mkaddnode(mkstringnode(" "),$1);
2903 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2904 //$$ = allocprintf("<%s%s/>", $2, $3, $5, $8);
2905 $$ = mkaddnode(mkaddnode(mkaddnode(mkstringnode("<"),$2),$3),mkstringnode("/>"));
2907 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2908 //$$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2909 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2910 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),mkstringnode("</")),$8),mkstringnode(">"));
2912 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2913 //$$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2914 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2915 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),$6),mkstringnode("</")),$9),mkstringnode(">"));
2918 XMLATTRIBUTES: XMLATTRIBUTE {
2921 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {
2922 $$ = mkaddnode($1, mkaddnode(mkstringnode(" "),$2));
2924 XMLATTRIBUTE: XMLEXPR2 {
2927 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2928 char* str = string_cstr(&$3);
2929 $$ = mkaddnode($1, mkstringnode(concat2("=",str)));
2932 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2933 $$ = mkaddnode($1, mkaddnode(mkstringnode("=\""), mkaddnode($3, mkstringnode("\""))));
2935 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2936 $$ = mkaddnode(mkaddnode(mkstringnode(concat2($1,"=\"")), $3), mkstringnode("\""));
2938 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2939 char* str = string_cstr(&$3);
2940 $$=mkstringnode(allocprintf("%s=%s", $1,str));
2942 free($1);free((char*)$3.str);
2945 /* ------------ classes and interfaces (body, functions) ------- */
2947 // non-vararg version
2950 memset(&$$,0,sizeof($$));
2952 MAYBE_PARAM_LIST: PARAM_LIST {
2958 MAYBE_PARAM_LIST: "..." PARAM {
2960 memset(&$$,0,sizeof($$));
2962 list_append($$.list, $2);
2964 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2968 list_append($$.list, $4);
2972 PARAM_LIST: PARAM_LIST ',' PARAM {
2975 list_append($$.list, $3);
2979 memset(&$$,0,sizeof($$));
2980 list_append($$.list, $1);
2983 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2985 $$ = rfx_calloc(sizeof(param_t));
2991 PARAM: T_IDENTIFIER MAYBECONSTANT {
2993 $$ = rfx_calloc(sizeof(param_t));
2995 $$->type = TYPE_ANY;
3003 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
3004 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
3007 endfunction(&$1,$3,$4,&$6,0,0);
3009 if(!state->method->info) syntaxerror("internal error");
3011 code_t*c = method_header(state->method);
3012 c = wrap_function(c, 0, $11);
3014 endfunction(&$1,$3,$4,&$6,$8,c);
3016 list_deep_free($6.list);
3020 MAYBE_IDENTIFIER: T_IDENTIFIER
3021 MAYBE_IDENTIFIER: {PASS12 $$=0;}
3022 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
3023 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
3026 endfunction(0,0,$2,&$4,0,0);
3028 methodinfo_t*f = state->method->info;
3029 if(!f || !f->kind) syntaxerror("internal error");
3031 code_t*c = method_header(state->method);
3032 c = wrap_function(c, 0, $9);
3034 int index = state->method->var_index;
3035 endfunction(0,0,$2,&$4,$6,c);
3037 $$.c = abc_getlocal(0, index);
3038 $$.t = TYPE_FUNCTION(f);
3040 PASS12 list_deep_free($4.list);
3044 /* ------------- package + class ids --------------- */
3046 CLASS: X_IDENTIFIER {
3047 PASS1 NEW(unresolvedinfo_t,c);
3048 memset(c, 0, sizeof(*c));
3049 c->kind = INFOTYPE_UNRESOLVED;
3051 c->package = get_package_from_name($1);
3053 c->nsset = get_current_imports();
3054 /* make the compiler look for this class in the current directory,
3056 as3_schedule_class_noerror(state->package, $1);
3058 $$ = (classinfo_t*)c;
3060 slotinfo_t*s = find_class($1);
3061 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
3062 $$ = (classinfo_t*)s;
3065 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
3066 PASS1 NEW(unresolvedinfo_t,c);
3067 memset(c, 0, sizeof(*c));
3068 c->kind = INFOTYPE_UNRESOLVED;
3071 $$ = (classinfo_t*)c;
3073 slotinfo_t*s = registry_find($1, $3);
3074 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
3076 $$ = (classinfo_t*)s;
3079 CLASS_SPEC: PACKAGEANDCLASS
3082 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
3083 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
3085 TYPE : CLASS_SPEC {PASS12 $$=$1;}
3086 | '*' {PASS12 $$=TYPE_ANY;}
3087 | "void" {PASS12 $$=TYPE_VOID;}
3089 | "String" {$$=registry_getstringclass();}
3090 | "int" {$$=registry_getintclass();}
3091 | "uint" {$$=registry_getuintclass();}
3092 | "Boolean" {$$=registry_getbooleanclass();}
3093 | "Number" {$$=registry_getnumberclass();}
3096 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
3097 MAYBETYPE: {PASS12 $$=0;}
3099 /* ----------function calls, delete, constructor calls ------ */
3101 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3102 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3104 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3105 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3106 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3108 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3112 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3113 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3114 $$.number= $1.number+1;
3115 $$.cc = code_append($1.cc, $2.c);
3119 NEW : "new" E XX MAYBE_PARAM_VALUES {
3120 typedcode_t v = node_read($2);
3122 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3124 code_t*paramcode = $4.cc;
3125 if($$.c->opcode == OPCODE_GETPROPERTY) {
3126 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3127 $$.c = code_cutlast($$.c);
3128 $$.c = code_append($$.c, paramcode);
3129 $$.c = abc_constructprop2($$.c, name, $4.number);
3130 multiname_destroy(name);
3131 } else if(is_getlocal($$.c)) {
3132 $$.c = code_append($$.c, paramcode);
3133 $$.c = abc_construct($$.c, $4.number);
3134 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3136 classinfo_t*c = v.t->data;
3138 $$.c = abc_findpropstrict2(0, &m);
3139 $$.c = code_append($$.c, paramcode);
3140 $$.c = abc_constructprop2($$.c, &m, $4.number);
3141 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3142 int slot = (int)(ptroff_t)$$.c->data[0];
3143 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3144 multiname_t*name = t->name;
3145 $$.c = code_cutlast($$.c);
3146 $$.c = code_append($$.c, paramcode);
3147 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3149 $$.c = code_append($$.c, paramcode);
3150 $$.c = abc_construct($$.c, $4.number);
3154 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3157 $$.c = abc_coerce_a($$.c);
3162 /* TODO: use abc_call (for calling local variables),
3163 abc_callstatic (for calling own methods)
3166 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3168 typedcode_t v = node_read($1);
3170 if($$.c->opcode == OPCODE_COERCE_A) {
3171 $$.c = code_cutlast($$.c);
3173 code_t*paramcode = $3.cc;
3176 if($$.c->opcode == OPCODE_GETPROPERTY) {
3177 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3178 $$.c = code_cutlast($$.c);
3179 $$.c = code_append($$.c, paramcode);
3180 $$.c = abc_callproperty2($$.c, name, $3.number);
3181 multiname_destroy(name);
3182 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3183 int slot = (int)(ptroff_t)$$.c->data[0];
3184 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3185 if(t->kind!=TRAIT_METHOD) {
3186 //ok: flash allows to assign closures to members.
3188 multiname_t*name = t->name;
3189 $$.c = code_cutlast($$.c);
3190 $$.c = code_append($$.c, paramcode);
3191 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3192 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3193 } else if($$.c->opcode == OPCODE_GETSUPER) {
3194 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3195 $$.c = code_cutlast($$.c);
3196 $$.c = code_append($$.c, paramcode);
3197 $$.c = abc_callsuper2($$.c, name, $3.number);
3198 multiname_destroy(name);
3200 $$.c = abc_getglobalscope($$.c);
3201 $$.c = code_append($$.c, paramcode);
3202 $$.c = abc_call($$.c, $3.number);
3205 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3206 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3207 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3208 // calling a class is like a typecast
3209 $$.t = (classinfo_t*)v.t->data;
3212 $$.c = abc_coerce_a($$.c);
3216 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3217 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3218 if(!state->method) syntaxerror("super() not allowed outside of a function");
3219 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3222 $$.c = abc_getlocal_0($$.c);
3224 $$.c = code_append($$.c, $3.cc);
3226 this is dependent on the control path, check this somewhere else
3227 if(state->method->has_super)
3228 syntaxerror("constructor may call super() only once");
3230 state->method->has_super = 1;
3232 $$.c = abc_constructsuper($$.c, $3.number);
3233 $$.c = abc_pushundefined($$.c);
3237 DELETE: "delete" E {
3238 typedcode_t v = node_read($2);
3240 if($$.c->opcode == OPCODE_COERCE_A) {
3241 $$.c = code_cutlast($$.c);
3243 multiname_t*name = 0;
3244 if($$.c->opcode == OPCODE_GETPROPERTY) {
3245 $$.c->opcode = OPCODE_DELETEPROPERTY;
3246 } else if($$.c->opcode == OPCODE_GETSLOT) {
3247 int slot = (int)(ptroff_t)$$.c->data[0];
3248 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3249 $$.c = code_cutlast($$.c);
3250 $$.c = abc_deleteproperty2($$.c, name);
3252 $$.c = abc_getlocal_0($$.c);
3253 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3254 $$.c = abc_deleteproperty2($$.c, &m);
3256 $$.t = TYPE_BOOLEAN;
3259 RETURN: "return" %prec prec_none {
3260 $$ = abc_returnvoid(0);
3262 RETURN: "return" EXPRESSION {
3264 $$ = abc_returnvalue($$);
3267 // ----------------------- expression types -------------------------------------
3269 NONCOMMAEXPRESSION : E %prec below_lt {
3272 EXPRESSION : COMMA_EXPRESSION {
3275 COMMA_EXPRESSION : E %prec below_lt {
3276 $$ = mkmultinode(&node_comma, $1);
3278 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3279 $$ = multinode_extend($1, $3);
3281 VOIDEXPRESSION : E %prec below_minus {
3284 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3286 $$ = code_append($$, node_exec($3));
3289 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3290 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3292 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3293 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3294 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3295 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3296 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3298 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3300 $$.cc = code_append($$.cc, $1);
3301 $$.cc = code_append($$.cc, $3.c);
3304 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3306 $$.number = $1.number+2;
3307 $$.cc = code_append($$.cc, $3);
3308 $$.cc = code_append($$.cc, $5.c);
3311 // ----------------------- expression evaluation -------------------------------------
3313 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3314 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3315 E : NEW {$$ = mkcodenode($1);}
3316 E : DELETE {$$ = mkcodenode($1);}
3317 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3318 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3321 $$ = mkconstnode($1);
3332 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3334 v.c = abc_getlex2(v.c, &m);
3335 v.c = abc_pushstring(v.c, $1.pattern);
3336 v.c = abc_construct(v.c, 1);
3338 v.c = abc_getlex2(v.c, &m);
3339 v.c = abc_pushstring(v.c, $1.pattern);
3340 v.c = abc_pushstring(v.c, $1.options);
3341 v.c = abc_construct(v.c, 2);
3349 state->method->need_arguments = 1;
3352 v.c = abc_getlocal(0, state->method->need_arguments);
3358 E : '[' MAYBE_EXPRESSION_LIST ']' {
3361 v.c = code_append(v.c, $2.cc);
3362 v.c = abc_newarray(v.c, $2.number);
3363 v.t = registry_getarrayclass();
3368 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3371 v.c = code_append(v.c, $2.cc);
3372 v.c = abc_newobject(v.c, $2.number/2);
3373 v.t = registry_getobjectclass();
3377 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3378 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3379 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3380 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3381 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3382 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3383 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3384 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3385 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3386 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3387 E : '!' E {$$ = mknode1(&node_not, $2);}
3388 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3389 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3390 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3391 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3392 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3393 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3394 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3395 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3396 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3397 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3398 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3399 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3400 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3401 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3402 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3403 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3404 E : "typeof" E {$$ = mknode1(&node_typeof, $2);}
3405 E : "void" E {$$ = mknode1(&node_void, $2);}
3406 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3407 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3408 E : '-' E {$$ = mknode1(&node_neg, $2);}
3409 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3410 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3411 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3412 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3413 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3414 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3415 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3416 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3417 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3418 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3419 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3420 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3421 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3422 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3424 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3425 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3426 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3427 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3429 E : "super" '.' T_IDENTIFIER
3430 { if(!state->cls->info)
3431 syntaxerror("super keyword not allowed outside a class");
3432 classinfo_t*t = state->cls->info->superclass;
3433 if(!t) t = TYPE_OBJECT;
3434 memberinfo_t*f = findmember_nsset(t, $3, 1);
3435 MEMBER_MULTINAME(m, f, $3);
3438 v.c = abc_getlocal_0(v.c);
3439 v.c = abc_getsuper2(v.c, &m);
3440 v.t = slotinfo_gettype((slotinfo_t*)f);
3444 E : '@' T_IDENTIFIER {
3446 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3447 v.c = abc_getlex2(0, &m);
3452 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3455 typedcode_t v = node_read($1);
3456 typedcode_t w = node_read($5);
3458 int index = alloc_local();
3459 int result = alloc_local();
3460 int tmp = alloc_local();
3461 int xml = alloc_local();
3463 c = code_append(c, v.c);
3464 c = abc_checkfilter(c);
3465 c = abc_coerce_a(c); //hasnext2 converts to *
3466 c = abc_setlocal(c, xml);
3467 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3468 c = abc_getlex2(c, &m);
3469 c = abc_construct(c, 0);
3470 c = abc_setlocal(c, result);
3471 c = abc_pushbyte(c, 0);
3472 c = abc_setlocal(c, index);
3473 code_t*jmp = c = abc_jump(c, 0);
3474 code_t*loop = c = abc_label(c);
3475 c = abc_getlocal(c, xml);
3476 c = abc_getlocal(c, index);
3477 c = abc_nextvalue(c);
3479 c = abc_setlocal(c, tmp);
3480 c = abc_pushwith(c);
3481 c = code_append(c, w.c);
3482 c = abc_popscope(c);
3483 code_t*b = c = abc_iffalse(c, 0);
3484 c = abc_getlocal(c, result);
3485 c = abc_getlocal(c, index);
3486 c = abc_getlocal(c, tmp);
3487 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3488 c = abc_setproperty2(c, &m2);
3489 c = b->branch = jmp->branch = abc_nop(c);
3490 c = abc_kill(c, tmp);
3491 c = abc_hasnext2(c, xml, index);
3492 c = abc_iftrue(c, loop);
3493 c = abc_getlocal(c, result);
3494 c = abc_kill(c, xml);
3495 c = abc_kill(c, result);
3496 c = abc_kill(c, index);
3498 c = var_block(c, state->vars);
3506 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3507 ID_OR_NS : '*' {$$="*";}
3508 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3509 SUBNODE: X_IDENTIFIER
3513 MAYBE_NS: T_IDENTIFIER "::" {$$=$1;}
3514 | T_NAMESPACE "::" {$$=(char*)$1;}
3515 | '*' "::" {$$="*";}
3518 E : E '.' ID_OR_NS "::" SUBNODE {
3519 typedcode_t v = node_read($1);
3520 typedcode_t w = node_read(resolve_identifier($3));
3521 v.c = code_append(v.c, w.c);
3522 if(!TYPE_IS_NAMESPACE(w.t)) {
3523 as3_softwarning("%s might not be a namespace", $3);
3525 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3526 multiname_t m = {RTQNAME, 0, 0, $5};
3527 v.c = abc_getproperty2(v.c, &m);
3528 if(TYPE_IS_XML(v.t)) {
3531 v.c = abc_coerce_a(v.c);
3536 E : E ".." SUBNODE {
3537 typedcode_t v = node_read($1);
3538 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3539 v.c = abc_getdescendants2(v.c, &m);
3543 E : E '.' '[' E ']' {
3544 typedcode_t v = node_read($1);
3545 typedcode_t w = node_read($4);
3546 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3547 v.c = code_append(v.c, w.c);
3548 v.c = converttype(w.c, w.t, TYPE_STRING);
3549 v.c = abc_getproperty2(v.c, &m);
3554 E : E '.' '@' SUBNODE {
3555 typedcode_t v = node_read($1);
3556 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3557 v.c = abc_getproperty2(v.c, &m);
3561 E : E ".." '@' SUBNODE {
3562 typedcode_t v = node_read($1);
3563 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3564 v.c = abc_getdescendants2(v.c, &m);
3568 E : E '.' '@' '[' E ']' {
3569 typedcode_t v = node_read($1);
3570 typedcode_t w = node_read($5);
3571 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3572 v.c = code_append(v.c, w.c);
3573 v.c = converttype(w.c, w.t, TYPE_STRING);
3574 v.c = abc_getproperty2(v.c, &m);
3578 E : E ".." '@' '[' E ']' {
3579 typedcode_t v = node_read($1);
3580 typedcode_t w = node_read($5);
3581 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3582 v.c = code_append(v.c, w.c);
3583 v.c = converttype(w.c, w.t, TYPE_STRING);
3584 v.c = abc_getdescendants2(v.c, &m);
3589 MEMBER : E '.' SUBNODE {
3590 typedcode_t v1 = node_read($1);
3592 classinfo_t*t = v1.t;
3594 if(TYPE_IS_CLASS(t) && t->data) {
3598 if(TYPE_IS_XML(t)) {
3599 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3600 $$.c = abc_getproperty2($$.c, &m);
3601 $$.c = abc_coerce_a($$.c);
3602 $$.t = TYPE_XMLLIST;
3604 if(t->subtype==INFOTYPE_UNRESOLVED) {
3605 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3607 memberinfo_t*f = findmember_nsset(t, $3, 1);
3609 if(f && !is_static != !(f->flags&FLAG_STATIC))
3611 if(f && f->slot && !noslot) {
3612 $$.c = abc_getslot($$.c, f->slot);
3615 if(!TYPE_IS_XMLLIST(t)) {
3616 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3619 MEMBER_MULTINAME(m, f, $3);
3620 $$.c = abc_getproperty2($$.c, &m);
3622 /* determine type */
3623 $$.t = slotinfo_gettype((slotinfo_t*)f);
3625 $$.c = abc_coerce_a($$.c);
3627 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3628 string_t*package = v1.c->data[0];
3629 char*package2 = concat3(package->str, ".", $3);
3631 slotinfo_t*a = registry_find(package->str, $3);
3634 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3635 registry_ispackage(package2)) {
3637 $$.c->data[0] = string_new4(package2);
3640 syntaxerror("couldn't resolve %s", package2);
3643 /* when resolving a property on an unknown type, we do know the
3644 name of the property (and don't seem to need the package), but
3645 we need to make avm2 try out all access modes */
3646 as3_softwarning("Resolving %s on unknown type", $3);
3647 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3648 $$.c = abc_getproperty2($$.c, &m);
3649 $$.c = abc_coerce_a($$.c);
3655 node_t* var_read(variable_t*v)
3658 o.c = abc_getlocal(0, v->index);
3660 return mkcodenode(o);
3663 node_t* resolve_identifier(char*name)
3673 /* look at variables */
3674 if((v = find_variable(state, name))) {
3675 // name is a local variable
3678 if((v = find_slot(state->method, name))) {
3679 o.c = abc_getscopeobject(o.c, 1);
3680 o.c = abc_getslot(o.c, v->index);
3682 return mkcodenode(o);
3685 int i_am_static = state->method->is_static;
3687 /* look at current class' members */
3688 if(!state->method->inner &&
3689 !state->xmlfilter &&
3691 (f = findmember_nsset(state->cls->info, name, 1)))
3693 // name is a member or attribute in this class
3694 int var_is_static = (f->flags&FLAG_STATIC);
3696 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3697 /* if the variable is a constant (and we know what is evaluates to), we
3698 can just use the value itself */
3699 varinfo_t*v = (varinfo_t*)f;
3701 return mkconstnode(v->value);
3705 if(var_is_static >= i_am_static) {
3706 if(f->kind == INFOTYPE_METHOD) {
3707 o.t = TYPE_FUNCTION(f);
3712 if(var_is_static && !i_am_static) {
3713 /* access to a static member from a non-static location.
3714 do this via findpropstrict:
3715 there doesn't seem to be any non-lookup way to access
3716 static properties of a class */
3717 state->method->late_binding = 1;
3719 namespace_t ns = {f->access, f->package};
3720 multiname_t m = {QNAME, &ns, 0, name};
3721 o.c = abc_findpropstrict2(o.c, &m);
3722 o.c = abc_getproperty2(o.c, &m);
3723 return mkcodenode(o);
3724 } else if(f->slot>0) {
3725 o.c = abc_getlocal_0(o.c);
3726 o.c = abc_getslot(o.c, f->slot);
3727 return mkcodenode(o);
3729 MEMBER_MULTINAME(m, f, name);
3730 o.c = abc_getlocal_0(o.c);
3731 o.c = abc_getproperty2(o.c, &m);
3732 return mkcodenode(o);
3737 /* look at actual classes, in the current package and imported */
3738 if(!state->xmlfilter && (a = find_class(name))) {
3739 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3740 o.c = abc_getlocal_0(0);
3741 o.t = TYPE_CLASS((classinfo_t*)a);
3745 return mkcodenode(o);
3748 /* look through package prefixes */
3749 if(!state->xmlfilter &&
3750 (dict_contains(state->import_toplevel_packages, name) ||
3751 registry_ispackage(name))) {
3752 o.c = abc___pushpackage__(o.c, name);
3754 return mkcodenode(o); //?
3757 /* unknown object, let the avm2 resolve it */
3759 if(!state->method->inner && !state->xmlfilter) {
3760 /* we really should make inner functions aware of the class context */
3761 as3_warning("Couldn't resolve '%s', doing late binding", name);
3763 state->method->late_binding = 1;
3765 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3768 o.c = abc_findpropstrict2(o.c, &m);
3769 o.c = abc_getproperty2(o.c, &m);
3770 return mkcodenode(o);
3775 /* TODO: causes 16 r/r conflicts */
3776 VAR_READ : T_NAMESPACE {
3778 $$ = resolve_identifier($1);
3780 VAR_READ : T_IDENTIFIER {
3782 /* Queue unresolved identifiers for checking against the parent
3783 function's variables.
3784 We consider everything which is not a local variable "unresolved".
3785 This encompasses class names, members of the surrounding class
3786 etc. which is *correct* because local variables of the parent function
3790 if(!find_variable(state, $1)) {
3791 unknown_variable($1);
3792 /* let the compiler know that it might want to check the current directory/package
3793 for this identifier- maybe there's a file $1.as defining $1. */
3794 as3_schedule_class_noerror(state->package, $1);
3800 $$ = resolve_identifier($1);
3803 // ----------------- namespaces -------------------------------------------------
3806 void add_active_url(const char*url)
3810 list_append(state->active_namespace_urls, n);
3814 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3816 NEW(namespace_decl_t,n);
3821 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3823 NEW(namespace_decl_t,n);
3828 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3830 NEW(namespace_decl_t,n);
3835 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3837 trie_put(active_namespaces, (unsigned char*)$2->name, (void*)$2->url);
3839 namespace_t access = modifiers2access(&$1);
3840 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3841 var->type = TYPE_NAMESPACE;
3843 ns.access = ACCESS_NAMESPACE;
3845 var->value = constant_new_namespace(&ns);
3848 MULTINAME(m, TYPE_NAMESPACE);
3849 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3850 t->value = var->value;
3851 t->type_name = multiname_clone(&m);
3857 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3859 as3_warning("default xml namespaces not supported yet");
3863 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3865 const char*url = $3->name;
3867 varinfo_t*s = (varinfo_t*)$3;
3868 if(s->kind == INFOTYPE_UNRESOLVED) {
3869 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3871 syntaxerror("Couldn't resolve namespace %s", $3->name);
3874 if(!s || s->kind != INFOTYPE_VAR)
3875 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3876 if(!s->value || !NS_TYPE(s->value->type))
3877 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3878 url = s->value->ns->name;
3880 trie_put(active_namespaces, (unsigned char*)$3->name, (void*)url);
3881 add_active_url(url);