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, const 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, char is_static)
950 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse, is_static);
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 && !((flags^m->flags)&FLAG_STATIC))
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, mod->flags&FLAG_STATIC);
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, mod->flags&FLAG_STATIC);
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, mod->flags&FLAG_STATIC);
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, mod->flags&FLAG_STATIC);
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, mod->flags&FLAG_STATIC);
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 compatibility 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))
1688 as3_error("can't convert type %s%s%s to %s%s%s",
1689 from->package, from->package[0]?".":"", from->name,
1690 to->package, to->package[0]?".":"", to->name);
1694 code_t* coerce_to_type(code_t*c, classinfo_t*t)
1697 return abc_coerce_a(c);
1698 } else if(TYPE_IS_STRING(t)) {
1699 return abc_coerce_s(c);
1702 return abc_coerce2(c, &m);
1706 char is_pushundefined(code_t*c)
1708 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1711 static const char* get_package_from_name(const char*name)
1713 /* try explicit imports */
1714 dictentry_t* e = dict_get_slot(state->imports, name);
1716 if(!strcmp(e->key, name)) {
1717 slotinfo_t*c = (slotinfo_t*)e->data;
1718 if(c) return c->package;
1724 static namespace_list_t*get_current_imports()
1726 namespace_list_t*searchlist = 0;
1728 list_append(searchlist, namespace_new_package(state->package));
1730 import_list_t*l = state->wildcard_imports;
1732 namespace_t*ns = namespace_new_package(l->import->package);
1733 list_append(searchlist, ns);
1736 list_append(searchlist, namespace_new_package(""));
1737 list_append(searchlist, namespace_new_package(internal_filename_package));
1741 static slotinfo_t* find_class(const char*name)
1745 c = registry_find(state->package, name);
1748 /* try explicit imports */
1749 dictentry_t* e = dict_get_slot(state->imports, name);
1752 if(!strcmp(e->key, name)) {
1753 c = (slotinfo_t*)e->data;
1759 /* try package.* imports */
1760 import_list_t*l = state->wildcard_imports;
1762 //printf("does package %s contain a class %s?\n", l->import->package, name);
1763 c = registry_find(l->import->package, name);
1768 /* try global package */
1769 c = registry_find("", name);
1772 /* try local "filename" package */
1773 c = registry_find(internal_filename_package, name);
1778 typedcode_t push_class(slotinfo_t*a)
1783 if(a->access == ACCESS_PACKAGEINTERNAL &&
1784 strcmp(a->package, state->package) &&
1785 strcmp(a->package, internal_filename_package)
1787 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1788 infotypename(a), a->name, a->package, state->package);
1792 if(a->kind != INFOTYPE_CLASS) {
1794 x.c = abc_findpropstrict2(x.c, &m);
1795 x.c = abc_getproperty2(x.c, &m);
1796 if(a->kind == INFOTYPE_METHOD) {
1797 methodinfo_t*f = (methodinfo_t*)a;
1798 x.t = TYPE_FUNCTION(f);
1800 varinfo_t*v = (varinfo_t*)a;
1805 if(state->cls && state->method == state->cls->static_init) {
1806 /* we're in the static initializer.
1807 record the fact that we're using this class here */
1808 parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
1810 classinfo_t*c = (classinfo_t*)a;
1812 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1813 x.c = abc_getglobalscope(x.c);
1814 x.c = abc_getslot(x.c, c->slot);
1817 x.c = abc_getlex2(x.c, &m);
1819 x.t = TYPE_CLASS(c);
1825 char is_break_or_jump(code_t*c)
1829 if(c->opcode == OPCODE_JUMP ||
1830 c->opcode == OPCODE___BREAK__ ||
1831 c->opcode == OPCODE___CONTINUE__ ||
1832 c->opcode == OPCODE_THROW ||
1833 c->opcode == OPCODE_RETURNVOID ||
1834 c->opcode == OPCODE_RETURNVALUE) {
1840 #define IS_FINALLY_TARGET(op) \
1841 ((op) == OPCODE___CONTINUE__ || \
1842 (op) == OPCODE___BREAK__ || \
1843 (op) == OPCODE_RETURNVOID || \
1844 (op) == OPCODE_RETURNVALUE || \
1845 (op) == OPCODE___RETHROW__)
1847 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1849 #define NEED_EXTRA_STACK_ARG
1850 code_t*finally_label = abc_nop(0);
1851 NEW(lookupswitch_t, l);
1857 code_t*prev = i->prev;
1858 if(IS_FINALLY_TARGET(i->opcode)) {
1861 if(i->opcode == OPCODE___RETHROW__ ||
1862 i->opcode == OPCODE_RETURNVALUE) {
1863 if(i->opcode == OPCODE___RETHROW__)
1864 i->opcode = OPCODE_THROW;
1866 p = abc_coerce_a(p);
1867 p = abc_setlocal(p, tempvar);
1869 p = abc_pushbyte(p, count++);
1870 p = abc_jump(p, finally_label);
1871 code_t*target = p = abc_label(p);
1872 #ifdef NEED_EXTRA_STACK_ARG
1876 p = abc_getlocal(p, tempvar);
1879 p->next = i;i->prev = p;
1880 list_append(l->targets, target);
1886 c = abc_pushbyte(c, -1);
1887 c = code_append(c, finally_label);
1888 c = code_append(c, finally);
1890 #ifdef NEED_EXTRA_STACK_ARG
1893 c = abc_lookupswitch(c, l);
1894 c = l->def = abc_label(c);
1895 #ifdef NEED_EXTRA_STACK_ARG
1902 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1906 code_t*prev = i->prev;
1907 if(IS_FINALLY_TARGET(i->opcode)) {
1908 if(i->opcode == OPCODE___RETHROW__)
1909 i->opcode = OPCODE_THROW;
1910 code_t*end = code_dup(finally);
1911 code_t*start = code_start(end);
1912 if(prev) prev->next = start;
1919 return code_append(c, finally);
1922 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1928 int num_insertion_points=0;
1930 if(IS_FINALLY_TARGET(i->opcode))
1931 num_insertion_points++;
1938 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1943 int simple_version_cost = (1+num_insertion_points)*code_size;
1944 int lookup_version_cost = 4*num_insertion_points + 5;
1946 if(cantdup || simple_version_cost > lookup_version_cost) {
1947 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1948 return insert_finally_lookup(c, finally, tempvar);
1950 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1951 return insert_finally_simple(c, finally, tempvar);
1955 #define PASS1 }} if(as3_pass == 1) {{
1956 #define PASS1END }} if(as3_pass == 2) {{
1957 #define PASS2 }} if(as3_pass == 2) {{
1958 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1959 #define PASS12END }} if(as3_pass == 2) {{
1960 #define PASS_ALWAYS }} {{
1966 /* ------------ code blocks / statements ---------------- */
1968 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1970 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1971 PROGRAM_CODE_LIST: PROGRAM_CODE
1972 | PROGRAM_CODE_LIST PROGRAM_CODE
1974 PROGRAM_CODE: PACKAGE_DECLARATION
1975 | INTERFACE_DECLARATION
1977 | FUNCTION_DECLARATION
1980 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1983 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1984 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1985 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1987 INPACKAGE_CODE: INTERFACE_DECLARATION
1989 | FUNCTION_DECLARATION
1992 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1993 | '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
1996 MAYBECODE: CODE {$$=$1;}
1997 MAYBECODE: {$$=code_new();}
1999 CODE: CODE CODEPIECE {
2000 $$=code_append($1,$2);
2002 CODE: CODEPIECE {$$=$1;}
2004 // code which may appear outside of methods
2005 CODE_STATEMENT: DEFAULT_NAMESPACE
2006 CODE_STATEMENT: IMPORT
2008 CODE_STATEMENT: FOR_IN
2009 CODE_STATEMENT: WHILE
2010 CODE_STATEMENT: DO_WHILE
2011 CODE_STATEMENT: SWITCH
2013 CODE_STATEMENT: WITH
2015 CODE_STATEMENT: VOIDEXPRESSION
2016 CODE_STATEMENT: USE_NAMESPACE
2017 CODE_STATEMENT: NAMESPACE_DECLARATION
2018 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
2019 CODE_STATEMENT: '{' '}' {$$=0;}
2021 // code which may appear in methods (includes the above)
2022 CODEPIECE: ';' {$$=0;}
2023 CODEPIECE: CODE_STATEMENT
2024 CODEPIECE: VARIABLE_DECLARATION
2029 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
2039 //CODEBLOCK : '{' CODE '}' {$$=$2;}
2040 //CODEBLOCK : '{' '}' {$$=0;}
2041 CODEBLOCK : CODEPIECE ';' {$$=$1;}
2042 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
2044 /* ------------ package init code ------------------- */
2046 PACKAGE_INITCODE: CODE_STATEMENT {
2049 global->init = abc_initscript(global->file);
2050 code_t**cc = &global->init->method->body->code;
2051 *cc = code_append(*cc, $1);
2055 /* ------------ embed code ------------- */
2057 EMBED_START: %prec above_function {
2063 /* ------------ conditional compilation ------------- */
2065 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
2068 char*key = concat3($1,"::",$3);
2069 if(!definitions || !dict_contains(definitions, key)) {
2075 /* ------------ variables --------------------------- */
2078 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
2082 char do_init_variable(char*name)
2084 if(!state->method->no_variable_scoping)
2086 if(!state->new_vars)
2092 MAYBEEXPRESSION : '=' E {$$=$2;}
2093 | {$$=mkdummynode();}
2095 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2096 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2098 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2099 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2101 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2104 if(variable_exists($1))
2105 syntaxerror("Variable %s already defined", $1);
2107 new_variable(state->method, $1, 0, 1, 0);
2113 if(state->method->uses_slots) {
2114 v = find_slot(state->method, $1);
2116 // this variable is stored in a slot
2123 v = new_variable2(state->method, $1, $2, 1, 0);
2126 $$ = slot?abc_getscopeobject(0, 1):0;
2128 typedcode_t val = node_read($3);
2129 if(!is_subtype_of(val.t, $2)) {
2130 syntaxerror("Can't convert %s to %s", val.t->name, $2->name);
2133 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2134 $$ = code_append($$, val.c);
2135 $$ = converttype($$, val.t, $2);
2138 $$ = defaultvalue($$, $2);
2141 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2142 $$ = code_append($$, val.c);
2143 $$ = abc_coerce_a($$);
2145 // don't do anything
2153 $$ = abc_setslot($$, v->index);
2155 $$ = abc_setlocal($$, v->index);
2156 v->init = do_init_variable($1);
2160 /* ------------ control flow ------------------------- */
2162 IF_CODEBLOCK: {PASS12 new_state();} CODEBLOCK {
2163 $$ = var_block($2, state->vars);
2166 MAYBEELSE: %prec below_else {$$ = code_new();}
2167 MAYBEELSE: "else" IF_CODEBLOCK {$$=$2;}
2168 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2170 IF : "if" '(' EXPRESSION ')' IF_CODEBLOCK MAYBEELSE {
2172 $$ = code_append($$, $3.c);
2173 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2175 $$ = code_append($$, $5);
2177 myjmp = $$ = abc_jump($$, 0);
2179 myif->branch = $$ = abc_nop($$);
2181 $$ = code_append($$, $6);
2182 myjmp->branch = $$ = abc_nop($$);
2186 FOR_INIT : {$$=code_new();}
2187 FOR_INIT : VARIABLE_DECLARATION
2188 FOR_INIT : VOIDEXPRESSION
2190 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2191 // (I don't see any easy way to revolve this conflict otherwise, as we
2192 // can't touch VAR_READ without upsetting the precedence about "return")
2193 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2194 PASS1 $$=$2;new_variable(state->method, $2,0,1,0);
2195 PASS2 $$=$2;new_variable(state->method, $2,$3,1,0);
2197 FOR_IN_INIT : T_IDENTIFIER {
2202 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2203 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2205 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' IF_CODEBLOCK {
2206 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2208 $$ = code_append($$, $2);
2209 code_t*loopstart = $$ = abc_label($$);
2210 $$ = code_append($$, $4.c);
2211 code_t*myif = $$ = abc_iffalse($$, 0);
2212 $$ = code_append($$, $8);
2213 code_t*cont = $$ = abc_nop($$);
2214 $$ = code_append($$, $6);
2215 $$ = abc_jump($$, loopstart);
2216 code_t*out = $$ = abc_nop($$);
2217 breakjumpsto($$, $1.name, out);
2218 continuejumpsto($$, $1.name, cont);
2221 $$ = var_block($$, state->vars);
2225 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' IF_CODEBLOCK {
2226 node_t*n = resolve_identifier($2);
2227 typedcode_t w = node_write(n);
2229 int it = alloc_local();
2230 int array = alloc_local();
2233 $$ = code_append($$, $4.c);
2234 $$ = abc_coerce_a($$);
2235 $$ = abc_setlocal($$, array);
2236 $$ = abc_pushbyte($$, 0);
2237 $$ = abc_setlocal($$, it);
2239 code_t*loopstart = $$ = abc_label($$);
2241 $$ = abc_hasnext2($$, array, it);
2242 code_t*myif = $$ = abc_iffalse($$, 0);
2243 $$ = abc_getlocal($$, array);
2244 $$ = abc_getlocal($$, it);
2246 $$ = abc_nextname($$);
2248 $$ = abc_nextvalue($$);
2250 $$ = converttype($$, 0, w.t);
2251 $$ = code_append($$, w.c);
2253 $$ = code_append($$, $6);
2254 $$ = abc_jump($$, loopstart);
2256 code_t*out = $$ = abc_nop($$);
2257 breakjumpsto($$, $1.name, out);
2258 continuejumpsto($$, $1.name, loopstart);
2262 $$ = abc_kill($$, it);
2263 $$ = abc_kill($$, array);
2265 $$ = var_block($$, state->vars);
2269 WHILE : T_WHILE '(' EXPRESSION ')' IF_CODEBLOCK {
2273 code_t*myjmp = $$ = abc_jump($$, 0);
2274 code_t*loopstart = $$ = abc_label($$);
2275 $$ = code_append($$, $5);
2276 code_t*cont = $$ = abc_nop($$);
2277 myjmp->branch = cont;
2278 $$ = code_append($$, $3.c);
2279 $$ = abc_iftrue($$, loopstart);
2280 code_t*out = $$ = abc_nop($$);
2281 breakjumpsto($$, $1, out);
2282 continuejumpsto($$, $1, cont);
2285 DO_WHILE : T_DO IF_CODEBLOCK "while" '(' EXPRESSION ')' {
2287 code_t*loopstart = $$ = abc_label($$);
2288 $$ = code_append($$, $2);
2289 code_t*cont = $$ = abc_nop($$);
2290 $$ = code_append($$, $5.c);
2291 $$ = abc_iftrue($$, loopstart);
2292 code_t*out = $$ = abc_nop($$);
2293 breakjumpsto($$, $1, out);
2294 continuejumpsto($$, $1, cont);
2297 BREAK : "break" %prec prec_none {
2298 $$ = abc___break__(0, "");
2300 BREAK : "break" T_IDENTIFIER {
2301 $$ = abc___break__(0, $2);
2303 CONTINUE : "continue" %prec prec_none {
2304 $$ = abc___continue__(0, "");
2306 CONTINUE : "continue" T_IDENTIFIER {
2307 $$ = abc___continue__(0, $2);
2310 MAYBE_CASE_LIST : {$$=0;}
2311 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2312 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2313 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2314 CASE_LIST: CASE {$$=$1;}
2315 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2317 CASE: "case" E ':' MAYBECODE {
2318 $$ = abc_getlocal(0, state->switch_var);
2319 $$ = code_append($$, node_read($2).c);
2320 code_t*j = $$ = abc_ifne($$, 0);
2321 $$ = code_append($$, $4);
2322 if($$->opcode != OPCODE___BREAK__) {
2323 $$ = abc___fallthrough__($$, "");
2325 code_t*e = $$ = abc_nop($$);
2328 DEFAULT: "default" ':' MAYBECODE {
2331 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2332 $$ = node_read($4).c;
2333 $$ = abc_setlocal($$, state->switch_var);
2334 $$ = code_append($$, $7);
2336 code_t*out = $$ = abc_kill($$, state->switch_var);
2337 breakjumpsto($$, $1, out);
2339 code_t*c = $$,*lastblock=0;
2341 if(c->opcode == OPCODE_IFNE) {
2342 if(!c->next) syntaxerror("internal error in fallthrough handling");
2344 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2346 c->opcode = OPCODE_JUMP;
2347 c->branch = lastblock;
2349 /* fall through end of switch */
2350 c->opcode = OPCODE_NOP;
2356 $$ = var_block($$, state->vars);
2360 /* ------------ try / catch /finally ---------------- */
2362 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2363 state->exception_name=$3;
2364 PASS1 new_variable(state->method, $3, 0, 0, 0);
2365 PASS2 new_variable(state->method, $3, $4, 0, 0);
2368 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2369 multiname_t name = {QNAME, &name_ns, 0, $3};
2371 NEW(abc_exception_t, e)
2372 e->exc_type = sig2mname($4);
2373 e->var_name = multiname_clone(&name);
2377 int i = find_variable_safe(state, $3)->index;
2378 e->target = c = abc_nop(0);
2379 c = abc_setlocal(c, i);
2380 c = code_append(c, code_dup(state->method->scope_code));
2381 c = code_append(c, $8);
2384 c = var_block(c, state->vars);
2387 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2388 $4 = var_block($4, state->vars);
2392 NEW(abc_exception_t, e)
2393 e->exc_type = 0; //all exceptions
2394 e->var_name = 0; //no name
2397 e->to = code_append(e->to, $4);
2403 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2404 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2405 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2406 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2410 list_append($$.l,$2);
2411 $$.finally = $2->to;$2->to=0;
2414 CATCH_FINALLY_LIST: FINALLY {
2418 list_append($$.l,$1);
2419 $$.finally = $1->to;$1->to=0;
2423 TRY : "try" '{' {PASS12 new_state();
2424 state->method->has_exceptions=1;
2425 state->method->late_binding=1;//for invariant scope_code
2426 } MAYBECODE '}' CATCH_FINALLY_LIST {
2427 code_t*out = abc_nop(0);
2429 code_t*start = abc_nop(0);
2430 $$ = code_append(start, $4);
2431 if(!is_break_or_jump($4)) {
2432 $$ = abc_jump($$, out);
2434 code_t*end = $$ = abc_nop($$);
2438 tmp = alloc_local();
2440 abc_exception_list_t*l = $6.l;
2443 abc_exception_t*e = l->abc_exception;
2445 $$ = code_append($$, e->target);
2446 $$ = abc_jump($$, out);
2448 parserassert((ptroff_t)$6.finally);
2450 e->target = $$ = abc_nop($$);
2451 $$ = code_append($$, code_dup(state->method->scope_code));
2452 $$ = abc___rethrow__($$);
2460 $$ = code_append($$, out);
2462 $$ = insert_finally($$, $6.finally, tmp);
2464 list_concat(state->method->exceptions, $6.l);
2466 $$ = var_block($$, state->vars);
2470 /* ------------ throw ------------------------------- */
2472 THROW : "throw" EXPRESSION {
2476 THROW : "throw" %prec prec_none {
2477 if(!state->exception_name)
2478 syntaxerror("re-throw only possible within a catch block");
2479 variable_t*v = find_variable(state, state->exception_name);
2481 $$=abc_getlocal($$, v->index);
2485 /* ------------ with -------------------------------- */
2487 WITH_HEAD : "with" '(' EXPRESSION ')' {
2489 if(state->method->has_exceptions) {
2490 int v = alloc_local();
2491 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2492 state->method->scope_code = abc_pushwith(state->method->scope_code);
2497 WITH : WITH_HEAD CODEBLOCK {
2498 /* remove getlocal;pushwith from scope code again */
2499 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2502 if(state->method->has_exceptions) {
2504 $$ = abc_setlocal($$, $1.number);
2506 $$ = abc_pushwith($$);
2507 $$ = code_append($$, $2);
2508 $$ = abc_popscope($$);
2512 /* ------------ packages and imports ---------------- */
2514 X_IDENTIFIER: T_IDENTIFIER
2515 | "package" {PASS12 $$="package";}
2516 | "namespace" {PASS12 $$="namespace";}
2517 | "NaN" {PASS12 $$="NaN";}
2518 | T_NAMESPACE {PASS12 $$=$1;}
2520 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2521 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2523 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2524 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2525 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2526 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2529 static void state_has_imports()
2531 state->wildcard_imports = list_clone(state->wildcard_imports);
2532 state->imports = dict_clone(state->imports);
2533 state->has_own_imports = 1;
2535 static void import_toplevel(const char*package)
2537 char* s = strdup(package);
2539 dict_put(state->import_toplevel_packages, s, 0);
2540 char*x = strrchr(s, '.');
2549 IMPORT : "import" T_IDENTIFIER {
2551 slotinfo_t*s = registry_find(state->package, $2);
2552 if(!s && as3_pass==1) {as3_schedule_class(state->package, $2);}
2553 state_has_imports();
2554 dict_put(state->imports, state->package, $2);
2557 IMPORT : "import" PACKAGEANDCLASS {
2559 slotinfo_t*s = registry_find($2->package, $2->name);
2560 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2561 as3_schedule_class($2->package, $2->name);
2563 state_has_imports();
2564 dict_put(state->imports, $2->name, $2);
2565 import_toplevel($2->package);
2568 IMPORT : "import" PACKAGE '.' '*' {
2570 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2571 as3_schedule_package($2);
2576 state_has_imports();
2577 list_append(state->wildcard_imports, i);
2578 import_toplevel(i->package);
2582 /* ------------ classes and interfaces (header) -------------- */
2584 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2585 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2586 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2587 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2589 $$.flags=$1.flags|$2.flags;
2590 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2591 $$.ns=$1.ns?$1.ns:$2.ns;
2594 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2595 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2596 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2597 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2598 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2599 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2600 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2601 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2602 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2603 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2607 EXTENDS : {PASS12 $$=0;}
2608 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2610 EXTENDS_LIST : {PASS12 $$=list_new();}
2611 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2613 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2614 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2616 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2617 EXTENDS IMPLEMENTS_LIST
2618 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2620 '}' {PASS12 endclass();$$=0;}
2622 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2624 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2625 startclass(&$1,$3,0,$4);}
2626 MAYBE_INTERFACE_BODY
2627 '}' {PASS12 endclass();$$=0;}
2629 /* ------------ classes and interfaces (body) -------------- */
2632 MAYBE_CLASS_BODY : CLASS_BODY
2633 CLASS_BODY : CLASS_BODY_ITEM
2634 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2635 CLASS_BODY_ITEM : ';'
2636 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2637 CLASS_BODY_ITEM : SLOT_DECLARATION
2638 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2639 CLASS_BODY_ITEM : '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
2641 CLASS_BODY_ITEM : CODE_STATEMENT {
2642 code_t*c = state->cls->static_init->header;
2643 c = code_append(c, $1);
2644 state->cls->static_init->header = c;
2647 MAYBE_INTERFACE_BODY :
2648 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2649 INTERFACE_BODY : IDECLARATION
2650 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2652 IDECLARATION : "var" T_IDENTIFIER {
2653 syntaxerror("variable declarations not allowed in interfaces");
2655 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2657 $1.flags |= FLAG_PUBLIC;
2658 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2659 syntaxerror("invalid method modifiers: interface methods always need to be public");
2661 startfunction(&$1,$3,$4,&$6,$8);
2662 endfunction(&$1,$3,$4,&$6,$8, 0);
2663 list_deep_free($6.list);
2666 /* ------------ classes and interfaces (body, slots ) ------- */
2669 static int slotstate_varconst = 0;
2670 static modifiers_t*slotstate_flags = 0;
2671 static void setslotstate(modifiers_t* flags, int varconst)
2673 slotstate_varconst = varconst;
2674 slotstate_flags = flags;
2677 if(flags->flags&FLAG_STATIC) {
2678 state->method = state->cls->static_init;
2680 state->method = state->cls->init;
2683 // reset to "default" state (all in class code is static by default) */
2684 state->method = state->cls->static_init;
2687 parserassert(state->method);
2690 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2692 int flags = modifiers->flags;
2693 namespace_t ns = modifiers2access(modifiers);
2696 multiname_t mname = {QNAME, &ns, 0, name};
2698 trait_list_t**traits;
2702 if(!global->init) global->init = abc_initscript(global->file);
2703 ns.name = state->package;
2704 traits = &global->init->traits;
2705 code = &global->init->method->body->code;
2706 } else if(flags&FLAG_STATIC) {
2708 traits = &state->cls->abc->static_traits;
2709 code = &state->cls->static_init->header;
2711 // instance variable
2712 traits = &state->cls->abc->traits;
2713 code = &state->cls->init->header;
2715 if(ns.access == ACCESS_PROTECTED) {
2716 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2722 *m = *multiname_clone(&mname);
2724 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2728 VARCONST: "var" | "const"
2730 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2732 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2733 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2735 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2738 int flags = slotstate_flags->flags;
2739 namespace_t ns = modifiers2access(slotstate_flags);
2743 varinfo_t* info = 0;
2745 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1, slotstate_flags->flags&FLAG_STATIC);
2747 check_override(i, flags);
2749 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1, slotstate_flags->flags&FLAG_STATIC);
2751 slotinfo_t*i = registry_find(state->package, $1);
2753 syntaxerror("package %s already contains '%s'", state->package, $1);
2755 if(ns.name && ns.name[0]) {
2756 syntaxerror("namespaces not allowed on package-level variables");
2758 info = varinfo_register_global(ns.access, state->package, $1);
2762 info->flags = flags;
2764 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2768 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2772 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2776 t->type_name = multiname_clone(&m);
2778 info->slot = t->slot_id;
2780 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2781 FIXME: is there a way to use slots and still don't have conflicting overrides?
2783 info->slot = t->slot_id = 0;
2785 constant_t cval = $3->type->eval($3);
2786 if(cval.type!=CONSTANT_UNKNOWN) {
2787 /* compile time constant */
2788 t->value = malloc(sizeof(constant_t));
2789 memcpy(t->value, &cval, sizeof(constant_t));
2790 info->value = constant_clone(t->value);
2792 typedcode_t v = node_read($3);
2793 /* initalization code (if needed) */
2795 if(v.c && !is_pushundefined(v.c)) {
2796 c = abc_getlocal_0(c);
2797 c = code_append(c, v.c);
2798 c = converttype(c, v.t, $2);
2800 c = abc_initproperty2(c, &mname);
2802 c = abc_setslot(c, t->slot_id);
2805 *code = code_append(*code, c);
2808 if(slotstate_varconst==KW_CONST) {
2809 t->kind= TRAIT_CONST;
2810 info->flags |= FLAG_CONST;
2817 /* ------------ constants -------------------------------------- */
2819 MAYBECONSTANT: {$$=0;}
2820 MAYBECONSTANT: '=' E {
2821 $$ = malloc(sizeof(constant_t));
2822 *$$ = node_eval($2);
2823 if($$->type == CONSTANT_UNKNOWN) {
2824 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2828 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2829 CONSTANT : T_INT {$$ = constant_new_int($1);}
2831 $$ = constant_new_uint($1);
2833 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2834 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2835 CONSTANT : "true" {$$ = constant_new_true($1);}
2836 CONSTANT : "false" {$$ = constant_new_false($1);}
2837 CONSTANT : "null" {$$ = constant_new_null($1);}
2838 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2839 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2841 /*CONSTANT : T_NAMESPACE {
2843 $$ = constant_new_namespace(namespace_new_namespace($1.url));
2846 /* ---------------------------xml ------------------------------ */
2849 static int xml_level = 0;
2853 multiname_t m = {QNAME, &stdns, 0, "XML"};
2856 v.c = abc_getlex2(v.c, &m);
2857 v.c = code_append(v.c, node_read($1).c);
2858 v.c = abc_construct(v.c, 1);
2863 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2864 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2865 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2867 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2870 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2873 XMLTEXT : {$$=mkstringnode("");}
2874 XMLTEXT : XMLTEXT XMLEXPR1 {
2875 $$ = mkaddnode($1,$2);
2877 XMLTEXT : XMLTEXT T_STRING {
2878 char* str = string_cstr(&$2);
2879 $$ = mkaddnode($1,mkstringnode(str));
2882 XMLTEXT : XMLTEXT '>' {
2883 $$ = mkaddnode($1, mkstringnode(">"));
2885 XML2 : XMLNODE XMLTEXT {
2886 $$ = mkaddnode($1,$2);
2888 XML2 : XML2 XMLNODE XMLTEXT {
2889 $$ = mkaddnode($1, mkaddnode($2,$3));
2891 XML_ID_OR_EXPR: T_IDENTIFIER {
2892 $$ = mkstringnode($1);
2894 XML_ID_OR_EXPR: XMLEXPR2 {
2898 MAYBE_XMLATTRIBUTES: {
2899 $$ = mkstringnode("");
2901 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {
2902 $$ = mkaddnode(mkstringnode(" "),$1);
2905 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2906 //$$ = allocprintf("<%s%s/>", $2, $3, $5, $8);
2907 $$ = mkaddnode(mkaddnode(mkaddnode(mkstringnode("<"),$2),$3),mkstringnode("/>"));
2909 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2910 //$$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2911 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2912 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),mkstringnode("</")),$8),mkstringnode(">"));
2914 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2915 //$$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2916 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2917 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),$6),mkstringnode("</")),$9),mkstringnode(">"));
2920 XMLATTRIBUTES: XMLATTRIBUTE {
2923 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {
2924 $$ = mkaddnode($1, mkaddnode(mkstringnode(" "),$2));
2926 XMLATTRIBUTE: XMLEXPR2 {
2929 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2930 char* str = string_cstr(&$3);
2931 $$ = mkaddnode($1, mkstringnode(concat2("=",str)));
2934 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2935 $$ = mkaddnode($1, mkaddnode(mkstringnode("=\""), mkaddnode($3, mkstringnode("\""))));
2937 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2938 $$ = mkaddnode(mkaddnode(mkstringnode(concat2($1,"=\"")), $3), mkstringnode("\""));
2940 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2941 char* str = string_cstr(&$3);
2942 $$=mkstringnode(allocprintf("%s=%s", $1,str));
2944 free($1);free((char*)$3.str);
2947 /* ------------ classes and interfaces (body, functions) ------- */
2949 // non-vararg version
2952 memset(&$$,0,sizeof($$));
2954 MAYBE_PARAM_LIST: PARAM_LIST {
2960 MAYBE_PARAM_LIST: "..." PARAM {
2962 memset(&$$,0,sizeof($$));
2964 list_append($$.list, $2);
2966 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2970 list_append($$.list, $4);
2974 PARAM_LIST: PARAM_LIST ',' PARAM {
2977 list_append($$.list, $3);
2981 memset(&$$,0,sizeof($$));
2982 list_append($$.list, $1);
2985 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2987 $$ = rfx_calloc(sizeof(param_t));
2993 PARAM: T_IDENTIFIER MAYBECONSTANT {
2995 $$ = rfx_calloc(sizeof(param_t));
2997 $$->type = TYPE_ANY;
3005 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
3006 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
3009 endfunction(&$1,$3,$4,&$6,0,0);
3011 if(!state->method->info) syntaxerror("internal error");
3013 code_t*c = method_header(state->method);
3014 c = wrap_function(c, 0, $11);
3016 endfunction(&$1,$3,$4,&$6,$8,c);
3018 list_deep_free($6.list);
3022 MAYBE_IDENTIFIER: T_IDENTIFIER
3023 MAYBE_IDENTIFIER: {PASS12 $$=0;}
3024 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
3025 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
3028 endfunction(0,0,$2,&$4,0,0);
3030 methodinfo_t*f = state->method->info;
3031 if(!f || !f->kind) syntaxerror("internal error");
3033 code_t*c = method_header(state->method);
3034 c = wrap_function(c, 0, $9);
3036 int index = state->method->var_index;
3037 endfunction(0,0,$2,&$4,$6,c);
3039 $$.c = abc_getlocal(0, index);
3040 $$.t = TYPE_FUNCTION(f);
3042 PASS12 list_deep_free($4.list);
3046 /* ------------- package + class ids --------------- */
3048 CLASS: X_IDENTIFIER {
3049 PASS1 NEW(unresolvedinfo_t,c);
3050 memset(c, 0, sizeof(*c));
3051 c->kind = INFOTYPE_UNRESOLVED;
3053 c->package = get_package_from_name($1);
3055 c->nsset = get_current_imports();
3056 /* make the compiler look for this class in the current directory,
3058 as3_schedule_class_noerror(state->package, $1);
3060 $$ = (classinfo_t*)c;
3062 slotinfo_t*s = find_class($1);
3063 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
3064 $$ = (classinfo_t*)s;
3067 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
3068 PASS1 NEW(unresolvedinfo_t,c);
3069 memset(c, 0, sizeof(*c));
3070 c->kind = INFOTYPE_UNRESOLVED;
3073 $$ = (classinfo_t*)c;
3075 slotinfo_t*s = registry_find($1, $3);
3076 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
3078 $$ = (classinfo_t*)s;
3081 CLASS_SPEC: PACKAGEANDCLASS
3084 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
3085 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
3087 TYPE : CLASS_SPEC {PASS12 $$=$1;}
3088 | '*' {PASS12 $$=TYPE_ANY;}
3089 | "void" {PASS12 $$=TYPE_VOID;}
3091 | "String" {$$=registry_getstringclass();}
3092 | "int" {$$=registry_getintclass();}
3093 | "uint" {$$=registry_getuintclass();}
3094 | "Boolean" {$$=registry_getbooleanclass();}
3095 | "Number" {$$=registry_getnumberclass();}
3098 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
3099 MAYBETYPE: {PASS12 $$=0;}
3101 /* ----------function calls, delete, constructor calls ------ */
3103 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3104 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3106 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3107 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3108 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3110 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3114 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3115 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3116 $$.number= $1.number+1;
3117 $$.cc = code_append($1.cc, $2.c);
3121 NEW : "new" E XX MAYBE_PARAM_VALUES {
3122 typedcode_t v = node_read($2);
3124 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3126 code_t*paramcode = $4.cc;
3127 if($$.c->opcode == OPCODE_GETPROPERTY) {
3128 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3129 $$.c = code_cutlast($$.c);
3130 $$.c = code_append($$.c, paramcode);
3131 $$.c = abc_constructprop2($$.c, name, $4.number);
3132 multiname_destroy(name);
3133 } else if(is_getlocal($$.c)) {
3134 $$.c = code_append($$.c, paramcode);
3135 $$.c = abc_construct($$.c, $4.number);
3136 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3138 classinfo_t*c = v.t->data;
3140 $$.c = abc_findpropstrict2(0, &m);
3141 $$.c = code_append($$.c, paramcode);
3142 $$.c = abc_constructprop2($$.c, &m, $4.number);
3143 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3144 int slot = (int)(ptroff_t)$$.c->data[0];
3145 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3146 multiname_t*name = t->name;
3147 $$.c = code_cutlast($$.c);
3148 $$.c = code_append($$.c, paramcode);
3149 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3151 $$.c = code_append($$.c, paramcode);
3152 $$.c = abc_construct($$.c, $4.number);
3156 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3159 $$.c = abc_coerce_a($$.c);
3164 /* TODO: use abc_call (for calling local variables),
3165 abc_callstatic (for calling own methods)
3168 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3170 typedcode_t v = node_read($1);
3172 if($$.c->opcode == OPCODE_COERCE_A) {
3173 $$.c = code_cutlast($$.c);
3175 code_t*paramcode = $3.cc;
3178 if($$.c->opcode == OPCODE_GETPROPERTY) {
3179 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3180 $$.c = code_cutlast($$.c);
3181 $$.c = code_append($$.c, paramcode);
3182 $$.c = abc_callproperty2($$.c, name, $3.number);
3183 multiname_destroy(name);
3184 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3185 int slot = (int)(ptroff_t)$$.c->data[0];
3186 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3187 if(t->kind!=TRAIT_METHOD) {
3188 //ok: flash allows to assign closures to members.
3190 multiname_t*name = t->name;
3191 $$.c = code_cutlast($$.c);
3192 $$.c = code_append($$.c, paramcode);
3193 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3194 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3195 } else if($$.c->opcode == OPCODE_GETSUPER) {
3196 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3197 $$.c = code_cutlast($$.c);
3198 $$.c = code_append($$.c, paramcode);
3199 $$.c = abc_callsuper2($$.c, name, $3.number);
3200 multiname_destroy(name);
3202 $$.c = abc_getglobalscope($$.c);
3203 $$.c = code_append($$.c, paramcode);
3204 $$.c = abc_call($$.c, $3.number);
3207 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3208 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3209 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3210 // calling a class is like a typecast
3211 $$.t = (classinfo_t*)v.t->data;
3214 $$.c = abc_coerce_a($$.c);
3218 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3219 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3220 if(!state->method) syntaxerror("super() not allowed outside of a function");
3221 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3224 $$.c = abc_getlocal_0($$.c);
3226 $$.c = code_append($$.c, $3.cc);
3228 this is dependent on the control path, check this somewhere else
3229 if(state->method->has_super)
3230 syntaxerror("constructor may call super() only once");
3232 state->method->has_super = 1;
3234 $$.c = abc_constructsuper($$.c, $3.number);
3235 $$.c = abc_pushundefined($$.c);
3239 DELETE: "delete" E {
3240 typedcode_t v = node_read($2);
3242 if($$.c->opcode == OPCODE_COERCE_A) {
3243 $$.c = code_cutlast($$.c);
3245 multiname_t*name = 0;
3246 if($$.c->opcode == OPCODE_GETPROPERTY) {
3247 $$.c->opcode = OPCODE_DELETEPROPERTY;
3248 } else if($$.c->opcode == OPCODE_GETSLOT) {
3249 int slot = (int)(ptroff_t)$$.c->data[0];
3250 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3251 $$.c = code_cutlast($$.c);
3252 $$.c = abc_deleteproperty2($$.c, name);
3254 $$.c = abc_getlocal_0($$.c);
3255 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3256 $$.c = abc_deleteproperty2($$.c, &m);
3258 $$.t = TYPE_BOOLEAN;
3261 RETURN: "return" %prec prec_none {
3262 $$ = abc_returnvoid(0);
3264 RETURN: "return" EXPRESSION {
3266 $$ = abc_returnvalue($$);
3269 // ----------------------- expression types -------------------------------------
3271 NONCOMMAEXPRESSION : E %prec below_lt {
3274 EXPRESSION : COMMA_EXPRESSION {
3277 COMMA_EXPRESSION : E %prec below_lt {
3278 $$ = mkmultinode(&node_comma, $1);
3280 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3281 $$ = multinode_extend($1, $3);
3283 VOIDEXPRESSION : E %prec below_minus {
3286 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3288 $$ = code_append($$, node_exec($3));
3291 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3292 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3294 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3295 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3296 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3297 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3298 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3300 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3302 $$.cc = code_append($$.cc, $1);
3303 $$.cc = code_append($$.cc, $3.c);
3306 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3308 $$.number = $1.number+2;
3309 $$.cc = code_append($$.cc, $3);
3310 $$.cc = code_append($$.cc, $5.c);
3313 // ----------------------- expression evaluation -------------------------------------
3315 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3316 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3317 E : NEW {$$ = mkcodenode($1);}
3318 E : DELETE {$$ = mkcodenode($1);}
3319 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3320 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3323 $$ = mkconstnode($1);
3334 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3336 v.c = abc_getlex2(v.c, &m);
3337 v.c = abc_pushstring(v.c, $1.pattern);
3338 v.c = abc_construct(v.c, 1);
3340 v.c = abc_getlex2(v.c, &m);
3341 v.c = abc_pushstring(v.c, $1.pattern);
3342 v.c = abc_pushstring(v.c, $1.options);
3343 v.c = abc_construct(v.c, 2);
3351 state->method->need_arguments = 1;
3354 v.c = abc_getlocal(0, state->method->need_arguments);
3360 E : '[' MAYBE_EXPRESSION_LIST ']' {
3363 v.c = code_append(v.c, $2.cc);
3364 v.c = abc_newarray(v.c, $2.number);
3365 v.t = registry_getarrayclass();
3370 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3373 v.c = code_append(v.c, $2.cc);
3374 v.c = abc_newobject(v.c, $2.number/2);
3375 v.t = registry_getobjectclass();
3379 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3380 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3381 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3382 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3383 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3384 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3385 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3386 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3387 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3388 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3389 E : '!' E {$$ = mknode1(&node_not, $2);}
3390 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3391 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3392 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3393 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3394 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3395 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3396 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3397 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3398 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3399 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3400 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3401 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3402 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3403 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3404 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3405 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3406 E : "typeof" E {$$ = mknode1(&node_typeof, $2);}
3407 E : "void" E {$$ = mknode1(&node_void, $2);}
3408 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3409 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3410 E : '-' E {$$ = mknode1(&node_neg, $2);}
3411 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3412 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3413 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3414 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3415 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3416 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3417 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3418 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3419 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3420 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3421 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3422 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3423 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3424 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3426 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3427 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3428 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3429 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3431 E : "super" '.' T_IDENTIFIER
3432 { if(!state->cls->info)
3433 syntaxerror("super keyword not allowed outside a class");
3434 classinfo_t*t = state->cls->info->superclass;
3435 if(!t) t = TYPE_OBJECT;
3436 memberinfo_t*f = findmember_nsset(t, $3, 1, 0);
3437 MEMBER_MULTINAME(m, f, $3);
3440 v.c = abc_getlocal_0(v.c);
3441 v.c = abc_getsuper2(v.c, &m);
3442 v.t = slotinfo_gettype((slotinfo_t*)f);
3446 E : '@' T_IDENTIFIER {
3448 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3449 v.c = abc_getlex2(0, &m);
3454 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3457 typedcode_t v = node_read($1);
3458 typedcode_t w = node_read($5);
3460 int index = alloc_local();
3461 int result = alloc_local();
3462 int tmp = alloc_local();
3463 int xml = alloc_local();
3465 c = code_append(c, v.c);
3466 c = abc_checkfilter(c);
3467 c = abc_coerce_a(c); //hasnext2 converts to *
3468 c = abc_setlocal(c, xml);
3469 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3470 c = abc_getlex2(c, &m);
3471 c = abc_construct(c, 0);
3472 c = abc_setlocal(c, result);
3473 c = abc_pushbyte(c, 0);
3474 c = abc_setlocal(c, index);
3475 code_t*jmp = c = abc_jump(c, 0);
3476 code_t*loop = c = abc_label(c);
3477 c = abc_getlocal(c, xml);
3478 c = abc_getlocal(c, index);
3479 c = abc_nextvalue(c);
3481 c = abc_setlocal(c, tmp);
3482 c = abc_pushwith(c);
3483 c = code_append(c, w.c);
3484 c = abc_popscope(c);
3485 code_t*b = c = abc_iffalse(c, 0);
3486 c = abc_getlocal(c, result);
3487 c = abc_getlocal(c, index);
3488 c = abc_getlocal(c, tmp);
3489 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3490 c = abc_setproperty2(c, &m2);
3491 c = b->branch = jmp->branch = abc_nop(c);
3492 c = abc_kill(c, tmp);
3493 c = abc_hasnext2(c, xml, index);
3494 c = abc_iftrue(c, loop);
3495 c = abc_getlocal(c, result);
3496 c = abc_kill(c, xml);
3497 c = abc_kill(c, result);
3498 c = abc_kill(c, index);
3500 c = var_block(c, state->vars);
3508 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3509 ID_OR_NS : '*' {$$="*";}
3510 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3511 SUBNODE: X_IDENTIFIER
3515 node_t* resolve_identifier(const char*name);
3516 node_t* get_descendants(node_t*e,const char*ns,const char*subnode,char multi, char attr)
3518 typedcode_t v = node_read(e);
3521 multiname_t m = {0,0,0,subnode};
3522 namespace_t zero = {ZERONAMESPACE,"*"};
3523 if(!strcmp(ns,"*")) {
3525 m.type = attr?QNAMEA:QNAME;
3527 typedcode_t w = node_read(resolve_identifier(ns));
3528 if(!TYPE_IS_NAMESPACE(w.t)) {
3529 as3_softwarning("%s might not be a namespace", ns);
3531 v.c = code_append(v.c, w.c);
3532 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3533 m.type = attr?RTQNAMEA:RTQNAME;
3537 v.c = abc_getproperty2(v.c, &m);
3539 v.c = abc_getdescendants2(v.c, &m);
3542 if(TYPE_IS_XML(v.t)) {
3545 v.c = abc_coerce_a(v.c);
3548 return mkcodenode(v);
3552 E : E '.' ID_OR_NS "::" SUBNODE {
3553 $$ = get_descendants($1, $3, $5, 0, 0);
3555 E : E ".." SUBNODE {
3556 typedcode_t v = node_read($1);
3557 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3558 v.c = abc_getdescendants2(v.c, &m);
3562 E : E ".." ID_OR_NS "::" SUBNODE {
3563 $$ = get_descendants($1, $3, $5, 1, 0);
3565 E : E '.' '[' E ']' {
3566 typedcode_t v = node_read($1);
3567 typedcode_t w = node_read($4);
3568 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3569 v.c = code_append(v.c, w.c);
3570 v.c = converttype(w.c, w.t, TYPE_STRING);
3571 v.c = abc_getproperty2(v.c, &m);
3576 E : E '.' '@' SUBNODE {
3577 typedcode_t v = node_read($1);
3578 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3579 v.c = abc_getproperty2(v.c, &m);
3584 E : E '.' '@' ID_OR_NS "::" SUBNODE {
3585 $$ = get_descendants($1, $4, $6, 0, 1);
3588 E : E ".." '@' SUBNODE {
3589 typedcode_t v = node_read($1);
3590 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3591 v.c = abc_getdescendants2(v.c, &m);
3595 E : E ".." '@' ID_OR_NS "::" SUBNODE {
3596 $$ = get_descendants($1, $4, $6, 1, 1);
3599 E : E '.' '@' '[' E ']' {
3600 typedcode_t v = node_read($1);
3601 typedcode_t w = node_read($5);
3602 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3603 v.c = code_append(v.c, w.c);
3604 v.c = converttype(w.c, w.t, TYPE_STRING);
3605 v.c = abc_getproperty2(v.c, &m);
3609 E : E ".." '@' '[' E ']' {
3610 typedcode_t v = node_read($1);
3611 typedcode_t w = node_read($5);
3612 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3613 v.c = code_append(v.c, w.c);
3614 v.c = converttype(w.c, w.t, TYPE_STRING);
3615 v.c = abc_getdescendants2(v.c, &m);
3620 MEMBER : E '.' SUBNODE {
3621 typedcode_t v1 = node_read($1);
3623 classinfo_t*t = v1.t;
3625 if(TYPE_IS_CLASS(t) && t->data) {
3629 if(TYPE_IS_XML(t) && !findmember_nsset(t, $3, 1, is_static)) {
3630 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3631 $$.c = abc_getproperty2($$.c, &m);
3632 $$.c = abc_coerce_a($$.c);
3633 $$.t = TYPE_XMLLIST;
3635 if(t->subtype==INFOTYPE_UNRESOLVED) {
3636 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3638 memberinfo_t*f = findmember_nsset(t, $3, 1, is_static);
3640 if(f && !is_static != !(f->flags&FLAG_STATIC))
3642 if(f && f->slot && !noslot) {
3643 $$.c = abc_getslot($$.c, f->slot);
3646 if(!TYPE_IS_XMLLIST(t)) {
3647 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3650 MEMBER_MULTINAME(m, f, $3);
3651 $$.c = abc_getproperty2($$.c, &m);
3653 /* determine type */
3654 $$.t = slotinfo_gettype((slotinfo_t*)f);
3656 $$.c = abc_coerce_a($$.c);
3658 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3659 string_t*package = v1.c->data[0];
3660 char*package2 = concat3(package->str, ".", $3);
3662 slotinfo_t*a = registry_find(package->str, $3);
3665 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3666 registry_ispackage(package2)) {
3668 $$.c->data[0] = string_new4(package2);
3671 syntaxerror("couldn't resolve %s", package2);
3674 /* when resolving a property on an unknown type, we do know the
3675 name of the property (and don't seem to need the package), but
3676 we need to make avm2 try out all access modes */
3677 as3_softwarning("Resolving %s on unknown type", $3);
3678 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3679 $$.c = abc_getproperty2($$.c, &m);
3680 $$.c = abc_coerce_a($$.c);
3686 node_t* var_read(variable_t*v)
3689 o.c = abc_getlocal(0, v->index);
3691 return mkcodenode(o);
3694 node_t* resolve_identifier(const char*name)
3704 /* look at variables */
3705 if((v = find_variable(state, name))) {
3706 // name is a local variable
3709 if((v = find_slot(state->method, name))) {
3710 o.c = abc_getscopeobject(o.c, 1);
3711 o.c = abc_getslot(o.c, v->index);
3713 return mkcodenode(o);
3716 int i_am_static = state->method->is_static;
3718 if(!state->method->inner && !state->xmlfilter && state->cls)
3720 /* look at current class' members */
3721 if((f = findmember_nsset(state->cls->info, name, 1, i_am_static)))
3723 // name is a member or attribute in this class
3724 int var_is_static = (f->flags&FLAG_STATIC);
3726 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3727 /* if the variable is a constant (and we know what is evaluates to), we
3728 can just use the value itself */
3729 varinfo_t*v = (varinfo_t*)f;
3731 return mkconstnode(v->value);
3735 if(var_is_static >= i_am_static) {
3736 if(f->kind == INFOTYPE_METHOD) {
3737 o.t = TYPE_FUNCTION(f);
3742 if(var_is_static && !i_am_static) {
3743 /* access to a static member from a non-static location.
3744 do this via findpropstrict:
3745 there doesn't seem to be any non-lookup way to access
3746 static properties of a class */
3747 state->method->late_binding = 1;
3749 namespace_t ns = {f->access, f->package};
3750 multiname_t m = {QNAME, &ns, 0, name};
3751 o.c = abc_findpropstrict2(o.c, &m);
3752 o.c = abc_getproperty2(o.c, &m);
3753 return mkcodenode(o);
3754 } else if(f->slot>0) {
3755 o.c = abc_getlocal_0(o.c);
3756 o.c = abc_getslot(o.c, f->slot);
3757 return mkcodenode(o);
3759 MEMBER_MULTINAME(m, f, name);
3760 o.c = abc_getlocal_0(o.c);
3761 o.c = abc_getproperty2(o.c, &m);
3762 return mkcodenode(o);
3766 /* special case: it's allowed to access non-static constants
3767 from a static context */
3768 if(i_am_static && (f=findmember_nsset(state->cls->info, name, 1, 0))) {
3769 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3770 varinfo_t*v = (varinfo_t*)f;
3772 return mkconstnode(v->value);
3778 /* look at actual classes, in the current package and imported */
3779 if(!state->xmlfilter && (a = find_class(name))) {
3780 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3781 o.c = abc_getlocal_0(0);
3782 o.t = TYPE_CLASS((classinfo_t*)a);
3786 return mkcodenode(o);
3789 /* look through package prefixes */
3790 if(!state->xmlfilter &&
3791 (dict_contains(state->import_toplevel_packages, name) ||
3792 registry_ispackage(name))) {
3793 o.c = abc___pushpackage__(o.c, (char*)name);
3795 return mkcodenode(o); //?
3798 /* unknown object, let the avm2 resolve it */
3800 if(!state->method->inner && !state->xmlfilter) {
3801 /* we really should make inner functions aware of the class context */
3802 as3_warning("Couldn't resolve '%s', doing late binding", name);
3804 state->method->late_binding = 1;
3806 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3809 o.c = abc_findpropstrict2(o.c, &m);
3810 o.c = abc_getproperty2(o.c, &m);
3811 return mkcodenode(o);
3816 /* TODO: causes 16 r/r conflicts */
3817 VAR_READ : T_NAMESPACE {
3819 $$ = resolve_identifier($1);
3822 VAR_READ : T_IDENTIFIER {
3824 /* Queue unresolved identifiers for checking against the parent
3825 function's variables.
3826 We consider everything which is not a local variable "unresolved".
3827 This encompasses class names, members of the surrounding class
3828 etc. which is *correct* because local variables of the parent function
3832 if(!find_variable(state, $1)) {
3833 unknown_variable($1);
3834 /* let the compiler know that it might want to check the current directory/package
3835 for this identifier- maybe there's a file $1.as defining $1. */
3836 as3_schedule_class_noerror(state->package, $1);
3842 $$ = resolve_identifier($1);
3845 // ----------------- namespaces -------------------------------------------------
3848 void add_active_url(const char*url)
3852 list_append(state->active_namespace_urls, n);
3856 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3858 NEW(namespace_decl_t,n);
3863 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3865 NEW(namespace_decl_t,n);
3870 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3872 NEW(namespace_decl_t,n);
3877 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3879 trie_put(active_namespaces, (unsigned char*)$2->name, (void*)$2->url);
3881 namespace_t access = modifiers2access(&$1);
3882 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3883 var->type = TYPE_NAMESPACE;
3885 ns.access = ACCESS_NAMESPACE;
3887 var->value = constant_new_namespace(&ns);
3890 MULTINAME(m, TYPE_NAMESPACE);
3891 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3892 t->value = var->value;
3893 t->type_name = multiname_clone(&m);
3899 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3902 $$ = code_append($$, node_read($4).c);
3903 $$ = abc_dxnslate($$);
3906 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3908 const char*url = $3->name;
3910 varinfo_t*s = (varinfo_t*)$3;
3911 if(s->kind == INFOTYPE_UNRESOLVED) {
3912 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3914 syntaxerror("Couldn't resolve namespace %s", $3->name);
3917 if(!s || s->kind != INFOTYPE_VAR)
3918 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3919 if(!s->value || !NS_TYPE(s->value->type))
3920 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3921 url = s->value->ns->name;
3923 trie_put(active_namespaces, (unsigned char*)$3->name, (void*)url);
3924 add_active_url(url);