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;
348 dict_t*allvars; // all variables (in all sublevels, but not for inner functions)
351 char uses_parent_function;
352 char no_variable_scoping;
360 int var_index; // for inner methods
361 int slot_index; // for inner methods
362 char is_a_slot; // for inner methods
367 abc_exception_list_t*exceptions;
369 methodstate_list_t*innerfunctions;
372 methodstate_t*methodstate_new()
374 NEW(methodstate_t,m);
375 m->allvars = dict_new();
378 void methodstate_destroy(methodstate_t*m)
380 dict_destroy(m->unresolved_variables); m->unresolved_variables = 0;
381 list_free(m->innerfunctions);m->innerfunctions=0;
384 DICT_ITERATE_DATA(m->allvars, void*, data) {free(data);}
389 typedef struct _state {
394 import_list_t*wildcard_imports;
395 dict_t*import_toplevel_packages;
398 namespace_list_t*active_namespace_urls;
400 char has_own_imports;
401 char new_vars; // e.g. transition between two functions
402 char xmlfilter; // are we inside a xmlobj..() filter?
405 methodstate_t*method;
414 typedef struct _global {
417 parsedclass_list_t*classes;
418 abc_script_t*classinit;
420 abc_script_t*init; //package-level code
423 dict_t*file2token2info;
426 static global_t*global = 0;
427 static state_t* state = 0;
431 /* protected handling here is a big hack: we just assume the protectedns
432 is package:class. the correct approach would be to add the proper
433 namespace to all protected members in the registry, even though that
434 would slow down searching */
435 #define MEMBER_MULTINAME(m,f,n) \
439 m##_ns.access = ((slotinfo_t*)(f))->access; \
440 if(m##_ns.access == ACCESS_NAMESPACE) \
441 m##_ns.name = ((slotinfo_t*)(f))->package; \
442 else if(m##_ns.access == ACCESS_PROTECTED && (f)->parent) \
443 m##_ns.name = concat3((f)->parent->package,":",(f)->parent->name); \
448 m.namespace_set = 0; \
449 m.name = ((slotinfo_t*)(f))->name; \
451 m.type = MULTINAME; \
453 m.namespace_set = &nopackage_namespace_set; \
457 /* warning: list length of namespace set is undefined */
458 #define MULTINAME_LATE(m, access, package) \
459 namespace_t m##_ns = {access, package}; \
460 namespace_set_t m##_nsset; \
461 namespace_list_t m##_l;m##_l.next = 0; \
462 m##_nsset.namespaces = &m##_l; \
463 m##_nsset = m##_nsset; \
464 m##_l.namespace = &m##_ns; \
465 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
467 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
468 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
469 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
470 static namespace_t stdns = {ACCESS_PACKAGE, ""};
471 static namespace_list_t nl4 = {&stdns,0};
472 static namespace_list_t nl3 = {&ns3,&nl4};
473 static namespace_list_t nl2 = {&ns2,&nl3};
474 static namespace_list_t nl1 = {&ns1,&nl2};
475 static namespace_set_t nopackage_namespace_set = {&nl1};
477 static dict_t*definitions=0;
478 void as3_set_define(const char*c)
481 definitions = dict_new();
482 if(!dict_contains(definitions,c))
483 dict_put(definitions,c,0);
486 static void new_state()
489 state_t*oldstate = state;
491 memcpy(s, state, sizeof(state_t)); //shallow copy
493 s->imports = dict_new();
495 if(!s->import_toplevel_packages) {
496 s->import_toplevel_packages = dict_new();
500 state->has_own_imports = 0;
501 state->vars = dict_new();
502 state->old = oldstate;
505 trie_remember(active_namespaces);
508 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
511 static void state_destroy(state_t*state)
513 if(state->has_own_imports) {
514 list_free(state->wildcard_imports);
515 dict_destroy(state->imports);state->imports=0;
517 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
518 dict_destroy(state->imports);state->imports=0;
521 dict_destroy(state->vars);state->vars=0;
524 list_free(state->active_namespace_urls)
525 state->active_namespace_urls = 0;
530 static void old_state()
532 trie_rollback(active_namespaces);
534 if(!state || !state->old)
535 syntaxerror("invalid nesting");
536 state_t*leaving = state;
540 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
541 methodstate_destroy(leaving->method);leaving->method=0;
543 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
548 state_destroy(leaving);
551 static code_t* method_header(methodstate_t*m);
552 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
553 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0);
556 static char* internal_filename_package = 0;
557 void initialize_file(char*filename)
560 syntaxerror("invalid call to initialize_file during parsing of another file");
563 active_namespaces = trie_new();
566 state->package = internal_filename_package = strdup(filename);
568 global->token2info = dict_lookup(global->file2token2info,
569 current_filename // use long version
571 if(!global->token2info) {
572 global->token2info = dict_new2(&ptr_type);
573 dict_put(global->file2token2info, current_filename, global->token2info);
577 state->method = rfx_calloc(sizeof(methodstate_t));
578 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
579 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
580 state->method->allvars = dict_new();
582 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
583 state->method->variable_count = 0;
585 syntaxerror("internal error: skewed tokencount");
586 function_initvars(state->method, 0, 0, 0, 1);
593 if(!state || state->level!=1) {
594 syntaxerror("unexpected end of file in pass %d", as3_pass);
598 dict_del(global->file2token2info, current_filename);
599 code_t*header = method_header(state->method);
600 //if(global->init->method->body->code || global->init->traits) {
602 code_t*c = wrap_function(header, 0, global->init->method->body->code);
603 global->init->method->body->code = abc_returnvoid(c);
604 free(state->method);state->method=0;
608 //free(state->package);state->package=0; // used in registry
609 state_destroy(state);state=0;
612 void initialize_parser()
614 global = rfx_calloc(sizeof(global_t));
615 global->file = abc_file_new();
616 global->file->flags &= ~ABCFILE_LAZY;
617 global->file2token2info = dict_new();
618 global->token2info = 0;
619 global->classinit = abc_initscript(global->file);
622 void* finish_parser()
624 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
625 global->token2info=0;
627 initcode_add_classlist(global->classinit, global->classes);
632 typedef struct _variable {
638 methodstate_t*is_inner_method;
641 static variable_t* find_variable(state_t*s, const char*name)
643 if(s->method->no_variable_scoping) {
644 return dict_lookup(s->method->allvars, name);
649 v = dict_lookup(s->vars, name);
651 if(s->new_vars) break;
657 static variable_t* find_slot(methodstate_t*m, const char*name)
660 return dict_lookup(m->slots, name);
664 static variable_t* find_variable_safe(state_t*s, char*name)
666 variable_t* v = find_variable(s, name);
668 syntaxerror("undefined variable: %s", name);
672 static char variable_exists(char*name)
674 return dict_contains(state->vars, name);
677 static code_t*defaultvalue(code_t*c, classinfo_t*type)
679 parserassert(!type || type->kind!=INFOTYPE_UNRESOLVED);
680 if(TYPE_IS_INT(type)) {
681 c = abc_pushbyte(c, 0);
682 } else if(TYPE_IS_UINT(type)) {
683 c = abc_pushuint(c, 0);
684 } else if(TYPE_IS_FLOAT(type)) {
686 } else if(TYPE_IS_BOOLEAN(type)) {
687 c = abc_pushfalse(c);
688 } else if(TYPE_IS_STRING(type)) {
692 //c = abc_pushundefined(c);
693 syntaxerror("internal error: can't generate default value for * type");
697 c = abc_coerce2(c, &m);
702 static int alloc_local()
704 return state->method->variable_count++;
707 static variable_t* new_variable2(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
710 variable_t*v = find_slot(method, name);
718 v->index = alloc_local();
720 v->init = v->kill = init;
723 if(!method->no_variable_scoping)
725 if(dict_contains(state->vars, name)) {
726 syntaxerror("variable %s already defined", name);
728 dict_put(state->vars, name, v);
730 if(method->no_variable_scoping &&
732 dict_contains(state->method->allvars, name))
734 variable_t*v = dict_lookup(state->method->allvars, name);
735 if(v->type != type && (!v->type || v->type->kind!=INFOTYPE_UNRESOLVED)) {
736 syntaxerror("variable %s already defined.", name);
740 dict_put(state->method->allvars, name, v);
745 static int new_variable(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
747 return new_variable2(method, name, type, init, maybeslot)->index;
750 #define TEMPVARNAME "__as3_temp__"
753 variable_t*v = find_variable(state, TEMPVARNAME);
758 i = new_variable(state->method, TEMPVARNAME, 0, 0, 0);
763 static code_t* var_block(code_t*body, dict_t*vars)
768 DICT_ITERATE_DATA(vars, variable_t*, v) {
769 if(v->type && v->init) {
770 c = defaultvalue(c, v->type);
771 c = abc_setlocal(c, v->index);
773 if(v->type && v->kill) {
774 k = abc_kill(k, v->index);
781 if(x->opcode== OPCODE___BREAK__ ||
782 x->opcode== OPCODE___CONTINUE__) {
783 /* link kill code before break/continue */
784 code_t*e = code_dup(k);
785 code_t*s = code_start(e);
797 c = code_append(c, body);
798 c = code_append(c, k);
802 static void unknown_variable(char*name)
804 if(!state->method->unresolved_variables)
805 state->method->unresolved_variables = dict_new();
806 if(!dict_contains(state->method->unresolved_variables, name))
807 dict_put(state->method->unresolved_variables, name, 0);
810 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
812 if(m->uses_slots || m->innerfunctions || (m->late_binding && !m->inner)) {
813 c = abc_getlocal_0(c);
814 c = abc_pushscope(c);
817 /* FIXME: this alloc_local() causes variable indexes to be
818 different in pass2 than in pass1 */
819 if(!m->activation_var) {
820 m->activation_var = alloc_local();
823 c = abc_newactivation(c);
825 c = abc_pushscope(c);
826 c = abc_setlocal(c, m->activation_var);
828 c = abc_getlocal(c, m->activation_var);
829 c = abc_pushscope(c);
835 static code_t* method_header(methodstate_t*m)
839 c = add_scope_code(c, m, 1);
841 methodstate_list_t*l = m->innerfunctions;
843 parserassert(l->methodstate->abc);
844 if(m->uses_slots && l->methodstate->is_a_slot) {
845 c = abc_getscopeobject(c, 1);
846 c = abc_newfunction(c, l->methodstate->abc);
848 c = abc_setlocal(c, l->methodstate->var_index);
849 c = abc_setslot(c, l->methodstate->slot_index);
851 c = abc_newfunction(c, l->methodstate->abc);
852 c = abc_setlocal(c, l->methodstate->var_index);
854 free(l->methodstate);l->methodstate=0;
858 c = code_append(c, m->header);
861 if(m->is_constructor && !m->has_super) {
862 // call default constructor
863 c = abc_getlocal_0(c);
864 c = abc_constructsuper(c, 0);
868 /* all parameters that are used by inner functions
869 need to be copied from local to slot */
870 parserassert(m->activation_var);
871 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
872 if(v->is_parameter) {
873 c = abc_getlocal(c, m->activation_var);
874 c = abc_getlocal(c, v->index);
875 c = abc_setslot(c, v->index);
879 list_free(m->innerfunctions);
880 m->innerfunctions = 0;
885 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
887 c = code_append(c, header);
888 c = code_append(c, var_block(body, state->method->no_variable_scoping?state->method->allvars:state->vars));
889 /* append return if necessary */
890 if(!c || (c->opcode != OPCODE_RETURNVOID &&
891 c->opcode != OPCODE_RETURNVALUE)) {
892 c = abc_returnvoid(c);
897 static void startpackage(char*name)
900 state->package = strdup(name);
902 static void endpackage()
904 //used e.g. in classinfo_register:
905 //free(state->package);state->package=0;
909 #define FLAG_PUBLIC 256
910 #define FLAG_PROTECTED 512
911 #define FLAG_PRIVATE 1024
912 #define FLAG_PACKAGEINTERNAL 2048
913 #define FLAG_NAMESPACE 4096
915 static namespace_t modifiers2access(modifiers_t*mod)
920 if(mod->flags&FLAG_NAMESPACE) {
921 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
922 syntaxerror("invalid combination of access levels and namespaces");
923 ns.access = ACCESS_NAMESPACE;
925 const char*url = (const char*)trie_lookup(active_namespaces, (unsigned char*)mod->ns);
927 /* shouldn't happen- the tokenizer only reports something as a namespace
928 if it was already registered */
929 trie_dump(active_namespaces);
930 syntaxerror("unknown namespace: %s", mod->ns);
933 } else if(mod->flags&FLAG_PUBLIC) {
934 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
935 syntaxerror("invalid combination of access levels");
936 ns.access = ACCESS_PACKAGE;
937 } else if(mod->flags&FLAG_PRIVATE) {
938 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
939 syntaxerror("invalid combination of access levels");
940 ns.access = ACCESS_PRIVATE;
941 } else if(mod->flags&FLAG_PROTECTED) {
942 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
943 syntaxerror("invalid combination of access levels");
944 ns.access = ACCESS_PROTECTED;
946 ns.access = ACCESS_PACKAGEINTERNAL;
950 static slotinfo_t* find_class(const char*name);
952 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse, char is_static)
954 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse, is_static);
957 static void innerfunctions2vars(methodstate_t*m)
959 methodstate_list_t*l = m->innerfunctions;
961 methodstate_t*m = l->methodstate;
963 variable_t* v = new_variable2(state->method, m->info->name, TYPE_FUNCTION(m->info), 0, 0);
964 m->var_index = v->index;
966 m->slot_index = m->is_a_slot;
967 v->is_inner_method = m;
972 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
977 index = new_variable(m, "this", 0, 0, 0);
978 else if(!m->is_global)
979 index = new_variable(m, (flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
981 index = new_variable(m, "globalscope", 0, 0, 0);
983 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
984 printf("%s %d\n", name, v->index);
987 parserassert(!index);
992 for(p=params->list;p;p=p->next) {
993 variable_t*v = new_variable2(m, p->param->name, p->param->type, 0, 1);
996 if(as3_pass==2 && m->need_arguments) {
997 /* arguments can never be used by an innerfunction (the inner functions
998 have their own arguments var), so it's ok to not initialize this until
999 pass 2. (We don't know whether we need it before, anyway) */
1000 variable_t*v = new_variable2(m, "arguments", TYPE_ARRAY, 0, 0);
1001 m->need_arguments = v->index;
1005 innerfunctions2vars(m);
1008 m->scope_code = add_scope_code(m->scope_code, m, 0);
1010 /* exchange unresolved identifiers with the actual objects */
1011 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v1) {
1012 if(v1->type && v1->type->kind == INFOTYPE_UNRESOLVED) {
1013 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v1->type);
1014 if(!type || type->kind != INFOTYPE_CLASS) {
1015 syntaxerror("Couldn't find class %s::%s (%s)", v1->type->package, v1->type->name, name);
1022 DICT_ITERATE_ITEMS(m->allvars, char*, name2, variable_t*, v2) {
1023 if(v2->type && v2->type->kind == INFOTYPE_UNRESOLVED) {
1024 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v2->type);
1025 if(!type || type->kind != INFOTYPE_CLASS) {
1026 syntaxerror("Couldn't find class %s::%s (%s)", v2->type->package, v2->type->name, name2);
1036 char*as3_globalclass=0;
1037 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
1040 syntaxerror("inner classes now allowed");
1045 classinfo_list_t*mlist=0;
1047 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
1048 syntaxerror("invalid modifier(s)");
1050 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
1051 syntaxerror("public and internal not supported at the same time.");
1053 if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
1054 syntaxerror("protected and static not supported at the same time.");
1056 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1057 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1058 // all classes extend object
1059 extends = registry_getobjectclass();
1062 /* create the class name, together with the proper attributes */
1066 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
1067 access = ACCESS_PRIVATE; package = internal_filename_package;
1068 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
1069 access = ACCESS_PACKAGEINTERNAL; package = state->package;
1070 } else if(state->package!=internal_filename_package) {
1071 access = ACCESS_PACKAGE; package = state->package;
1073 syntaxerror("public classes only allowed inside a package");
1077 state->cls = rfx_calloc(sizeof(classstate_t));
1078 state->cls->init = methodstate_new();
1079 state->cls->static_init = methodstate_new();
1080 state->cls->static_init->is_static=FLAG_STATIC;
1081 /* notice: we make no effort to initialize the top variable (local0) here,
1082 even though it has special meaning. We just rely on the fact
1083 that pass 1 won't do anything with variables */
1085 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1087 /* set current method to constructor- all code within the class-level (except
1088 static variable initializations) will be executed during construction time */
1089 state->method = state->cls->init;
1091 if(registry_find(package, classname)) {
1092 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1094 /* build info struct */
1095 int num_interfaces = (list_length(implements));
1096 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1097 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1098 state->cls->info->superclass = extends;
1101 classinfo_list_t*l = implements;
1102 for(l=implements;l;l=l->next) {
1103 state->cls->info->interfaces[pos++] = l->classinfo;
1108 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1110 parserassert(state->cls && state->cls->info);
1112 state->method = state->cls->static_init;
1114 function_initvars(state->cls->init, 0, 0, 0, 1);
1115 state->cls->static_init->variable_count=1;
1116 function_initvars(state->cls->static_init, 0, 0, 0, 0);
1118 if(extends && (extends->flags & FLAG_FINAL))
1119 syntaxerror("Can't extend final class '%s'", extends->name);
1122 while(state->cls->info->interfaces[pos]) {
1123 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1124 syntaxerror("'%s' is not an interface",
1125 state->cls->info->interfaces[pos]->name);
1129 /* generate the abc code for this class */
1130 MULTINAME(classname2,state->cls->info);
1131 multiname_t*extends2 = sig2mname(extends);
1133 /* don't add the class to the class index just yet- that will be done later
1135 state->cls->abc = abc_class_new(0, &classname2, extends2);
1136 state->cls->abc->file = global->file;
1138 multiname_destroy(extends2);
1139 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1140 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1141 if(state->cls->info->flags&FLAG_INTERFACE) {
1142 abc_class_interface(state->cls->abc);
1145 for(mlist=implements;mlist;mlist=mlist->next) {
1146 MULTINAME(m, mlist->classinfo);
1147 abc_class_add_interface(state->cls->abc, &m);
1150 state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
1151 list_append(global->classes, state->cls->dependencies);
1153 /* flash.display.MovieClip handling */
1154 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1155 if(state->package && state->package[0]) {
1156 as3_globalclass = concat3(state->package, ".", classname);
1158 as3_globalclass = strdup(classname);
1164 static void endclass()
1167 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1169 c = abc_getlocal_0(c);
1170 c = abc_constructsuper(c, 0);
1171 state->cls->init->header = code_append(state->cls->init->header, c);
1172 state->cls->has_constructor=1;
1174 if(state->cls->init) {
1175 if(state->cls->info->flags&FLAG_INTERFACE) {
1176 if(state->cls->init->header)
1177 syntaxerror("interface can not have class-level code");
1179 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1180 code_t*c = method_header(state->cls->init);
1181 m->body->code = wrap_function(c, 0, m->body->code);
1184 if(state->cls->static_init) {
1185 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1186 code_t*c = method_header(state->cls->static_init);
1187 m->body->code = wrap_function(c, 0, m->body->code);
1190 trait_list_t*trait = state->cls->abc->traits;
1191 /* switch all protected members to the protected ns of this class */
1193 trait_t*t = trait->trait;
1194 if(t->name->ns->access == ACCESS_PROTECTED) {
1195 if(!state->cls->abc->protectedNS) {
1196 char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
1197 state->cls->abc->protectedNS = namespace_new_protected(n);
1198 state->cls->abc->flags |= CLASS_PROTECTED_NS;
1200 t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
1202 trait = trait->next;
1209 void check_code_for_break(code_t*c)
1212 if(c->opcode == OPCODE___BREAK__) {
1213 char*name = string_cstr(c->data[0]);
1214 syntaxerror("Unresolved \"break %s\"", name);
1216 if(c->opcode == OPCODE___CONTINUE__) {
1217 char*name = string_cstr(c->data[0]);
1218 syntaxerror("Unresolved \"continue %s\"", name);
1220 if(c->opcode == OPCODE___RETHROW__) {
1221 syntaxerror("Unresolved \"rethrow\"");
1223 if(c->opcode == OPCODE___FALLTHROUGH__) {
1224 syntaxerror("Unresolved \"fallthrough\"");
1226 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1227 char*name = string_cstr(c->data[0]);
1228 syntaxerror("Can't reference a package (%s) as such", name);
1234 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1236 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1237 if(TYPE_IS_NUMBER(t)) {
1238 xassert(c->type == CONSTANT_FLOAT
1239 || c->type == CONSTANT_INT
1240 || c->type == CONSTANT_UINT);
1241 } else if(TYPE_IS_UINT(t)) {
1242 xassert(c->type == CONSTANT_UINT ||
1243 (c->type == CONSTANT_INT && c->i>=0));
1244 } else if(TYPE_IS_INT(t)) {
1245 xassert(c->type == CONSTANT_INT);
1246 } else if(TYPE_IS_BOOLEAN(t)) {
1247 xassert(c->type == CONSTANT_TRUE
1248 || c->type == CONSTANT_FALSE);
1252 static void check_override(memberinfo_t*m, int flags)
1256 if(m->parent == state->cls->info && !((flags^m->flags)&FLAG_STATIC))
1257 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1259 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1260 if(m->access==ACCESS_PRIVATE)
1262 if(m->flags & FLAG_FINAL)
1263 syntaxerror("can't override final member %s", m->name);
1265 /* allow this. it's no issue.
1266 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1267 syntaxerror("can't override static member %s", m->name);*/
1269 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1270 syntaxerror("can't override non-static member %s with static declaration", m->name);
1272 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1273 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1274 if(m->kind == INFOTYPE_METHOD)
1275 syntaxerror("can't override without explicit 'override' declaration");
1277 syntaxerror("can't override '%s'", m->name);
1282 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1284 methodinfo_t*minfo = 0;
1285 namespace_t ns = modifiers2access(mod);
1288 minfo = methodinfo_register_global(ns.access, state->package, name);
1289 minfo->return_type = return_type;
1290 } else if(getset != KW_GET && getset != KW_SET) {
1292 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0, mod->flags&FLAG_STATIC);
1294 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1296 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name, mod->flags&FLAG_STATIC);
1297 minfo->return_type = return_type;
1298 // getslot on a member slot only returns "undefined", so no need
1299 // to actually store these
1300 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1302 //class getter/setter
1303 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1305 if(getset == KW_GET) {
1307 } else if(params->list && params->list->param && !params->list->next) {
1308 type = params->list->param->type;
1310 syntaxerror("setter function needs to take exactly one argument");
1311 // not sure wether to look into superclasses here, too
1312 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1, mod->flags&FLAG_STATIC);
1314 if(minfo->kind!=INFOTYPE_VAR)
1315 syntaxerror("class already contains a method called '%s'", name);
1316 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1317 syntaxerror("class already contains a field called '%s'", name);
1318 if(minfo->subtype & gs)
1319 syntaxerror("getter/setter for '%s' already defined", name);
1320 /* make a setter or getter into a getset */
1321 minfo->subtype |= gs;
1324 FIXME: this check needs to be done in pass 2
1326 if((!minfo->return_type != !type) ||
1327 (minfo->return_type && type &&
1328 !strcmp(minfo->return_type->name, type->name))) {
1329 syntaxerror("different type in getter and setter: %s and %s",
1330 minfo->return_type?minfo->return_type->name:"*",
1331 type?type->name:"*");
1334 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name, mod->flags&FLAG_STATIC);
1335 minfo->kind = INFOTYPE_VAR; //hack
1336 minfo->subtype = gs;
1337 minfo->return_type = type;
1340 /* can't assign a slot as getter and setter might have different slots */
1341 //minfo->slot = slot;
1343 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1344 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1345 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1350 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1352 //parserassert(state->method && state->method->info);
1354 methodstate_t*parent_method = state->method;
1358 return_type = 0; // not valid in pass 1
1360 v = new_variable2(parent_method, name, 0, 0, 0);
1365 state->new_vars = 1;
1368 state->method = methodstate_new();
1369 state->method->inner = 1;
1370 state->method->is_static = parent_method->is_static;
1371 state->method->variable_count = 0;
1372 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1374 v->is_inner_method = state->method;
1377 NEW(methodinfo_t,minfo);
1378 minfo->kind = INFOTYPE_METHOD;
1379 minfo->access = ACCESS_PACKAGEINTERNAL;
1381 state->method->info = minfo;
1384 list_append(parent_method->innerfunctions, state->method);
1386 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1388 function_initvars(state->method, 1, params, 0, 1);
1392 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1393 state->method->variable_count = 0;
1394 parserassert(state->method);
1396 state->method->info->return_type = return_type;
1397 function_initvars(state->method, 1, params, 0, 1);
1401 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1402 params_t*params, classinfo_t*return_type)
1404 if(state->method && state->method->info) {
1405 syntaxerror("not able to start another method scope");
1408 state->new_vars = 1;
1411 state->method = methodstate_new();
1412 state->method->has_super = 0;
1413 state->method->is_static = mod->flags&FLAG_STATIC;
1416 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1418 state->method->is_global = 1;
1419 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1421 if(state->method->is_constructor)
1422 name = "__as3_constructor__";
1424 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1426 function_initvars(state->method, 1, params, mod->flags, 1);
1428 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1432 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1433 state->method->variable_count = 0;
1434 parserassert(state->method);
1437 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2, mod->flags&FLAG_STATIC);
1438 check_override(m, mod->flags);
1442 state->cls->has_constructor |= state->method->is_constructor;
1445 function_initvars(state->method, 1, params, mod->flags, 1);
1449 static void insert_unresolved(methodstate_t*m, dict_t*xvars, dict_t*allvars)
1451 parserassert(m->inner);
1452 if(m->unresolved_variables) {
1453 dict_t*d = m->unresolved_variables;
1455 DICT_ITERATE_KEY(d, char*, id) {
1456 /* check parent method's variables */
1458 if(dict_contains(allvars, id)) {
1459 m->uses_parent_function = 1;
1460 state->method->uses_slots = 1;
1461 dict_put(xvars, id, 0);
1465 methodstate_list_t*ml = m->innerfunctions;
1467 insert_unresolved(ml->methodstate, xvars, allvars);
1472 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1473 params_t*params, classinfo_t*return_type, code_t*body)
1476 dict_t*xvars = dict_new();
1478 if(state->method->unresolved_variables) {
1479 DICT_ITERATE_KEY(state->method->unresolved_variables, char*, vname) {
1480 if(!state->method->no_variable_scoping && dict_contains(state->method->allvars, vname)) {
1481 variable_t*v = dict_lookup(state->method->allvars, vname);
1482 if(!v->is_inner_method) {
1483 state->method->no_variable_scoping = 1;
1484 as3_warning("function %s uses forward or outer block variable references (%s): switching into compatibility mode", name, vname);
1490 methodstate_list_t*ml = state->method->innerfunctions;
1492 insert_unresolved(ml->methodstate, xvars, state->method->allvars);
1496 if(state->method->uses_slots) {
1497 state->method->slots = dict_new();
1499 DICT_ITERATE_ITEMS(state->method->allvars, char*, name, variable_t*, v) {
1500 if(!name) syntaxerror("internal error");
1501 if(v->index && dict_contains(xvars, name)) {
1502 v->init = v->kill = 0;
1504 if(v->is_inner_method) {
1505 v->is_inner_method->is_a_slot = i;
1508 dict_put(state->method->slots, name, v);
1511 state->method->uses_slots = i;
1512 dict_destroy(state->vars);state->vars = 0;
1513 parserassert(state->new_vars);
1520 /*if(state->method->uses_parent_function){
1521 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1526 multiname_t*type2 = sig2mname(return_type);
1528 if(state->method->inner) {
1529 f = state->method->abc;
1530 abc_method_init(f, global->file, type2, 1);
1531 } else if(state->method->is_constructor) {
1532 f = abc_class_getconstructor(state->cls->abc, type2);
1533 } else if(!state->method->is_global) {
1534 namespace_t ns = modifiers2access(mod);
1535 multiname_t mname = {QNAME, &ns, 0, name};
1536 if(mod->flags&FLAG_STATIC)
1537 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1539 f = abc_class_method(state->cls->abc, type2, &mname);
1540 slot = f->trait->slot_id;
1542 namespace_t mname_ns = {state->method->info->access, state->package};
1543 multiname_t mname = {QNAME, &mname_ns, 0, name};
1545 f = abc_method_new(global->file, type2, 1);
1546 if(!global->init) global->init = abc_initscript(global->file);
1547 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1548 //abc_code_t*c = global->init->method->body->code;
1550 //flash doesn't seem to allow us to access function slots
1551 //state->method->info->slot = slot;
1553 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1554 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1555 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1556 if(params->varargs) f->flags |= METHOD_NEED_REST;
1557 if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
1561 for(p=params->list;p;p=p->next) {
1562 if(params->varargs && !p->next) {
1563 break; //varargs: omit last parameter in function signature
1565 multiname_t*m = sig2mname(p->param->type);
1566 list_append(f->parameters, m);
1567 if(p->param->value) {
1568 check_constant_against_type(p->param->type, p->param->value);
1569 opt=1;list_append(f->optional_parameters, p->param->value);
1571 syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
1574 if(state->method->slots) {
1575 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1577 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1578 multiname_t*type = sig2mname(v->type);
1579 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1580 t->slot_id = v->index;
1585 check_code_for_break(body);
1587 /* Seems this works now.
1588 if(state->method->exceptions && state->method->uses_slots) {
1589 as3_warning("try/catch and activation not supported yet within the same method");
1593 f->body->code = body;
1594 f->body->exceptions = state->method->exceptions;
1595 } else { //interface
1597 syntaxerror("interface methods can't have a method body");
1607 void breakjumpsto(code_t*c, char*name, code_t*jump)
1610 if(c->opcode == OPCODE___BREAK__) {
1611 string_t*name2 = c->data[0];
1612 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1613 c->opcode = OPCODE_JUMP;
1620 void continuejumpsto(code_t*c, char*name, code_t*jump)
1623 if(c->opcode == OPCODE___CONTINUE__) {
1624 string_t*name2 = c->data[0];
1625 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1626 c->opcode = OPCODE_JUMP;
1634 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1639 return abc_coerce_a(c);
1643 // cast an "any" type to a specific type. subject to
1644 // runtime exceptions
1645 return abc_coerce2(c, &m);
1648 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1649 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1650 // allow conversion between number types
1651 if(TYPE_IS_UINT(to))
1652 return abc_convert_u(c);
1653 else if(TYPE_IS_INT(to))
1654 return abc_convert_i(c);
1655 else if(TYPE_IS_NUMBER(to))
1656 return abc_convert_d(c);
1657 return abc_coerce2(c, &m);
1660 if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
1663 if(TYPE_IS_BOOLEAN(to))
1664 return abc_convert_b(c);
1665 if(TYPE_IS_STRING(to))
1666 return abc_convert_s(c);
1667 if(TYPE_IS_OBJECT(to))
1668 return abc_coerce2(c, &m);
1669 if(TYPE_IS_OBJECT(from) && TYPE_IS_XMLLIST(to))
1670 return abc_coerce2(c, &m);
1671 if(TYPE_IS_OBJECT(from) && TYPE_IS_ARRAY(to))
1672 return abc_coerce2(c, &m);
1674 classinfo_t*supertype = from;
1676 if(supertype == to) {
1677 /* target type is one of from's superclasses.
1678 (not sure we need this coerce - as far as the verifier
1679 is concerned, object==object (i think) */
1680 return abc_coerce2(c, &m);
1683 while(supertype->interfaces[t]) {
1684 if(supertype->interfaces[t]==to) {
1685 // target type is one of from's interfaces
1686 return abc_coerce2(c, &m);
1690 supertype = supertype->superclass;
1692 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1694 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1696 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1700 as3_error("can't convert type %s%s%s to %s%s%s",
1701 from->package, from->package[0]?".":"", from->name,
1702 to->package, to->package[0]?".":"", to->name);
1706 code_t* coerce_to_type(code_t*c, classinfo_t*t)
1709 return abc_coerce_a(c);
1710 } else if(TYPE_IS_STRING(t)) {
1711 return abc_coerce_s(c);
1714 return abc_coerce2(c, &m);
1718 char is_pushundefined(code_t*c)
1720 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1723 static const char* get_package_from_name(const char*name)
1725 /* try explicit imports */
1726 dictentry_t* e = dict_get_slot(state->imports, name);
1728 if(!strcmp(e->key, name)) {
1729 slotinfo_t*c = (slotinfo_t*)e->data;
1730 if(c) return c->package;
1736 static namespace_list_t*get_current_imports()
1738 namespace_list_t*searchlist = 0;
1740 list_append(searchlist, namespace_new_package(state->package));
1742 import_list_t*l = state->wildcard_imports;
1744 namespace_t*ns = namespace_new_package(l->import->package);
1745 list_append(searchlist, ns);
1748 list_append(searchlist, namespace_new_package(""));
1749 list_append(searchlist, namespace_new_package(internal_filename_package));
1753 static slotinfo_t* find_class(const char*name)
1757 c = registry_find(state->package, name);
1760 /* try explicit imports */
1761 dictentry_t* e = dict_get_slot(state->imports, name);
1764 if(!strcmp(e->key, name)) {
1765 c = (slotinfo_t*)e->data;
1771 /* try package.* imports */
1772 import_list_t*l = state->wildcard_imports;
1774 //printf("does package %s contain a class %s?\n", l->import->package, name);
1775 c = registry_find(l->import->package, name);
1780 /* try global package */
1781 c = registry_find("", name);
1784 /* try local "filename" package */
1785 c = registry_find(internal_filename_package, name);
1790 typedcode_t push_class(slotinfo_t*a)
1795 if(a->access == ACCESS_PACKAGEINTERNAL &&
1796 strcmp(a->package, state->package) &&
1797 strcmp(a->package, internal_filename_package)
1799 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1800 infotypename(a), a->name, a->package, state->package);
1804 if(a->kind != INFOTYPE_CLASS) {
1806 x.c = abc_findpropstrict2(x.c, &m);
1807 x.c = abc_getproperty2(x.c, &m);
1808 if(a->kind == INFOTYPE_METHOD) {
1809 methodinfo_t*f = (methodinfo_t*)a;
1810 x.t = TYPE_FUNCTION(f);
1812 varinfo_t*v = (varinfo_t*)a;
1817 if(state->cls && state->method == state->cls->static_init) {
1818 /* we're in the static initializer.
1819 record the fact that we're using this class here */
1820 parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
1822 classinfo_t*c = (classinfo_t*)a;
1824 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1825 x.c = abc_getglobalscope(x.c);
1826 x.c = abc_getslot(x.c, c->slot);
1829 x.c = abc_getlex2(x.c, &m);
1831 x.t = TYPE_CLASS(c);
1837 char is_break_or_jump(code_t*c)
1841 if(c->opcode == OPCODE_JUMP ||
1842 c->opcode == OPCODE___BREAK__ ||
1843 c->opcode == OPCODE___CONTINUE__ ||
1844 c->opcode == OPCODE_THROW ||
1845 c->opcode == OPCODE_RETURNVOID ||
1846 c->opcode == OPCODE_RETURNVALUE) {
1852 #define IS_FINALLY_TARGET(op) \
1853 ((op) == OPCODE___CONTINUE__ || \
1854 (op) == OPCODE___BREAK__ || \
1855 (op) == OPCODE_RETURNVOID || \
1856 (op) == OPCODE_RETURNVALUE || \
1857 (op) == OPCODE___RETHROW__)
1859 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1861 #define NEED_EXTRA_STACK_ARG
1862 code_t*finally_label = abc_nop(0);
1863 NEW(lookupswitch_t, l);
1869 code_t*prev = i->prev;
1870 if(IS_FINALLY_TARGET(i->opcode)) {
1873 if(i->opcode == OPCODE___RETHROW__ ||
1874 i->opcode == OPCODE_RETURNVALUE) {
1875 if(i->opcode == OPCODE___RETHROW__)
1876 i->opcode = OPCODE_THROW;
1878 p = abc_coerce_a(p);
1879 p = abc_setlocal(p, tempvar);
1881 p = abc_pushbyte(p, count++);
1882 p = abc_jump(p, finally_label);
1883 code_t*target = p = abc_label(p);
1884 #ifdef NEED_EXTRA_STACK_ARG
1888 p = abc_getlocal(p, tempvar);
1891 p->next = i;i->prev = p;
1892 list_append(l->targets, target);
1898 c = abc_pushbyte(c, -1);
1899 c = code_append(c, finally_label);
1900 c = code_append(c, finally);
1902 #ifdef NEED_EXTRA_STACK_ARG
1905 c = abc_lookupswitch(c, l);
1906 c = l->def = abc_label(c);
1907 #ifdef NEED_EXTRA_STACK_ARG
1914 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1918 code_t*prev = i->prev;
1919 if(IS_FINALLY_TARGET(i->opcode)) {
1920 if(i->opcode == OPCODE___RETHROW__)
1921 i->opcode = OPCODE_THROW;
1922 code_t*end = code_dup(finally);
1923 code_t*start = code_start(end);
1924 if(prev) prev->next = start;
1931 return code_append(c, finally);
1934 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1940 int num_insertion_points=0;
1942 if(IS_FINALLY_TARGET(i->opcode))
1943 num_insertion_points++;
1950 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1955 int simple_version_cost = (1+num_insertion_points)*code_size;
1956 int lookup_version_cost = 4*num_insertion_points + 5;
1958 if(cantdup || simple_version_cost > lookup_version_cost) {
1959 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1960 return insert_finally_lookup(c, finally, tempvar);
1962 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1963 return insert_finally_simple(c, finally, tempvar);
1967 #define PASS1 }} if(as3_pass == 1) {{
1968 #define PASS1END }} if(as3_pass == 2) {{
1969 #define PASS2 }} if(as3_pass == 2) {{
1970 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1971 #define PASS12END }} if(as3_pass == 2) {{
1972 #define PASS_ALWAYS }} {{
1978 /* ------------ code blocks / statements ---------------- */
1980 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1982 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1983 PROGRAM_CODE_LIST: PROGRAM_CODE
1984 | PROGRAM_CODE_LIST PROGRAM_CODE
1986 PROGRAM_CODE: PACKAGE_DECLARATION
1987 | INTERFACE_DECLARATION
1989 | FUNCTION_DECLARATION
1992 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1995 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1996 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1997 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1999 INPACKAGE_CODE: INTERFACE_DECLARATION
2001 | FUNCTION_DECLARATION
2004 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
2005 | '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
2008 MAYBECODE: CODE {$$=$1;}
2009 MAYBECODE: {$$=code_new();}
2011 CODE: CODE CODEPIECE {
2012 $$=code_append($1,$2);
2014 CODE: CODEPIECE {$$=$1;}
2016 // code which may appear outside of methods
2017 CODE_STATEMENT: DEFAULT_NAMESPACE
2018 CODE_STATEMENT: IMPORT
2020 CODE_STATEMENT: FOR_IN
2021 CODE_STATEMENT: WHILE
2022 CODE_STATEMENT: DO_WHILE
2023 CODE_STATEMENT: SWITCH
2025 CODE_STATEMENT: WITH
2027 CODE_STATEMENT: VOIDEXPRESSION
2028 CODE_STATEMENT: USE_NAMESPACE
2029 CODE_STATEMENT: NAMESPACE_DECLARATION
2030 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
2031 CODE_STATEMENT: '{' '}' {$$=0;}
2033 // code which may appear in methods (includes the above)
2034 CODEPIECE: ';' {$$=0;}
2035 CODEPIECE: CODE_STATEMENT
2036 CODEPIECE: VARIABLE_DECLARATION
2041 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
2051 //CODEBLOCK : '{' CODE '}' {$$=$2;}
2052 //CODEBLOCK : '{' '}' {$$=0;}
2053 CODEBLOCK : CODEPIECE ';' {$$=$1;}
2054 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
2056 /* ------------ package init code ------------------- */
2058 PACKAGE_INITCODE: CODE_STATEMENT {
2061 global->init = abc_initscript(global->file);
2062 code_t**cc = &global->init->method->body->code;
2063 *cc = code_append(*cc, $1);
2067 /* ------------ embed code ------------- */
2069 EMBED_START: %prec above_function {
2075 /* ------------ conditional compilation ------------- */
2077 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
2080 char*key = concat3($1,"::",$3);
2081 if(!definitions || !dict_contains(definitions, key)) {
2087 /* ------------ variables --------------------------- */
2090 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
2094 char do_init_variable(char*name)
2096 if(!state->method->no_variable_scoping)
2098 if(!state->new_vars)
2104 MAYBEEXPRESSION : '=' E {$$=$2;}
2105 | {$$=mkdummynode();}
2107 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2108 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2110 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2111 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2113 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2116 if(variable_exists($1))
2117 syntaxerror("Variable %s already defined", $1);
2119 new_variable(state->method, $1, $2, 1, 0);
2125 if(state->method->uses_slots) {
2126 v = find_slot(state->method, $1);
2128 // this variable is stored in a slot
2135 v = new_variable2(state->method, $1, $2, 1, 0);
2138 $$ = slot?abc_getscopeobject(0, 1):0;
2140 typedcode_t val = node_read($3);
2141 if(!is_subtype_of(val.t, $2)) {
2142 syntaxerror("Can't convert %s to %s", val.t->name, $2->name);
2145 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2146 $$ = code_append($$, val.c);
2147 $$ = converttype($$, val.t, $2);
2150 $$ = defaultvalue($$, $2);
2153 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2154 $$ = code_append($$, val.c);
2155 $$ = abc_coerce_a($$);
2157 // don't do anything
2165 $$ = abc_setslot($$, v->index);
2167 $$ = abc_setlocal($$, v->index);
2168 v->init = do_init_variable($1);
2172 /* ------------ control flow ------------------------- */
2174 IF_CODEBLOCK: {PASS12 new_state();} CODEBLOCK {
2175 $$ = var_block($2, state->vars);
2178 MAYBEELSE: %prec below_else {$$ = code_new();}
2179 MAYBEELSE: "else" IF_CODEBLOCK {$$=$2;}
2180 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2182 IF : "if" '(' EXPRESSION ')' IF_CODEBLOCK MAYBEELSE {
2184 $$ = code_append($$, $3.c);
2185 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2187 $$ = code_append($$, $5);
2189 myjmp = $$ = abc_jump($$, 0);
2191 myif->branch = $$ = abc_nop($$);
2193 $$ = code_append($$, $6);
2194 myjmp->branch = $$ = abc_nop($$);
2198 FOR_INIT : {$$=code_new();}
2199 FOR_INIT : VARIABLE_DECLARATION
2200 FOR_INIT : VOIDEXPRESSION
2202 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2203 // (I don't see any easy way to revolve this conflict otherwise, as we
2204 // can't touch VAR_READ without upsetting the precedence about "return")
2205 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2206 PASS1 $$=$2;new_variable(state->method, $2,0,1,0);
2207 PASS2 $$=$2;new_variable(state->method, $2,$3,1,0);
2209 FOR_IN_INIT : T_IDENTIFIER {
2214 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2215 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2217 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' IF_CODEBLOCK {
2218 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2220 $$ = code_append($$, $2);
2221 code_t*loopstart = $$ = abc_label($$);
2222 $$ = code_append($$, $4.c);
2223 code_t*myif = $$ = abc_iffalse($$, 0);
2224 $$ = code_append($$, $8);
2225 code_t*cont = $$ = abc_nop($$);
2226 $$ = code_append($$, $6);
2227 $$ = abc_jump($$, loopstart);
2228 code_t*out = $$ = abc_nop($$);
2229 breakjumpsto($$, $1.name, out);
2230 continuejumpsto($$, $1.name, cont);
2233 $$ = var_block($$, state->vars);
2237 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' IF_CODEBLOCK {
2238 node_t*n = resolve_identifier($2);
2239 typedcode_t w = node_write(n);
2241 int it = alloc_local();
2242 int array = alloc_local();
2245 $$ = code_append($$, $4.c);
2246 $$ = abc_coerce_a($$);
2247 $$ = abc_setlocal($$, array);
2248 $$ = abc_pushbyte($$, 0);
2249 $$ = abc_setlocal($$, it);
2251 code_t*loopstart = $$ = abc_label($$);
2253 $$ = abc_hasnext2($$, array, it);
2254 code_t*myif = $$ = abc_iffalse($$, 0);
2255 $$ = abc_getlocal($$, array);
2256 $$ = abc_getlocal($$, it);
2258 $$ = abc_nextname($$);
2260 $$ = abc_nextvalue($$);
2262 $$ = converttype($$, 0, w.t);
2263 $$ = code_append($$, w.c);
2265 $$ = code_append($$, $6);
2266 $$ = abc_jump($$, loopstart);
2268 code_t*out = $$ = abc_nop($$);
2269 breakjumpsto($$, $1.name, out);
2270 continuejumpsto($$, $1.name, loopstart);
2274 $$ = abc_kill($$, it);
2275 $$ = abc_kill($$, array);
2277 $$ = var_block($$, state->vars);
2281 WHILE : T_WHILE '(' EXPRESSION ')' IF_CODEBLOCK {
2285 code_t*myjmp = $$ = abc_jump($$, 0);
2286 code_t*loopstart = $$ = abc_label($$);
2287 $$ = code_append($$, $5);
2288 code_t*cont = $$ = abc_nop($$);
2289 myjmp->branch = cont;
2290 $$ = code_append($$, $3.c);
2291 $$ = abc_iftrue($$, loopstart);
2292 code_t*out = $$ = abc_nop($$);
2293 breakjumpsto($$, $1, out);
2294 continuejumpsto($$, $1, cont);
2297 DO_WHILE : T_DO IF_CODEBLOCK "while" '(' EXPRESSION ')' {
2299 code_t*loopstart = $$ = abc_label($$);
2300 $$ = code_append($$, $2);
2301 code_t*cont = $$ = abc_nop($$);
2302 $$ = code_append($$, $5.c);
2303 $$ = abc_iftrue($$, loopstart);
2304 code_t*out = $$ = abc_nop($$);
2305 breakjumpsto($$, $1, out);
2306 continuejumpsto($$, $1, cont);
2309 BREAK : "break" %prec prec_none {
2310 $$ = abc___break__(0, "");
2312 BREAK : "break" T_IDENTIFIER {
2313 $$ = abc___break__(0, $2);
2315 CONTINUE : "continue" %prec prec_none {
2316 $$ = abc___continue__(0, "");
2318 CONTINUE : "continue" T_IDENTIFIER {
2319 $$ = abc___continue__(0, $2);
2322 MAYBE_CASE_LIST : {$$=0;}
2323 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2324 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2325 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2326 CASE_LIST: CASE {$$=$1;}
2327 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2329 CASE: "case" E ':' MAYBECODE {
2330 $$ = abc_getlocal(0, state->switch_var);
2331 $$ = code_append($$, node_read($2).c);
2332 code_t*j = $$ = abc_ifne($$, 0);
2333 $$ = code_append($$, $4);
2334 if($$->opcode != OPCODE___BREAK__) {
2335 $$ = abc___fallthrough__($$, "");
2337 code_t*e = $$ = abc_nop($$);
2340 DEFAULT: "default" ':' MAYBECODE {
2343 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2344 $$ = node_read($4).c;
2345 $$ = abc_setlocal($$, state->switch_var);
2346 $$ = code_append($$, $7);
2348 code_t*out = $$ = abc_kill($$, state->switch_var);
2349 breakjumpsto($$, $1, out);
2351 code_t*c = $$,*lastblock=0;
2353 if(c->opcode == OPCODE_IFNE) {
2354 if(!c->next) syntaxerror("internal error in fallthrough handling");
2356 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2358 c->opcode = OPCODE_JUMP;
2359 c->branch = lastblock;
2361 /* fall through end of switch */
2362 c->opcode = OPCODE_NOP;
2368 $$ = var_block($$, state->vars);
2372 /* ------------ try / catch /finally ---------------- */
2374 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2375 state->exception_name=$3;
2376 PASS1 new_variable(state->method, $3, 0, 0, 0);
2377 PASS2 new_variable(state->method, $3, $4, 0, 0);
2380 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2381 multiname_t name = {QNAME, &name_ns, 0, $3};
2383 NEW(abc_exception_t, e)
2384 e->exc_type = sig2mname($4);
2385 e->var_name = multiname_clone(&name);
2389 int i = find_variable_safe(state, $3)->index;
2390 e->target = c = abc_nop(0);
2391 c = abc_setlocal(c, i);
2392 c = code_append(c, code_dup(state->method->scope_code));
2393 c = code_append(c, $8);
2396 c = var_block(c, state->vars);
2399 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2400 $4 = var_block($4, state->vars);
2404 NEW(abc_exception_t, e)
2405 e->exc_type = 0; //all exceptions
2406 e->var_name = 0; //no name
2409 e->to = code_append(e->to, $4);
2415 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2416 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2417 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2418 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2422 list_append($$.l,$2);
2423 $$.finally = $2->to;$2->to=0;
2426 CATCH_FINALLY_LIST: FINALLY {
2430 list_append($$.l,$1);
2431 $$.finally = $1->to;$1->to=0;
2435 TRY : "try" '{' {PASS12 new_state();
2436 state->method->has_exceptions=1;
2437 state->method->late_binding=1;//for invariant scope_code
2438 } MAYBECODE '}' CATCH_FINALLY_LIST {
2439 code_t*out = abc_nop(0);
2441 code_t*start = abc_nop(0);
2442 $$ = code_append(start, $4);
2443 if(!is_break_or_jump($4)) {
2444 $$ = abc_jump($$, out);
2446 code_t*end = $$ = abc_nop($$);
2450 tmp = alloc_local();
2452 abc_exception_list_t*l = $6.l;
2455 abc_exception_t*e = l->abc_exception;
2457 $$ = code_append($$, e->target);
2458 $$ = abc_jump($$, out);
2460 parserassert((ptroff_t)$6.finally);
2462 e->target = $$ = abc_nop($$);
2463 $$ = code_append($$, code_dup(state->method->scope_code));
2464 $$ = abc___rethrow__($$);
2472 $$ = code_append($$, out);
2474 $$ = insert_finally($$, $6.finally, tmp);
2476 list_concat(state->method->exceptions, $6.l);
2478 $$ = var_block($$, state->vars);
2482 /* ------------ throw ------------------------------- */
2484 THROW : "throw" EXPRESSION {
2488 THROW : "throw" %prec prec_none {
2489 if(!state->exception_name)
2490 syntaxerror("re-throw only possible within a catch block");
2491 variable_t*v = find_variable(state, state->exception_name);
2493 $$=abc_getlocal($$, v->index);
2497 /* ------------ with -------------------------------- */
2499 WITH_HEAD : "with" '(' EXPRESSION ')' {
2501 if(state->method->has_exceptions) {
2502 int v = alloc_local();
2503 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2504 state->method->scope_code = abc_pushwith(state->method->scope_code);
2509 WITH : WITH_HEAD CODEBLOCK {
2510 /* remove getlocal;pushwith from scope code again */
2511 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2514 if(state->method->has_exceptions) {
2516 $$ = abc_setlocal($$, $1.number);
2518 $$ = abc_pushwith($$);
2519 $$ = code_append($$, $2);
2520 $$ = abc_popscope($$);
2524 /* ------------ packages and imports ---------------- */
2526 X_IDENTIFIER: T_IDENTIFIER
2527 | "package" {PASS12 $$="package";}
2528 | "namespace" {PASS12 $$="namespace";}
2529 | "NaN" {PASS12 $$="NaN";}
2530 | T_NAMESPACE {PASS12 $$=$1;}
2532 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2533 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2535 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2536 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2537 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2538 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2541 static void state_has_imports()
2543 state->wildcard_imports = list_clone(state->wildcard_imports);
2544 state->imports = dict_clone(state->imports);
2545 state->has_own_imports = 1;
2547 static void import_toplevel(const char*package)
2549 char* s = strdup(package);
2551 dict_put(state->import_toplevel_packages, s, 0);
2552 char*x = strrchr(s, '.');
2561 IMPORT : "import" T_IDENTIFIER {
2563 slotinfo_t*s = registry_find(state->package, $2);
2564 if(!s && as3_pass==1) {as3_schedule_class(state->package, $2);}
2565 state_has_imports();
2566 dict_put(state->imports, state->package, $2);
2569 IMPORT : "import" PACKAGEANDCLASS {
2571 slotinfo_t*s = registry_find($2->package, $2->name);
2572 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2573 as3_schedule_class($2->package, $2->name);
2575 state_has_imports();
2576 dict_put(state->imports, $2->name, $2);
2577 import_toplevel($2->package);
2580 IMPORT : "import" PACKAGE '.' '*' {
2582 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2583 as3_schedule_package($2);
2588 state_has_imports();
2589 list_append(state->wildcard_imports, i);
2590 import_toplevel(i->package);
2594 /* ------------ classes and interfaces (header) -------------- */
2596 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2597 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2598 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2599 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2601 $$.flags=$1.flags|$2.flags;
2602 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2603 $$.ns=$1.ns?$1.ns:$2.ns;
2606 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2607 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2608 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2609 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2610 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2611 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2612 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2613 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2614 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2615 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2619 EXTENDS : {PASS12 $$=0;}
2620 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2622 EXTENDS_LIST : {PASS12 $$=list_new();}
2623 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2625 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2626 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2628 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2629 EXTENDS IMPLEMENTS_LIST
2630 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2632 '}' {PASS12 endclass();$$=0;}
2634 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2636 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2637 startclass(&$1,$3,0,$4);}
2638 MAYBE_INTERFACE_BODY
2639 '}' {PASS12 endclass();$$=0;}
2641 /* ------------ classes and interfaces (body) -------------- */
2644 MAYBE_CLASS_BODY : CLASS_BODY
2645 CLASS_BODY : CLASS_BODY_ITEM
2646 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2647 CLASS_BODY_ITEM : ';'
2648 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2649 CLASS_BODY_ITEM : SLOT_DECLARATION
2650 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2651 CLASS_BODY_ITEM : '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
2653 CLASS_BODY_ITEM : CODE_STATEMENT {
2654 code_t*c = state->cls->static_init->header;
2655 c = code_append(c, $1);
2656 state->cls->static_init->header = c;
2659 MAYBE_INTERFACE_BODY :
2660 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2661 INTERFACE_BODY : IDECLARATION
2662 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2664 IDECLARATION : "var" T_IDENTIFIER {
2665 syntaxerror("variable declarations not allowed in interfaces");
2667 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2669 $1.flags |= FLAG_PUBLIC;
2670 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2671 syntaxerror("invalid method modifiers: interface methods always need to be public");
2673 startfunction(&$1,$3,$4,&$6,$8);
2674 endfunction(&$1,$3,$4,&$6,$8, 0);
2675 list_deep_free($6.list);
2678 /* ------------ classes and interfaces (body, slots ) ------- */
2681 static int slotstate_varconst = 0;
2682 static modifiers_t*slotstate_flags = 0;
2683 static void setslotstate(modifiers_t* flags, int varconst)
2685 slotstate_varconst = varconst;
2686 slotstate_flags = flags;
2689 if(flags->flags&FLAG_STATIC) {
2690 state->method = state->cls->static_init;
2692 state->method = state->cls->init;
2695 // reset to "default" state (all in class code is static by default) */
2696 state->method = state->cls->static_init;
2699 parserassert(state->method);
2702 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2704 int flags = modifiers->flags;
2705 namespace_t ns = modifiers2access(modifiers);
2708 multiname_t mname = {QNAME, &ns, 0, name};
2710 trait_list_t**traits;
2714 if(!global->init) global->init = abc_initscript(global->file);
2715 ns.name = state->package;
2716 traits = &global->init->traits;
2717 code = &global->init->method->body->code;
2718 } else if(flags&FLAG_STATIC) {
2720 traits = &state->cls->abc->static_traits;
2721 code = &state->cls->static_init->header;
2723 // instance variable
2724 traits = &state->cls->abc->traits;
2725 code = &state->cls->init->header;
2727 if(ns.access == ACCESS_PROTECTED) {
2728 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2734 *m = *multiname_clone(&mname);
2736 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2740 VARCONST: "var" | "const"
2742 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2744 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2745 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2747 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2750 int flags = slotstate_flags->flags;
2751 namespace_t ns = modifiers2access(slotstate_flags);
2755 varinfo_t* info = 0;
2757 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1, slotstate_flags->flags&FLAG_STATIC);
2759 check_override(i, flags);
2761 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1, slotstate_flags->flags&FLAG_STATIC);
2763 slotinfo_t*i = registry_find(state->package, $1);
2765 syntaxerror("package %s already contains '%s'", state->package, $1);
2767 if(ns.name && ns.name[0]) {
2768 syntaxerror("namespaces not allowed on package-level variables");
2770 info = varinfo_register_global(ns.access, state->package, $1);
2774 info->flags = flags;
2776 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2780 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2784 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2788 t->type_name = multiname_clone(&m);
2790 info->slot = t->slot_id;
2792 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2793 FIXME: is there a way to use slots and still don't have conflicting overrides?
2795 info->slot = t->slot_id = 0;
2797 constant_t cval = $3->type->eval($3);
2798 if(cval.type!=CONSTANT_UNKNOWN) {
2799 /* compile time constant */
2800 t->value = malloc(sizeof(constant_t));
2801 memcpy(t->value, &cval, sizeof(constant_t));
2802 info->value = constant_clone(t->value);
2804 typedcode_t v = node_read($3);
2805 /* initalization code (if needed) */
2807 if(v.c && !is_pushundefined(v.c)) {
2808 c = abc_getlocal_0(c);
2809 c = code_append(c, v.c);
2810 c = converttype(c, v.t, $2);
2812 c = abc_initproperty2(c, &mname);
2814 c = abc_setslot(c, t->slot_id);
2817 *code = code_append(*code, c);
2820 if(slotstate_varconst==KW_CONST) {
2821 t->kind= TRAIT_CONST;
2822 info->flags |= FLAG_CONST;
2829 /* ------------ constants -------------------------------------- */
2831 MAYBECONSTANT: {$$=0;}
2832 MAYBECONSTANT: '=' E {
2833 $$ = malloc(sizeof(constant_t));
2834 *$$ = node_eval($2);
2835 if($$->type == CONSTANT_UNKNOWN) {
2836 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2840 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2841 CONSTANT : T_INT {$$ = constant_new_int($1);}
2843 $$ = constant_new_uint($1);
2845 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2846 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2847 CONSTANT : "true" {$$ = constant_new_true($1);}
2848 CONSTANT : "false" {$$ = constant_new_false($1);}
2849 CONSTANT : "null" {$$ = constant_new_null($1);}
2850 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2851 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2853 /*CONSTANT : T_NAMESPACE {
2855 $$ = constant_new_namespace(namespace_new_namespace($1.url));
2858 /* ---------------------------xml ------------------------------ */
2861 static int xml_level = 0;
2865 multiname_t m = {QNAME, &stdns, 0, "XML"};
2868 v.c = abc_getlex2(v.c, &m);
2869 v.c = code_append(v.c, node_read($1).c);
2870 v.c = abc_construct(v.c, 1);
2875 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2876 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2877 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2879 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2882 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2885 XMLTEXT : {$$=mkstringnode("");}
2886 XMLTEXT : XMLTEXT XMLEXPR1 {
2887 $$ = mkaddnode($1,$2);
2889 XMLTEXT : XMLTEXT T_STRING {
2890 char* str = string_cstr(&$2);
2891 $$ = mkaddnode($1,mkstringnode(str));
2894 XMLTEXT : XMLTEXT '>' {
2895 $$ = mkaddnode($1, mkstringnode(">"));
2897 XML2 : XMLNODE XMLTEXT {
2898 $$ = mkaddnode($1,$2);
2900 XML2 : XML2 XMLNODE XMLTEXT {
2901 $$ = mkaddnode($1, mkaddnode($2,$3));
2903 XML_ID_OR_EXPR: T_IDENTIFIER {
2904 $$ = mkstringnode($1);
2906 XML_ID_OR_EXPR: XMLEXPR2 {
2910 MAYBE_XMLATTRIBUTES: {
2911 $$ = mkstringnode("");
2913 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {
2914 $$ = mkaddnode(mkstringnode(" "),$1);
2917 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2918 //$$ = allocprintf("<%s%s/>", $2, $3, $5, $8);
2919 $$ = mkaddnode(mkaddnode(mkaddnode(mkstringnode("<"),$2),$3),mkstringnode("/>"));
2921 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2922 //$$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2923 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2924 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),mkstringnode("</")),$8),mkstringnode(">"));
2926 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2927 //$$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2928 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2929 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),$6),mkstringnode("</")),$9),mkstringnode(">"));
2932 XMLATTRIBUTES: XMLATTRIBUTE {
2935 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {
2936 $$ = mkaddnode($1, mkaddnode(mkstringnode(" "),$2));
2938 XMLATTRIBUTE: XMLEXPR2 {
2941 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2942 char* str = string_cstr(&$3);
2943 $$ = mkaddnode($1, mkstringnode(concat2("=",str)));
2946 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2947 $$ = mkaddnode($1, mkaddnode(mkstringnode("=\""), mkaddnode($3, mkstringnode("\""))));
2949 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2950 $$ = mkaddnode(mkaddnode(mkstringnode(concat2($1,"=\"")), $3), mkstringnode("\""));
2952 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2953 char* str = string_cstr(&$3);
2954 $$=mkstringnode(allocprintf("%s=%s", $1,str));
2956 free($1);free((char*)$3.str);
2959 /* ------------ classes and interfaces (body, functions) ------- */
2961 // non-vararg version
2964 memset(&$$,0,sizeof($$));
2966 MAYBE_PARAM_LIST: PARAM_LIST {
2972 MAYBE_PARAM_LIST: "..." PARAM {
2974 memset(&$$,0,sizeof($$));
2976 list_append($$.list, $2);
2978 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2982 list_append($$.list, $4);
2986 PARAM_LIST: PARAM_LIST ',' PARAM {
2989 list_append($$.list, $3);
2993 memset(&$$,0,sizeof($$));
2994 list_append($$.list, $1);
2997 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2999 $$ = rfx_calloc(sizeof(param_t));
3005 PARAM: T_IDENTIFIER MAYBECONSTANT {
3007 $$ = rfx_calloc(sizeof(param_t));
3009 $$->type = TYPE_ANY;
3017 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
3018 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
3021 endfunction(&$1,$3,$4,&$6,0,0);
3023 if(!state->method->info) syntaxerror("internal error");
3025 code_t*c = method_header(state->method);
3026 c = wrap_function(c, 0, $11);
3028 endfunction(&$1,$3,$4,&$6,$8,c);
3030 list_deep_free($6.list);
3034 MAYBE_IDENTIFIER: T_IDENTIFIER
3035 MAYBE_IDENTIFIER: {PASS12 $$=0;}
3036 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
3037 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
3040 endfunction(0,0,$2,&$4,0,0);
3042 methodinfo_t*f = state->method->info;
3043 if(!f || !f->kind) syntaxerror("internal error");
3045 code_t*c = method_header(state->method);
3046 c = wrap_function(c, 0, $9);
3048 int index = state->method->var_index;
3049 endfunction(0,0,$2,&$4,$6,c);
3051 $$.c = abc_getlocal(0, index);
3052 $$.t = TYPE_FUNCTION(f);
3054 PASS12 list_deep_free($4.list);
3058 /* ------------- package + class ids --------------- */
3060 CLASS: X_IDENTIFIER {
3061 PASS1 NEW(unresolvedinfo_t,c);
3062 memset(c, 0, sizeof(*c));
3063 c->kind = INFOTYPE_UNRESOLVED;
3065 c->package = get_package_from_name($1);
3067 c->nsset = get_current_imports();
3068 /* make the compiler look for this class in the current directory,
3070 as3_schedule_class_noerror(state->package, $1);
3072 $$ = (classinfo_t*)c;
3074 slotinfo_t*s = find_class($1);
3075 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
3076 $$ = (classinfo_t*)s;
3079 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
3080 PASS1 NEW(unresolvedinfo_t,c);
3081 memset(c, 0, sizeof(*c));
3082 c->kind = INFOTYPE_UNRESOLVED;
3085 $$ = (classinfo_t*)c;
3087 slotinfo_t*s = registry_find($1, $3);
3088 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
3090 $$ = (classinfo_t*)s;
3093 CLASS_SPEC: PACKAGEANDCLASS
3096 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
3097 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
3099 TYPE : CLASS_SPEC {PASS12 $$=$1;}
3100 | '*' {PASS12 $$=TYPE_ANY;}
3101 | "void" {PASS12 $$=TYPE_VOID;}
3103 | "String" {$$=registry_getstringclass();}
3104 | "int" {$$=registry_getintclass();}
3105 | "uint" {$$=registry_getuintclass();}
3106 | "Boolean" {$$=registry_getbooleanclass();}
3107 | "Number" {$$=registry_getnumberclass();}
3110 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
3111 MAYBETYPE: {PASS12 $$=0;}
3113 /* ----------function calls, delete, constructor calls ------ */
3115 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3116 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3118 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3119 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3120 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3122 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3126 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3127 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3128 $$.number= $1.number+1;
3129 $$.cc = code_append($1.cc, $2.c);
3133 NEW : "new" E XX MAYBE_PARAM_VALUES {
3134 typedcode_t v = node_read($2);
3136 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3138 code_t*paramcode = $4.cc;
3139 if($$.c->opcode == OPCODE_GETPROPERTY) {
3140 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3141 $$.c = code_cutlast($$.c);
3142 $$.c = code_append($$.c, paramcode);
3143 $$.c = abc_constructprop2($$.c, name, $4.number);
3144 multiname_destroy(name);
3145 } else if(is_getlocal($$.c)) {
3146 $$.c = code_append($$.c, paramcode);
3147 $$.c = abc_construct($$.c, $4.number);
3148 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3150 classinfo_t*c = v.t->data;
3152 $$.c = abc_findpropstrict2(0, &m);
3153 $$.c = code_append($$.c, paramcode);
3154 $$.c = abc_constructprop2($$.c, &m, $4.number);
3155 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3156 int slot = (int)(ptroff_t)$$.c->data[0];
3157 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3158 multiname_t*name = t->name;
3159 $$.c = code_cutlast($$.c);
3160 $$.c = code_append($$.c, paramcode);
3161 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3163 $$.c = code_append($$.c, paramcode);
3164 $$.c = abc_construct($$.c, $4.number);
3168 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3171 $$.c = abc_coerce_a($$.c);
3176 /* TODO: use abc_call (for calling local variables),
3177 abc_callstatic (for calling own methods)
3180 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3182 typedcode_t v = node_read($1);
3184 if($$.c->opcode == OPCODE_COERCE_A) {
3185 $$.c = code_cutlast($$.c);
3187 code_t*paramcode = $3.cc;
3190 if($$.c->opcode == OPCODE_GETPROPERTY) {
3191 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3192 $$.c = code_cutlast($$.c);
3193 $$.c = code_append($$.c, paramcode);
3194 $$.c = abc_callproperty2($$.c, name, $3.number);
3195 multiname_destroy(name);
3196 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3197 int slot = (int)(ptroff_t)$$.c->data[0];
3198 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3199 if(t->kind!=TRAIT_METHOD) {
3200 //ok: flash allows to assign closures to members.
3202 multiname_t*name = t->name;
3203 $$.c = code_cutlast($$.c);
3204 $$.c = code_append($$.c, paramcode);
3205 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3206 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3207 } else if($$.c->opcode == OPCODE_GETSUPER) {
3208 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3209 $$.c = code_cutlast($$.c);
3210 $$.c = code_append($$.c, paramcode);
3211 $$.c = abc_callsuper2($$.c, name, $3.number);
3212 multiname_destroy(name);
3214 $$.c = abc_getglobalscope($$.c);
3215 $$.c = code_append($$.c, paramcode);
3216 $$.c = abc_call($$.c, $3.number);
3219 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3220 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3221 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3222 // calling a class is like a typecast
3223 $$.t = (classinfo_t*)v.t->data;
3226 $$.c = abc_coerce_a($$.c);
3230 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3231 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3232 if(!state->method) syntaxerror("super() not allowed outside of a function");
3233 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3236 $$.c = abc_getlocal_0($$.c);
3238 $$.c = code_append($$.c, $3.cc);
3240 this is dependent on the control path, check this somewhere else
3241 if(state->method->has_super)
3242 syntaxerror("constructor may call super() only once");
3244 state->method->has_super = 1;
3246 $$.c = abc_constructsuper($$.c, $3.number);
3247 $$.c = abc_pushundefined($$.c);
3251 DELETE: "delete" E {
3252 typedcode_t v = node_read($2);
3254 if($$.c->opcode == OPCODE_COERCE_A) {
3255 $$.c = code_cutlast($$.c);
3257 multiname_t*name = 0;
3258 if($$.c->opcode == OPCODE_GETPROPERTY) {
3259 $$.c->opcode = OPCODE_DELETEPROPERTY;
3260 } else if($$.c->opcode == OPCODE_GETSLOT) {
3261 int slot = (int)(ptroff_t)$$.c->data[0];
3262 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3263 $$.c = code_cutlast($$.c);
3264 $$.c = abc_deleteproperty2($$.c, name);
3266 $$.c = abc_getlocal_0($$.c);
3267 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3268 $$.c = abc_deleteproperty2($$.c, &m);
3270 $$.t = TYPE_BOOLEAN;
3273 RETURN: "return" %prec prec_none {
3274 $$ = abc_returnvoid(0);
3276 RETURN: "return" EXPRESSION {
3278 $$ = abc_returnvalue($$);
3281 // ----------------------- expression types -------------------------------------
3283 NONCOMMAEXPRESSION : E %prec below_lt {
3286 EXPRESSION : COMMA_EXPRESSION {
3289 COMMA_EXPRESSION : E %prec below_lt {
3290 $$ = mkmultinode(&node_comma, $1);
3292 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3293 $$ = multinode_extend($1, $3);
3295 VOIDEXPRESSION : E %prec below_minus {
3298 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3300 $$ = code_append($$, node_exec($3));
3303 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3304 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3306 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3307 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3308 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3309 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3310 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3312 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3314 $$.cc = code_append($$.cc, $1);
3315 $$.cc = code_append($$.cc, $3.c);
3318 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3320 $$.number = $1.number+2;
3321 $$.cc = code_append($$.cc, $3);
3322 $$.cc = code_append($$.cc, $5.c);
3325 // ----------------------- expression evaluation -------------------------------------
3327 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3328 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3329 E : NEW {$$ = mkcodenode($1);}
3330 E : DELETE {$$ = mkcodenode($1);}
3331 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3332 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3335 $$ = mkconstnode($1);
3346 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3348 v.c = abc_getlex2(v.c, &m);
3349 v.c = abc_pushstring(v.c, $1.pattern);
3350 v.c = abc_construct(v.c, 1);
3352 v.c = abc_getlex2(v.c, &m);
3353 v.c = abc_pushstring(v.c, $1.pattern);
3354 v.c = abc_pushstring(v.c, $1.options);
3355 v.c = abc_construct(v.c, 2);
3363 state->method->need_arguments = 1;
3366 v.c = abc_getlocal(0, state->method->need_arguments);
3372 E : '[' MAYBE_EXPRESSION_LIST ']' {
3375 v.c = code_append(v.c, $2.cc);
3376 v.c = abc_newarray(v.c, $2.number);
3377 v.t = registry_getarrayclass();
3382 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3385 v.c = code_append(v.c, $2.cc);
3386 v.c = abc_newobject(v.c, $2.number/2);
3387 v.t = registry_getobjectclass();
3391 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3392 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3393 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3394 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3395 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3396 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3397 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3398 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3399 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3400 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3401 E : '!' E {$$ = mknode1(&node_not, $2);}
3402 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3403 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3404 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3405 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3406 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3407 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3408 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3409 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3410 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3411 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3412 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3413 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3414 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3415 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3416 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3417 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3418 E : "typeof" E {$$ = mknode1(&node_typeof, $2);}
3419 E : "void" E {$$ = mknode1(&node_void, $2);}
3420 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3421 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3422 E : '-' E {$$ = mknode1(&node_neg, $2);}
3423 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3424 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3425 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3426 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3427 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3428 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3429 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3430 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3431 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3432 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3433 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3434 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3435 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3436 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3438 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3439 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3440 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3441 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3443 E : "super" '.' T_IDENTIFIER
3444 { if(!state->cls->info)
3445 syntaxerror("super keyword not allowed outside a class");
3446 classinfo_t*t = state->cls->info->superclass;
3447 if(!t) t = TYPE_OBJECT;
3448 memberinfo_t*f = findmember_nsset(t, $3, 1, 0);
3449 MEMBER_MULTINAME(m, f, $3);
3452 v.c = abc_getlocal_0(v.c);
3453 v.c = abc_getsuper2(v.c, &m);
3454 v.t = slotinfo_gettype((slotinfo_t*)f);
3458 E : '@' T_IDENTIFIER {
3460 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3461 v.c = abc_getlex2(0, &m);
3466 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3469 typedcode_t v = node_read($1);
3470 typedcode_t w = node_read($5);
3472 int index = alloc_local();
3473 int result = alloc_local();
3474 int tmp = alloc_local();
3475 int xml = alloc_local();
3477 c = code_append(c, v.c);
3478 c = abc_checkfilter(c);
3479 c = abc_coerce_a(c); //hasnext2 converts to *
3480 c = abc_setlocal(c, xml);
3481 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3482 c = abc_getlex2(c, &m);
3483 c = abc_construct(c, 0);
3484 c = abc_setlocal(c, result);
3485 c = abc_pushbyte(c, 0);
3486 c = abc_setlocal(c, index);
3487 code_t*jmp = c = abc_jump(c, 0);
3488 code_t*loop = c = abc_label(c);
3489 c = abc_getlocal(c, xml);
3490 c = abc_getlocal(c, index);
3491 c = abc_nextvalue(c);
3493 c = abc_setlocal(c, tmp);
3494 c = abc_pushwith(c);
3495 c = code_append(c, w.c);
3496 c = abc_popscope(c);
3497 code_t*b = c = abc_iffalse(c, 0);
3498 c = abc_getlocal(c, result);
3499 c = abc_getlocal(c, index);
3500 c = abc_getlocal(c, tmp);
3501 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3502 c = abc_setproperty2(c, &m2);
3503 c = b->branch = jmp->branch = abc_nop(c);
3504 c = abc_kill(c, tmp);
3505 c = abc_hasnext2(c, xml, index);
3506 c = abc_iftrue(c, loop);
3507 c = abc_getlocal(c, result);
3508 c = abc_kill(c, xml);
3509 c = abc_kill(c, result);
3510 c = abc_kill(c, index);
3512 c = var_block(c, state->vars);
3520 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3521 ID_OR_NS : '*' {$$="*";}
3522 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3523 SUBNODE: X_IDENTIFIER
3527 node_t* resolve_identifier(const char*name);
3528 node_t* get_descendants(node_t*e,const char*ns,const char*subnode,char multi, char attr)
3530 typedcode_t v = node_read(e);
3533 multiname_t m = {0,0,0,subnode};
3534 namespace_t zero = {ZERONAMESPACE,"*"};
3535 if(!strcmp(ns,"*")) {
3537 m.type = attr?QNAMEA:QNAME;
3539 typedcode_t w = node_read(resolve_identifier(ns));
3540 if(!TYPE_IS_NAMESPACE(w.t)) {
3541 as3_softwarning("%s might not be a namespace", ns);
3543 v.c = code_append(v.c, w.c);
3544 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3545 m.type = attr?RTQNAMEA:RTQNAME;
3549 v.c = abc_getproperty2(v.c, &m);
3551 v.c = abc_getdescendants2(v.c, &m);
3554 if(TYPE_IS_XML(v.t)) {
3557 v.c = abc_coerce_a(v.c);
3560 return mkcodenode(v);
3564 E : E '.' ID_OR_NS "::" SUBNODE {
3565 $$ = get_descendants($1, $3, $5, 0, 0);
3567 E : E ".." SUBNODE {
3568 typedcode_t v = node_read($1);
3569 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3570 v.c = abc_getdescendants2(v.c, &m);
3574 E : E ".." ID_OR_NS "::" SUBNODE {
3575 $$ = get_descendants($1, $3, $5, 1, 0);
3577 E : E '.' '[' E ']' {
3578 typedcode_t v = node_read($1);
3579 typedcode_t w = node_read($4);
3580 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3581 v.c = code_append(v.c, w.c);
3582 v.c = converttype(w.c, w.t, TYPE_STRING);
3583 v.c = abc_getproperty2(v.c, &m);
3588 E : E '.' '@' SUBNODE {
3589 typedcode_t v = node_read($1);
3590 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3591 v.c = abc_getproperty2(v.c, &m);
3596 E : E '.' '@' ID_OR_NS "::" SUBNODE {
3597 $$ = get_descendants($1, $4, $6, 0, 1);
3600 E : E ".." '@' SUBNODE {
3601 typedcode_t v = node_read($1);
3602 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3603 v.c = abc_getdescendants2(v.c, &m);
3607 E : E ".." '@' ID_OR_NS "::" SUBNODE {
3608 $$ = get_descendants($1, $4, $6, 1, 1);
3611 E : E '.' '@' '[' E ']' {
3612 typedcode_t v = node_read($1);
3613 typedcode_t w = node_read($5);
3614 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3615 v.c = code_append(v.c, w.c);
3616 v.c = converttype(w.c, w.t, TYPE_STRING);
3617 v.c = abc_getproperty2(v.c, &m);
3621 E : E ".." '@' '[' E ']' {
3622 typedcode_t v = node_read($1);
3623 typedcode_t w = node_read($5);
3624 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3625 v.c = code_append(v.c, w.c);
3626 v.c = converttype(w.c, w.t, TYPE_STRING);
3627 v.c = abc_getdescendants2(v.c, &m);
3632 MEMBER : E '.' SUBNODE {
3633 typedcode_t v1 = node_read($1);
3635 classinfo_t*t = v1.t;
3637 if(TYPE_IS_CLASS(t) && t->data) {
3641 if(TYPE_IS_XML(t) && !findmember_nsset(t, $3, 1, is_static)) {
3642 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3643 $$.c = abc_getproperty2($$.c, &m);
3644 $$.c = abc_coerce_a($$.c);
3645 $$.t = TYPE_XMLLIST;
3647 if(t->subtype==INFOTYPE_UNRESOLVED) {
3648 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3650 memberinfo_t*f = findmember_nsset(t, $3, 1, is_static);
3652 if(f && !is_static != !(f->flags&FLAG_STATIC))
3654 if(f && f->slot && !noslot) {
3655 $$.c = abc_getslot($$.c, f->slot);
3658 if(!TYPE_IS_XMLLIST(t)) {
3659 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3662 MEMBER_MULTINAME(m, f, $3);
3663 $$.c = abc_getproperty2($$.c, &m);
3665 /* determine type */
3666 $$.t = slotinfo_gettype((slotinfo_t*)f);
3668 $$.c = abc_coerce_a($$.c);
3670 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3671 string_t*package = v1.c->data[0];
3672 char*package2 = concat3(package->str, ".", $3);
3674 slotinfo_t*a = registry_find(package->str, $3);
3677 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3678 registry_ispackage(package2)) {
3680 $$.c->data[0] = string_new4(package2);
3683 syntaxerror("couldn't resolve %s", package2);
3686 /* when resolving a property on an unknown type, we do know the
3687 name of the property (and don't seem to need the package), but
3688 we need to make avm2 try out all access modes */
3689 as3_softwarning("Resolving %s on unknown type", $3);
3690 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3691 $$.c = abc_getproperty2($$.c, &m);
3692 $$.c = abc_coerce_a($$.c);
3698 node_t* var_read(variable_t*v)
3701 o.c = abc_getlocal(0, v->index);
3703 return mkcodenode(o);
3706 node_t* resolve_identifier(const char*name)
3716 /* look at variables */
3717 if((v = find_variable(state, name))) {
3718 // name is a local variable
3721 if((v = find_slot(state->method, name))) {
3722 o.c = abc_getscopeobject(o.c, 1);
3723 o.c = abc_getslot(o.c, v->index);
3725 return mkcodenode(o);
3728 int i_am_static = state->method->is_static;
3730 if(!state->method->inner && !state->xmlfilter && state->cls)
3732 /* look at current class' members */
3733 if((f = findmember_nsset(state->cls->info, name, 1, i_am_static)))
3735 // name is a member or attribute in this class
3736 int var_is_static = (f->flags&FLAG_STATIC);
3738 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3739 /* if the variable is a constant (and we know what is evaluates to), we
3740 can just use the value itself */
3741 varinfo_t*v = (varinfo_t*)f;
3743 return mkconstnode(v->value);
3747 if(var_is_static >= i_am_static) {
3748 if(f->kind == INFOTYPE_METHOD) {
3749 o.t = TYPE_FUNCTION(f);
3754 if(var_is_static && !i_am_static) {
3755 /* access to a static member from a non-static location.
3756 do this via findpropstrict:
3757 there doesn't seem to be any non-lookup way to access
3758 static properties of a class */
3759 state->method->late_binding = 1;
3761 namespace_t ns = {f->access, f->package};
3762 multiname_t m = {QNAME, &ns, 0, name};
3763 o.c = abc_findpropstrict2(o.c, &m);
3764 o.c = abc_getproperty2(o.c, &m);
3765 return mkcodenode(o);
3766 } else if(f->slot>0) {
3767 o.c = abc_getlocal_0(o.c);
3768 o.c = abc_getslot(o.c, f->slot);
3769 return mkcodenode(o);
3771 MEMBER_MULTINAME(m, f, name);
3772 o.c = abc_getlocal_0(o.c);
3773 o.c = abc_getproperty2(o.c, &m);
3774 return mkcodenode(o);
3778 /* special case: it's allowed to access non-static constants
3779 from a static context */
3780 if(i_am_static && (f=findmember_nsset(state->cls->info, name, 1, 0))) {
3781 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3782 varinfo_t*v = (varinfo_t*)f;
3784 return mkconstnode(v->value);
3790 /* look at actual classes, in the current package and imported */
3791 if(!state->xmlfilter && (a = find_class(name))) {
3792 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3793 o.c = abc_getlocal_0(0);
3794 o.t = TYPE_CLASS((classinfo_t*)a);
3798 return mkcodenode(o);
3801 /* look through package prefixes */
3802 if(!state->xmlfilter &&
3803 (dict_contains(state->import_toplevel_packages, name) ||
3804 registry_ispackage(name))) {
3805 o.c = abc___pushpackage__(o.c, (char*)name);
3807 return mkcodenode(o); //?
3810 /* unknown object, let the avm2 resolve it */
3812 if(!state->method->inner && !state->xmlfilter) {
3813 /* we really should make inner functions aware of the class context */
3814 as3_warning("Couldn't resolve '%s', doing late binding", name);
3816 state->method->late_binding = 1;
3818 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3821 o.c = abc_findpropstrict2(o.c, &m);
3822 o.c = abc_getproperty2(o.c, &m);
3823 return mkcodenode(o);
3828 /* TODO: causes 16 r/r conflicts */
3829 VAR_READ : T_NAMESPACE {
3831 $$ = resolve_identifier($1);
3834 VAR_READ : T_IDENTIFIER {
3836 /* Queue unresolved identifiers for checking against the parent
3837 function's variables.
3838 We consider everything which is not a local variable "unresolved".
3839 This encompasses class names, members of the surrounding class
3840 etc. which is *correct* because local variables of the parent function
3844 if(!find_variable(state, $1)) {
3845 unknown_variable($1);
3846 /* let the compiler know that it might want to check the current directory/package
3847 for this identifier- maybe there's a file $1.as defining $1. */
3848 as3_schedule_class_noerror(state->package, $1);
3854 $$ = resolve_identifier($1);
3857 // ----------------- namespaces -------------------------------------------------
3860 void add_active_url(const char*url)
3864 list_append(state->active_namespace_urls, n);
3868 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3870 NEW(namespace_decl_t,n);
3875 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3877 NEW(namespace_decl_t,n);
3882 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3884 NEW(namespace_decl_t,n);
3889 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3891 trie_put(active_namespaces, (unsigned char*)$2->name, (void*)$2->url);
3893 namespace_t access = modifiers2access(&$1);
3894 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3895 var->type = TYPE_NAMESPACE;
3897 ns.access = ACCESS_NAMESPACE;
3899 var->value = constant_new_namespace(&ns);
3902 MULTINAME(m, TYPE_NAMESPACE);
3903 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3904 t->value = var->value;
3905 t->type_name = multiname_clone(&m);
3911 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3914 $$ = code_append($$, node_read($4).c);
3915 $$ = abc_dxnslate($$);
3918 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3920 const char*url = $3->name;
3922 varinfo_t*s = (varinfo_t*)$3;
3923 if(s->kind == INFOTYPE_UNRESOLVED) {
3924 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3926 syntaxerror("Couldn't resolve namespace %s", $3->name);
3929 if(!s || s->kind != INFOTYPE_VAR)
3930 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3931 if(!s->value || !NS_TYPE(s->value->type))
3932 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3933 url = s->value->ns->name;
3935 trie_put(active_namespaces, (unsigned char*)$3->name, (void*)url);
3936 add_active_url(url);