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, $4, 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 /*if(s && s->kind == INFOTYPE_VAR && TYPE_IS_NAMESPACE(s->type)) {
2576 trie_put(active_namespaces, (unsigned char*)$2->name, 0);
2578 state_has_imports();
2579 dict_put(state->imports, $2->name, $2);
2580 import_toplevel($2->package);
2583 IMPORT : "import" PACKAGE '.' '*' {
2585 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2586 as3_schedule_package($2);
2591 state_has_imports();
2592 list_append(state->wildcard_imports, i);
2593 import_toplevel(i->package);
2597 /* ------------ classes and interfaces (header) -------------- */
2599 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2600 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2601 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2602 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2604 $$.flags=$1.flags|$2.flags;
2605 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2606 $$.ns=$1.ns?$1.ns:$2.ns;
2609 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2610 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2611 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2612 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2613 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2614 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2615 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2616 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2617 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2618 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2622 EXTENDS : {PASS12 $$=0;}
2623 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2625 EXTENDS_LIST : {PASS12 $$=list_new();}
2626 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2628 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2629 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2631 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2632 EXTENDS IMPLEMENTS_LIST
2633 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2635 '}' {PASS12 endclass();$$=0;}
2637 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2639 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2640 startclass(&$1,$3,0,$4);}
2641 MAYBE_INTERFACE_BODY
2642 '}' {PASS12 endclass();$$=0;}
2644 /* ------------ classes and interfaces (body) -------------- */
2647 MAYBE_CLASS_BODY : CLASS_BODY
2648 CLASS_BODY : CLASS_BODY_ITEM
2649 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2650 CLASS_BODY_ITEM : ';'
2651 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2652 CLASS_BODY_ITEM : SLOT_DECLARATION
2653 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2654 CLASS_BODY_ITEM : '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
2656 CLASS_BODY_ITEM : CODE_STATEMENT {
2657 code_t*c = state->cls->static_init->header;
2658 c = code_append(c, $1);
2659 state->cls->static_init->header = c;
2662 MAYBE_INTERFACE_BODY :
2663 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2664 INTERFACE_BODY : IDECLARATION
2665 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2667 IDECLARATION : "var" T_IDENTIFIER {
2668 syntaxerror("variable declarations not allowed in interfaces");
2670 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2672 $1.flags |= FLAG_PUBLIC;
2673 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2674 syntaxerror("invalid method modifiers: interface methods always need to be public");
2676 startfunction(&$1,$3,$4,&$6,$8);
2677 endfunction(&$1,$3,$4,&$6,$8, 0);
2678 list_deep_free($6.list);
2681 /* ------------ classes and interfaces (body, slots ) ------- */
2684 static int slotstate_varconst = 0;
2685 static modifiers_t*slotstate_flags = 0;
2686 static void setslotstate(modifiers_t* flags, int varconst)
2688 slotstate_varconst = varconst;
2689 slotstate_flags = flags;
2692 if(flags->flags&FLAG_STATIC) {
2693 state->method = state->cls->static_init;
2695 state->method = state->cls->init;
2698 // reset to "default" state (all in class code is static by default) */
2699 state->method = state->cls->static_init;
2702 parserassert(state->method);
2705 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2707 int flags = modifiers->flags;
2708 namespace_t ns = modifiers2access(modifiers);
2711 multiname_t mname = {QNAME, &ns, 0, name};
2713 trait_list_t**traits;
2717 if(!global->init) global->init = abc_initscript(global->file);
2718 ns.name = state->package;
2719 traits = &global->init->traits;
2720 code = &global->init->method->body->code;
2721 } else if(flags&FLAG_STATIC) {
2723 traits = &state->cls->abc->static_traits;
2724 code = &state->cls->static_init->header;
2726 // instance variable
2727 traits = &state->cls->abc->traits;
2728 code = &state->cls->init->header;
2730 if(ns.access == ACCESS_PROTECTED) {
2731 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2737 *m = *multiname_clone(&mname);
2739 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2743 VARCONST: "var" | "const"
2745 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2747 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2748 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2750 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2753 int flags = slotstate_flags->flags;
2754 namespace_t ns = modifiers2access(slotstate_flags);
2758 varinfo_t* info = 0;
2760 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1, slotstate_flags->flags&FLAG_STATIC);
2762 check_override(i, flags);
2764 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1, slotstate_flags->flags&FLAG_STATIC);
2766 slotinfo_t*i = registry_find(state->package, $1);
2768 syntaxerror("package %s already contains '%s'", state->package, $1);
2770 if(ns.name && ns.name[0]) {
2771 syntaxerror("namespaces not allowed on package-level variables");
2773 info = varinfo_register_global(ns.access, state->package, $1);
2777 info->flags = flags;
2779 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2783 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2787 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2791 t->type_name = multiname_clone(&m);
2793 info->slot = t->slot_id;
2795 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2796 FIXME: is there a way to use slots and still don't have conflicting overrides?
2798 info->slot = t->slot_id = 0;
2800 constant_t cval = $3->type->eval($3);
2801 if(cval.type!=CONSTANT_UNKNOWN) {
2802 /* compile time constant */
2803 t->value = malloc(sizeof(constant_t));
2804 memcpy(t->value, &cval, sizeof(constant_t));
2805 info->value = constant_clone(t->value);
2807 typedcode_t v = node_read($3);
2808 /* initalization code (if needed) */
2810 if(v.c && !is_pushundefined(v.c)) {
2811 c = abc_getlocal_0(c);
2812 c = code_append(c, v.c);
2813 c = converttype(c, v.t, $2);
2815 c = abc_initproperty2(c, &mname);
2817 c = abc_setslot(c, t->slot_id);
2820 *code = code_append(*code, c);
2823 if(slotstate_varconst==KW_CONST) {
2824 t->kind= TRAIT_CONST;
2825 info->flags |= FLAG_CONST;
2832 /* ------------ constants -------------------------------------- */
2834 MAYBECONSTANT: {$$=0;}
2835 MAYBECONSTANT: '=' E {
2836 $$ = malloc(sizeof(constant_t));
2837 *$$ = node_eval($2);
2838 if($$->type == CONSTANT_UNKNOWN) {
2839 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2843 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2844 CONSTANT : T_INT {$$ = constant_new_int($1);}
2846 $$ = constant_new_uint($1);
2848 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2849 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2850 CONSTANT : "true" {$$ = constant_new_true($1);}
2851 CONSTANT : "false" {$$ = constant_new_false($1);}
2852 CONSTANT : "null" {$$ = constant_new_null($1);}
2853 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2854 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2856 /*CONSTANT : T_NAMESPACE {
2858 $$ = constant_new_namespace(namespace_new_namespace($1.url));
2861 /* ---------------------------xml ------------------------------ */
2864 static int xml_level = 0;
2868 multiname_t m = {QNAME, &stdns, 0, "XML"};
2871 v.c = abc_getlex2(v.c, &m);
2872 v.c = code_append(v.c, node_read($1).c);
2873 v.c = abc_construct(v.c, 1);
2878 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2879 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2880 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2882 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2885 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2888 XMLTEXT : {$$=mkstringnode("");}
2889 XMLTEXT : XMLTEXT XMLEXPR1 {
2890 $$ = mkaddnode($1,$2);
2892 XMLTEXT : XMLTEXT T_STRING {
2893 char* str = string_cstr(&$2);
2894 $$ = mkaddnode($1,mkstringnode(str));
2897 XMLTEXT : XMLTEXT '>' {
2898 $$ = mkaddnode($1, mkstringnode(">"));
2900 XML2 : XMLNODE XMLTEXT {
2901 $$ = mkaddnode($1,$2);
2903 XML2 : XML2 XMLNODE XMLTEXT {
2904 $$ = mkaddnode($1, mkaddnode($2,$3));
2906 XML_ID_OR_EXPR: T_IDENTIFIER {
2907 $$ = mkstringnode($1);
2909 XML_ID_OR_EXPR: XMLEXPR2 {
2913 MAYBE_XMLATTRIBUTES: {
2914 $$ = mkstringnode("");
2916 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {
2917 $$ = mkaddnode(mkstringnode(" "),$1);
2920 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2921 //$$ = allocprintf("<%s%s/>", $2, $3, $5, $8);
2922 $$ = mkaddnode(mkaddnode(mkaddnode(mkstringnode("<"),$2),$3),mkstringnode("/>"));
2924 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2925 //$$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2926 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2927 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),mkstringnode("</")),$8),mkstringnode(">"));
2929 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2930 //$$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2931 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2932 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),$6),mkstringnode("</")),$9),mkstringnode(">"));
2935 XMLATTRIBUTES: XMLATTRIBUTE {
2938 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {
2939 $$ = mkaddnode($1, mkaddnode(mkstringnode(" "),$2));
2941 XMLATTRIBUTE: XMLEXPR2 {
2944 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2945 char* str = string_cstr(&$3);
2946 $$ = mkaddnode($1, mkstringnode(concat2("=",str)));
2949 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2950 $$ = mkaddnode($1, mkaddnode(mkstringnode("=\""), mkaddnode($3, mkstringnode("\""))));
2952 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2953 $$ = mkaddnode(mkaddnode(mkstringnode(concat2($1,"=\"")), $3), mkstringnode("\""));
2955 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2956 char* str = string_cstr(&$3);
2957 $$=mkstringnode(allocprintf("%s=%s", $1,str));
2959 free($1);free((char*)$3.str);
2962 /* ------------ classes and interfaces (body, functions) ------- */
2964 // non-vararg version
2967 memset(&$$,0,sizeof($$));
2969 MAYBE_PARAM_LIST: PARAM_LIST {
2975 MAYBE_PARAM_LIST: "..." PARAM {
2977 memset(&$$,0,sizeof($$));
2979 list_append($$.list, $2);
2981 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2985 list_append($$.list, $4);
2989 PARAM_LIST: PARAM_LIST ',' PARAM {
2992 list_append($$.list, $3);
2996 memset(&$$,0,sizeof($$));
2997 list_append($$.list, $1);
3000 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
3002 $$ = rfx_calloc(sizeof(param_t));
3008 PARAM: T_IDENTIFIER MAYBECONSTANT {
3010 $$ = rfx_calloc(sizeof(param_t));
3012 $$->type = TYPE_ANY;
3020 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
3021 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
3024 endfunction(&$1,$3,$4,&$6,0,0);
3026 if(!state->method->info) syntaxerror("internal error");
3028 code_t*c = method_header(state->method);
3029 c = wrap_function(c, 0, $11);
3031 endfunction(&$1,$3,$4,&$6,$8,c);
3033 list_deep_free($6.list);
3037 MAYBE_IDENTIFIER: T_IDENTIFIER
3038 MAYBE_IDENTIFIER: {PASS12 $$=0;}
3039 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
3040 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
3043 endfunction(0,0,$2,&$4,0,0);
3045 methodinfo_t*f = state->method->info;
3046 if(!f || !f->kind) syntaxerror("internal error");
3048 code_t*c = method_header(state->method);
3049 c = wrap_function(c, 0, $9);
3051 int index = state->method->var_index;
3052 endfunction(0,0,$2,&$4,$6,c);
3054 $$.c = abc_getlocal(0, index);
3055 $$.t = TYPE_FUNCTION(f);
3057 PASS12 list_deep_free($4.list);
3061 /* ------------- package + class ids --------------- */
3063 CLASS: X_IDENTIFIER {
3064 PASS1 NEW(unresolvedinfo_t,c);
3065 memset(c, 0, sizeof(*c));
3066 c->kind = INFOTYPE_UNRESOLVED;
3068 c->package = get_package_from_name($1);
3070 c->nsset = get_current_imports();
3071 /* make the compiler look for this class in the current directory,
3073 as3_schedule_class_noerror(state->package, $1);
3075 $$ = (classinfo_t*)c;
3077 slotinfo_t*s = find_class($1);
3078 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
3079 $$ = (classinfo_t*)s;
3082 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
3083 PASS1 NEW(unresolvedinfo_t,c);
3084 memset(c, 0, sizeof(*c));
3085 c->kind = INFOTYPE_UNRESOLVED;
3088 $$ = (classinfo_t*)c;
3090 slotinfo_t*s = registry_find($1, $3);
3091 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
3093 $$ = (classinfo_t*)s;
3096 CLASS_SPEC: PACKAGEANDCLASS
3099 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
3100 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
3102 TYPE : CLASS_SPEC {PASS12 $$=$1;}
3103 | '*' {PASS12 $$=TYPE_ANY;}
3104 | "void" {PASS12 $$=TYPE_VOID;}
3106 | "String" {$$=registry_getstringclass();}
3107 | "int" {$$=registry_getintclass();}
3108 | "uint" {$$=registry_getuintclass();}
3109 | "Boolean" {$$=registry_getbooleanclass();}
3110 | "Number" {$$=registry_getnumberclass();}
3113 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
3114 MAYBETYPE: {PASS12 $$=0;}
3116 /* ----------function calls, delete, constructor calls ------ */
3118 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3119 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3121 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3122 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3123 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3125 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3129 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3130 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3131 $$.number= $1.number+1;
3132 $$.cc = code_append($1.cc, $2.c);
3136 NEW : "new" E XX MAYBE_PARAM_VALUES {
3137 typedcode_t v = node_read($2);
3139 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3141 code_t*paramcode = $4.cc;
3142 if($$.c->opcode == OPCODE_GETPROPERTY) {
3143 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3144 $$.c = code_cutlast($$.c);
3145 $$.c = code_append($$.c, paramcode);
3146 $$.c = abc_constructprop2($$.c, name, $4.number);
3147 multiname_destroy(name);
3148 } else if(is_getlocal($$.c)) {
3149 $$.c = code_append($$.c, paramcode);
3150 $$.c = abc_construct($$.c, $4.number);
3151 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3153 classinfo_t*c = v.t->data;
3155 $$.c = abc_findpropstrict2(0, &m);
3156 $$.c = code_append($$.c, paramcode);
3157 $$.c = abc_constructprop2($$.c, &m, $4.number);
3158 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3159 int slot = (int)(ptroff_t)$$.c->data[0];
3160 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3161 multiname_t*name = t->name;
3162 $$.c = code_cutlast($$.c);
3163 $$.c = code_append($$.c, paramcode);
3164 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3166 $$.c = code_append($$.c, paramcode);
3167 $$.c = abc_construct($$.c, $4.number);
3171 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3174 $$.c = abc_coerce_a($$.c);
3179 /* TODO: use abc_call (for calling local variables),
3180 abc_callstatic (for calling own methods)
3183 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3185 typedcode_t v = node_read($1);
3187 if($$.c->opcode == OPCODE_COERCE_A) {
3188 $$.c = code_cutlast($$.c);
3190 code_t*paramcode = $3.cc;
3193 if($$.c->opcode == OPCODE_GETPROPERTY) {
3194 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3195 $$.c = code_cutlast($$.c);
3196 $$.c = code_append($$.c, paramcode);
3197 $$.c = abc_callproperty2($$.c, name, $3.number);
3198 multiname_destroy(name);
3199 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3200 int slot = (int)(ptroff_t)$$.c->data[0];
3201 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3202 if(t->kind!=TRAIT_METHOD) {
3203 //ok: flash allows to assign closures to members.
3205 multiname_t*name = t->name;
3206 $$.c = code_cutlast($$.c);
3207 $$.c = code_append($$.c, paramcode);
3208 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3209 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3210 } else if($$.c->opcode == OPCODE_GETSUPER) {
3211 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3212 $$.c = code_cutlast($$.c);
3213 $$.c = code_append($$.c, paramcode);
3214 $$.c = abc_callsuper2($$.c, name, $3.number);
3215 multiname_destroy(name);
3217 $$.c = abc_getglobalscope($$.c);
3218 $$.c = code_append($$.c, paramcode);
3219 $$.c = abc_call($$.c, $3.number);
3222 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3223 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3224 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3225 // calling a class is like a typecast
3226 $$.t = (classinfo_t*)v.t->data;
3229 $$.c = abc_coerce_a($$.c);
3233 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3234 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3235 if(!state->method) syntaxerror("super() not allowed outside of a function");
3236 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3239 $$.c = abc_getlocal_0($$.c);
3241 $$.c = code_append($$.c, $3.cc);
3243 this is dependent on the control path, check this somewhere else
3244 if(state->method->has_super)
3245 syntaxerror("constructor may call super() only once");
3247 state->method->has_super = 1;
3249 $$.c = abc_constructsuper($$.c, $3.number);
3250 $$.c = abc_pushundefined($$.c);
3254 DELETE: "delete" E {
3255 typedcode_t v = node_read($2);
3257 if($$.c->opcode == OPCODE_COERCE_A) {
3258 $$.c = code_cutlast($$.c);
3260 multiname_t*name = 0;
3261 if($$.c->opcode == OPCODE_GETPROPERTY) {
3262 $$.c->opcode = OPCODE_DELETEPROPERTY;
3263 } else if($$.c->opcode == OPCODE_GETSLOT) {
3264 int slot = (int)(ptroff_t)$$.c->data[0];
3265 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3266 $$.c = code_cutlast($$.c);
3267 $$.c = abc_deleteproperty2($$.c, name);
3269 $$.c = abc_getlocal_0($$.c);
3270 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3271 $$.c = abc_deleteproperty2($$.c, &m);
3273 $$.t = TYPE_BOOLEAN;
3276 RETURN: "return" %prec prec_none {
3277 $$ = abc_returnvoid(0);
3279 RETURN: "return" EXPRESSION {
3281 $$ = abc_returnvalue($$);
3284 // ----------------------- expression types -------------------------------------
3286 NONCOMMAEXPRESSION : E %prec below_lt {
3289 EXPRESSION : COMMA_EXPRESSION {
3292 COMMA_EXPRESSION : E %prec below_lt {
3293 $$ = mkmultinode(&node_comma, $1);
3295 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3296 $$ = multinode_extend($1, $3);
3298 VOIDEXPRESSION : E %prec below_minus {
3301 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3303 $$ = code_append($$, node_exec($3));
3306 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3307 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3309 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3310 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3311 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3312 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3313 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3315 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3317 $$.cc = code_append($$.cc, $1);
3318 $$.cc = code_append($$.cc, $3.c);
3321 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3323 $$.number = $1.number+2;
3324 $$.cc = code_append($$.cc, $3);
3325 $$.cc = code_append($$.cc, $5.c);
3328 // ----------------------- expression evaluation -------------------------------------
3330 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3331 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3332 E : NEW {$$ = mkcodenode($1);}
3333 E : DELETE {$$ = mkcodenode($1);}
3334 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3335 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3338 $$ = mkconstnode($1);
3349 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3351 v.c = abc_getlex2(v.c, &m);
3352 v.c = abc_pushstring(v.c, $1.pattern);
3353 v.c = abc_construct(v.c, 1);
3355 v.c = abc_getlex2(v.c, &m);
3356 v.c = abc_pushstring(v.c, $1.pattern);
3357 v.c = abc_pushstring(v.c, $1.options);
3358 v.c = abc_construct(v.c, 2);
3366 state->method->need_arguments = 1;
3369 v.c = abc_getlocal(0, state->method->need_arguments);
3375 E : '[' MAYBE_EXPRESSION_LIST ']' {
3378 v.c = code_append(v.c, $2.cc);
3379 v.c = abc_newarray(v.c, $2.number);
3380 v.t = registry_getarrayclass();
3385 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3388 v.c = code_append(v.c, $2.cc);
3389 v.c = abc_newobject(v.c, $2.number/2);
3390 v.t = registry_getobjectclass();
3394 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3395 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3396 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3397 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3398 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3399 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3400 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3401 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3402 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3403 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3404 E : '!' E {$$ = mknode1(&node_not, $2);}
3405 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3406 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3407 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3408 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3409 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3410 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3411 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3412 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3413 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3414 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3415 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3416 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3417 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3418 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3419 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3420 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3421 E : "typeof" E {$$ = mknode1(&node_typeof, $2);}
3422 E : "void" E {$$ = mknode1(&node_void, $2);}
3423 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3424 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3425 E : '-' E {$$ = mknode1(&node_neg, $2);}
3426 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3427 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3428 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3429 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3430 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3431 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3432 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3433 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3434 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3435 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3436 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3437 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3438 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3439 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3441 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3442 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3443 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3444 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3446 E : "super" '.' T_IDENTIFIER
3447 { if(!state->cls->info)
3448 syntaxerror("super keyword not allowed outside a class");
3449 classinfo_t*t = state->cls->info->superclass;
3450 if(!t) t = TYPE_OBJECT;
3451 memberinfo_t*f = findmember_nsset(t, $3, 1, 0);
3452 MEMBER_MULTINAME(m, f, $3);
3455 v.c = abc_getlocal_0(v.c);
3456 v.c = abc_getsuper2(v.c, &m);
3457 v.t = slotinfo_gettype((slotinfo_t*)f);
3461 E : '@' T_IDENTIFIER {
3463 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3464 v.c = abc_getlex2(0, &m);
3469 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3472 typedcode_t v = node_read($1);
3473 typedcode_t w = node_read($5);
3475 int index = alloc_local();
3476 int result = alloc_local();
3477 int tmp = alloc_local();
3478 int xml = alloc_local();
3480 c = code_append(c, v.c);
3481 c = abc_checkfilter(c);
3482 c = abc_coerce_a(c); //hasnext2 converts to *
3483 c = abc_setlocal(c, xml);
3484 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3485 c = abc_getlex2(c, &m);
3486 c = abc_construct(c, 0);
3487 c = abc_setlocal(c, result);
3488 c = abc_pushbyte(c, 0);
3489 c = abc_setlocal(c, index);
3490 code_t*jmp = c = abc_jump(c, 0);
3491 code_t*loop = c = abc_label(c);
3492 c = abc_getlocal(c, xml);
3493 c = abc_getlocal(c, index);
3494 c = abc_nextvalue(c);
3496 c = abc_setlocal(c, tmp);
3497 c = abc_pushwith(c);
3498 c = code_append(c, w.c);
3499 c = abc_popscope(c);
3500 code_t*b = c = abc_iffalse(c, 0);
3501 c = abc_getlocal(c, result);
3502 c = abc_getlocal(c, index);
3503 c = abc_getlocal(c, tmp);
3504 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3505 c = abc_setproperty2(c, &m2);
3506 c = b->branch = jmp->branch = abc_nop(c);
3507 c = abc_kill(c, tmp);
3508 c = abc_hasnext2(c, xml, index);
3509 c = abc_iftrue(c, loop);
3510 c = abc_getlocal(c, result);
3511 c = abc_kill(c, xml);
3512 c = abc_kill(c, result);
3513 c = abc_kill(c, index);
3515 c = var_block(c, state->vars);
3523 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3524 ID_OR_NS : '*' {$$="*";}
3525 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3526 SUBNODE: X_IDENTIFIER
3530 node_t* resolve_identifier(const char*name);
3531 node_t* get_descendants(node_t*e,const char*ns,const char*subnode,char multi, char attr)
3533 typedcode_t v = node_read(e);
3536 multiname_t m = {0,0,0,subnode};
3537 namespace_t zero = {ZERONAMESPACE,"*"};
3538 if(!strcmp(ns,"*")) {
3540 m.type = attr?QNAMEA:QNAME;
3542 typedcode_t w = node_read(resolve_identifier(ns));
3543 if(!TYPE_IS_NAMESPACE(w.t)) {
3544 as3_softwarning("%s might not be a namespace", ns);
3546 v.c = code_append(v.c, w.c);
3547 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3548 m.type = attr?RTQNAMEA:RTQNAME;
3552 v.c = abc_getproperty2(v.c, &m);
3554 v.c = abc_getdescendants2(v.c, &m);
3557 if(TYPE_IS_XML(v.t)) {
3560 v.c = abc_coerce_a(v.c);
3563 return mkcodenode(v);
3567 E : E '.' ID_OR_NS "::" SUBNODE {
3568 $$ = get_descendants($1, $3, $5, 0, 0);
3570 E : E ".." SUBNODE {
3571 typedcode_t v = node_read($1);
3572 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3573 v.c = abc_getdescendants2(v.c, &m);
3577 E : E ".." ID_OR_NS "::" SUBNODE {
3578 $$ = get_descendants($1, $3, $5, 1, 0);
3580 E : E '.' '[' E ']' {
3581 typedcode_t v = node_read($1);
3582 typedcode_t w = node_read($4);
3583 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3584 v.c = code_append(v.c, w.c);
3585 v.c = converttype(w.c, w.t, TYPE_STRING);
3586 v.c = abc_getproperty2(v.c, &m);
3591 E : E '.' '@' SUBNODE {
3592 typedcode_t v = node_read($1);
3593 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3594 v.c = abc_getproperty2(v.c, &m);
3599 E : E '.' '@' ID_OR_NS "::" SUBNODE {
3600 $$ = get_descendants($1, $4, $6, 0, 1);
3603 E : E ".." '@' SUBNODE {
3604 typedcode_t v = node_read($1);
3605 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3606 v.c = abc_getdescendants2(v.c, &m);
3610 E : E ".." '@' ID_OR_NS "::" SUBNODE {
3611 $$ = get_descendants($1, $4, $6, 1, 1);
3614 E : E '.' '@' '[' E ']' {
3615 typedcode_t v = node_read($1);
3616 typedcode_t w = node_read($5);
3617 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3618 v.c = code_append(v.c, w.c);
3619 v.c = converttype(w.c, w.t, TYPE_STRING);
3620 v.c = abc_getproperty2(v.c, &m);
3624 E : E ".." '@' '[' E ']' {
3625 typedcode_t v = node_read($1);
3626 typedcode_t w = node_read($5);
3627 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3628 v.c = code_append(v.c, w.c);
3629 v.c = converttype(w.c, w.t, TYPE_STRING);
3630 v.c = abc_getdescendants2(v.c, &m);
3635 MEMBER : E '.' SUBNODE {
3636 typedcode_t v1 = node_read($1);
3638 classinfo_t*t = v1.t;
3640 if(TYPE_IS_CLASS(t) && t->data) {
3644 if(TYPE_IS_XML(t) && !findmember_nsset(t, $3, 1, is_static)) {
3645 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3646 $$.c = abc_getproperty2($$.c, &m);
3647 $$.c = abc_coerce_a($$.c);
3648 $$.t = TYPE_XMLLIST;
3650 if(t->subtype==INFOTYPE_UNRESOLVED) {
3651 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3653 memberinfo_t*f = findmember_nsset(t, $3, 1, is_static);
3655 if(f && !is_static != !(f->flags&FLAG_STATIC))
3657 if(f && f->slot && !noslot) {
3658 $$.c = abc_getslot($$.c, f->slot);
3661 if(!TYPE_IS_XMLLIST(t)) {
3662 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3665 MEMBER_MULTINAME(m, f, $3);
3666 $$.c = abc_getproperty2($$.c, &m);
3668 /* determine type */
3669 $$.t = slotinfo_gettype((slotinfo_t*)f);
3671 $$.c = abc_coerce_a($$.c);
3673 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3674 string_t*package = v1.c->data[0];
3675 char*package2 = concat3(package->str, ".", $3);
3677 slotinfo_t*a = registry_find(package->str, $3);
3680 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3681 registry_ispackage(package2)) {
3683 $$.c->data[0] = string_new4(package2);
3686 syntaxerror("couldn't resolve %s", package2);
3689 /* when resolving a property on an unknown type, we do know the
3690 name of the property (and don't seem to need the package), but
3691 we need to make avm2 try out all access modes */
3692 as3_softwarning("Resolving %s on unknown type", $3);
3693 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3694 $$.c = abc_getproperty2($$.c, &m);
3695 $$.c = abc_coerce_a($$.c);
3701 node_t* var_read(variable_t*v)
3704 o.c = abc_getlocal(0, v->index);
3706 return mkcodenode(o);
3709 node_t* resolve_identifier(const char*name)
3719 /* look at variables */
3720 if((v = find_variable(state, name))) {
3721 // name is a local variable
3724 if((v = find_slot(state->method, name))) {
3725 o.c = abc_getscopeobject(o.c, 1);
3726 o.c = abc_getslot(o.c, v->index);
3728 return mkcodenode(o);
3731 int i_am_static = state->method->is_static;
3733 if(!state->method->inner && !state->xmlfilter && state->cls)
3735 /* look at current class' members */
3736 if((f = findmember_nsset(state->cls->info, name, 1, i_am_static)))
3738 // name is a member or attribute in this class
3739 int var_is_static = (f->flags&FLAG_STATIC);
3741 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3742 /* if the variable is a constant (and we know what is evaluates to), we
3743 can just use the value itself */
3744 varinfo_t*v = (varinfo_t*)f;
3746 return mkconstnode(v->value);
3750 if(var_is_static >= i_am_static) {
3751 if(f->kind == INFOTYPE_METHOD) {
3752 o.t = TYPE_FUNCTION(f);
3757 if(var_is_static && !i_am_static) {
3758 /* access to a static member from a non-static location.
3759 do this via findpropstrict:
3760 there doesn't seem to be any non-lookup way to access
3761 static properties of a class */
3762 state->method->late_binding = 1;
3764 namespace_t ns = {f->access, f->package};
3765 multiname_t m = {QNAME, &ns, 0, name};
3766 o.c = abc_findpropstrict2(o.c, &m);
3767 o.c = abc_getproperty2(o.c, &m);
3768 return mkcodenode(o);
3769 } else if(f->slot>0) {
3770 o.c = abc_getlocal_0(o.c);
3771 o.c = abc_getslot(o.c, f->slot);
3772 return mkcodenode(o);
3774 MEMBER_MULTINAME(m, f, name);
3775 o.c = abc_getlocal_0(o.c);
3776 o.c = abc_getproperty2(o.c, &m);
3777 return mkcodenode(o);
3781 /* special case: it's allowed to access non-static constants
3782 from a static context */
3783 if(i_am_static && (f=findmember_nsset(state->cls->info, name, 1, 0))) {
3784 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3785 varinfo_t*v = (varinfo_t*)f;
3787 return mkconstnode(v->value);
3793 /* look at actual classes, in the current package and imported */
3794 if(!state->xmlfilter && (a = find_class(name))) {
3795 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3796 o.c = abc_getlocal_0(0);
3797 o.t = TYPE_CLASS((classinfo_t*)a);
3801 return mkcodenode(o);
3804 /* look through package prefixes */
3805 if(!state->xmlfilter &&
3806 (dict_contains(state->import_toplevel_packages, name) ||
3807 registry_ispackage(name))) {
3808 o.c = abc___pushpackage__(o.c, (char*)name);
3810 return mkcodenode(o); //?
3813 /* unknown object, let the avm2 resolve it */
3815 if(!state->method->inner && !state->xmlfilter) {
3816 /* we really should make inner functions aware of the class context */
3817 as3_warning("Couldn't resolve '%s', doing late binding", name);
3819 state->method->late_binding = 1;
3821 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3824 o.c = abc_findpropstrict2(o.c, &m);
3825 o.c = abc_getproperty2(o.c, &m);
3826 return mkcodenode(o);
3831 /* TODO: causes 16 r/r conflicts */
3832 VAR_READ : T_NAMESPACE {
3834 $$ = resolve_identifier($1);
3837 VAR_READ : T_IDENTIFIER {
3839 /* Queue unresolved identifiers for checking against the parent
3840 function's variables.
3841 We consider everything which is not a local variable "unresolved".
3842 This encompasses class names, members of the surrounding class
3843 etc. which is *correct* because local variables of the parent function
3847 if(!find_variable(state, $1)) {
3848 unknown_variable($1);
3849 /* let the compiler know that it might want to check the current directory/package
3850 for this identifier- maybe there's a file $1.as defining $1. */
3851 as3_schedule_class_noerror(state->package, $1);
3857 $$ = resolve_identifier($1);
3860 // ----------------- namespaces -------------------------------------------------
3863 void add_active_url(const char*url)
3867 list_append(state->active_namespace_urls, n);
3871 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3873 NEW(namespace_decl_t,n);
3878 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3880 NEW(namespace_decl_t,n);
3885 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3887 NEW(namespace_decl_t,n);
3892 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3894 trie_put(active_namespaces, (unsigned char*)$2->name, (void*)$2->url);
3896 namespace_t access = modifiers2access(&$1);
3897 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3898 var->type = TYPE_NAMESPACE;
3900 ns.access = ACCESS_NAMESPACE;
3902 var->value = constant_new_namespace(&ns);
3905 MULTINAME(m, TYPE_NAMESPACE);
3906 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3907 t->value = var->value;
3908 t->type_name = multiname_clone(&m);
3914 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3917 $$ = code_append($$, node_read($4).c);
3918 $$ = abc_dxnslate($$);
3921 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3924 varinfo_t*s = (varinfo_t*)$3;
3925 if(s->kind == INFOTYPE_UNRESOLVED) {
3926 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3928 syntaxerror("Couldn't resolve namespace %s", $3->name);
3931 if(!s || s->kind != INFOTYPE_VAR)
3932 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3933 if(!s->value || !NS_TYPE(s->value->type))
3934 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3936 const char*url = s->value->ns->name;
3937 trie_put(active_namespaces, (unsigned char*)$3->name, (void*)url);
3938 add_active_url(url);