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
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
270 %nonassoc "false" "true" "null" "undefined" "super" "function"
276 static int a3_error(char*s)
278 syntaxerror("%s", s);
279 return 0; //make gcc happy
282 static void parsererror(const char*file, int line, const char*f)
284 syntaxerror("internal error in %s, %s:%d", f, file, line);
287 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
290 static char* concat2(const char* t1, const char* t2)
294 char*text = malloc(l1+l2+1);
295 memcpy(text , t1, l1);
296 memcpy(text+l1, t2, l2);
300 static char* concat3(const char* t1, const char* t2, const char* t3)
305 char*text = malloc(l1+l2+l3+1);
306 memcpy(text , t1, l1);
307 memcpy(text+l1, t2, l2);
308 memcpy(text+l1+l2, t3, l3);
313 typedef struct _import {
316 DECLARE_LIST(import);
318 DECLARE(methodstate);
319 DECLARE_LIST(methodstate);
321 typedef struct _classstate {
327 methodstate_t*static_init;
329 //code_t*static_init;
330 parsedclass_t*dependencies;
332 char has_constructor;
335 struct _methodstate {
346 dict_t*unresolved_variables;
347 dict_t*allvars; // all variables (in all sublevels, but not for inner functions)
350 char uses_parent_function;
351 char no_variable_scoping;
359 int var_index; // for inner methods
360 int slot_index; // for inner methods
361 char is_a_slot; // for inner methods
366 abc_exception_list_t*exceptions;
368 methodstate_list_t*innerfunctions;
371 methodstate_t*methodstate_new()
373 NEW(methodstate_t,m);
374 m->allvars = dict_new();
377 void methodstate_destroy(methodstate_t*m)
379 dict_destroy(m->unresolved_variables); m->unresolved_variables = 0;
380 list_free(m->innerfunctions);m->innerfunctions=0;
383 DICT_ITERATE_DATA(m->allvars, void*, data) {free(data);}
388 typedef struct _state {
393 import_list_t*wildcard_imports;
394 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 state->namespaces = dict_new();
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 if(!state || !state->old)
533 syntaxerror("invalid nesting");
534 state_t*leaving = state;
538 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
539 methodstate_destroy(leaving->method);leaving->method=0;
541 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
546 state_destroy(leaving);
549 static code_t* method_header(methodstate_t*m);
550 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
551 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0);
554 static char* internal_filename_package = 0;
555 void initialize_file(char*filename)
558 syntaxerror("invalid call to initialize_file during parsing of another file");
562 state->package = internal_filename_package = strdup(filename);
564 global->token2info = dict_lookup(global->file2token2info,
565 current_filename // use long version
567 if(!global->token2info) {
568 global->token2info = dict_new2(&ptr_type);
569 dict_put(global->file2token2info, current_filename, global->token2info);
573 state->method = rfx_calloc(sizeof(methodstate_t));
574 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
575 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
576 state->method->allvars = dict_new();
578 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
579 state->method->variable_count = 0;
581 syntaxerror("internal error: skewed tokencount");
582 function_initvars(state->method, 0, 0, 0, 1);
589 if(!state || state->level!=1) {
590 syntaxerror("unexpected end of file in pass %d", as3_pass);
594 dict_del(global->file2token2info, current_filename);
595 code_t*header = method_header(state->method);
596 //if(global->init->method->body->code || global->init->traits) {
598 code_t*c = wrap_function(header, 0, global->init->method->body->code);
599 global->init->method->body->code = abc_returnvoid(c);
600 free(state->method);state->method=0;
604 //free(state->package);state->package=0; // used in registry
605 state_destroy(state);state=0;
608 void initialize_parser()
610 global = rfx_calloc(sizeof(global_t));
611 global->file = abc_file_new();
612 global->file->flags &= ~ABCFILE_LAZY;
613 global->file2token2info = dict_new();
614 global->token2info = 0;
615 global->classinit = abc_initscript(global->file);
618 void* finish_parser()
620 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
621 global->token2info=0;
623 initcode_add_classlist(global->classinit, global->classes);
628 typedef struct _variable {
634 methodstate_t*is_inner_method;
637 static variable_t* find_variable(state_t*s, const char*name)
639 if(s->method->no_variable_scoping) {
640 return dict_lookup(s->method->allvars, name);
645 v = dict_lookup(s->vars, name);
647 if(s->new_vars) break;
653 static variable_t* find_slot(methodstate_t*m, const char*name)
656 return dict_lookup(m->slots, name);
660 static variable_t* find_variable_safe(state_t*s, char*name)
662 variable_t* v = find_variable(s, name);
664 syntaxerror("undefined variable: %s", name);
668 static char variable_exists(char*name)
670 return dict_contains(state->vars, name);
673 static code_t*defaultvalue(code_t*c, classinfo_t*type)
675 parserassert(!type || type->kind!=INFOTYPE_UNRESOLVED);
676 if(TYPE_IS_INT(type)) {
677 c = abc_pushbyte(c, 0);
678 } else if(TYPE_IS_UINT(type)) {
679 c = abc_pushuint(c, 0);
680 } else if(TYPE_IS_FLOAT(type)) {
682 } else if(TYPE_IS_BOOLEAN(type)) {
683 c = abc_pushfalse(c);
684 } else if(TYPE_IS_STRING(type)) {
688 //c = abc_pushundefined(c);
689 syntaxerror("internal error: can't generate default value for * type");
693 c = abc_coerce2(c, &m);
698 static int alloc_local()
700 return state->method->variable_count++;
703 static variable_t* new_variable2(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
706 variable_t*v = find_slot(method, name);
714 v->index = alloc_local();
716 v->init = v->kill = init;
719 if(!method->no_variable_scoping)
721 if(dict_contains(state->vars, name)) {
722 syntaxerror("variable %s already defined", name);
724 dict_put(state->vars, name, v);
726 if(method->no_variable_scoping &&
728 dict_contains(state->method->allvars, name))
730 variable_t*v = dict_lookup(state->method->allvars, name);
731 if(v->type != type && (!v->type || v->type->kind!=INFOTYPE_UNRESOLVED)) {
732 syntaxerror("variable %s already defined.", name);
736 dict_put(state->method->allvars, name, v);
741 static int new_variable(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
743 return new_variable2(method, name, type, init, maybeslot)->index;
746 #define TEMPVARNAME "__as3_temp__"
749 variable_t*v = find_variable(state, TEMPVARNAME);
754 i = new_variable(state->method, TEMPVARNAME, 0, 0, 0);
759 static code_t* var_block(code_t*body, dict_t*vars)
764 DICT_ITERATE_DATA(vars, variable_t*, v) {
765 if(v->type && v->init) {
766 c = defaultvalue(c, v->type);
767 c = abc_setlocal(c, v->index);
769 if(v->type && v->kill) {
770 k = abc_kill(k, v->index);
777 if(x->opcode== OPCODE___BREAK__ ||
778 x->opcode== OPCODE___CONTINUE__) {
779 /* link kill code before break/continue */
780 code_t*e = code_dup(k);
781 code_t*s = code_start(e);
793 c = code_append(c, body);
794 c = code_append(c, k);
798 static void unknown_variable(char*name)
800 if(!state->method->unresolved_variables)
801 state->method->unresolved_variables = dict_new();
802 if(!dict_contains(state->method->unresolved_variables, name))
803 dict_put(state->method->unresolved_variables, name, 0);
806 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
808 if(m->uses_slots || m->innerfunctions || (m->late_binding && !m->inner)) {
809 c = abc_getlocal_0(c);
810 c = abc_pushscope(c);
813 /* FIXME: this alloc_local() causes variable indexes to be
814 different in pass2 than in pass1 */
815 if(!m->activation_var) {
816 m->activation_var = alloc_local();
819 c = abc_newactivation(c);
821 c = abc_pushscope(c);
822 c = abc_setlocal(c, m->activation_var);
824 c = abc_getlocal(c, m->activation_var);
825 c = abc_pushscope(c);
831 static code_t* method_header(methodstate_t*m)
835 c = add_scope_code(c, m, 1);
837 methodstate_list_t*l = m->innerfunctions;
839 parserassert(l->methodstate->abc);
840 if(m->uses_slots && l->methodstate->is_a_slot) {
841 c = abc_getscopeobject(c, 1);
842 c = abc_newfunction(c, l->methodstate->abc);
844 c = abc_setlocal(c, l->methodstate->var_index);
845 c = abc_setslot(c, l->methodstate->slot_index);
847 c = abc_newfunction(c, l->methodstate->abc);
848 c = abc_setlocal(c, l->methodstate->var_index);
850 free(l->methodstate);l->methodstate=0;
854 c = code_append(c, m->header);
857 if(m->is_constructor && !m->has_super) {
858 // call default constructor
859 c = abc_getlocal_0(c);
860 c = abc_constructsuper(c, 0);
864 /* all parameters that are used by inner functions
865 need to be copied from local to slot */
866 parserassert(m->activation_var);
867 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
868 if(v->is_parameter) {
869 c = abc_getlocal(c, m->activation_var);
870 c = abc_getlocal(c, v->index);
871 c = abc_setslot(c, v->index);
875 list_free(m->innerfunctions);
876 m->innerfunctions = 0;
881 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
883 c = code_append(c, header);
884 c = code_append(c, var_block(body, state->method->no_variable_scoping?state->method->allvars:state->vars));
885 /* append return if necessary */
886 if(!c || (c->opcode != OPCODE_RETURNVOID &&
887 c->opcode != OPCODE_RETURNVALUE)) {
888 c = abc_returnvoid(c);
893 static void startpackage(char*name)
896 state->package = strdup(name);
898 static void endpackage()
900 //used e.g. in classinfo_register:
901 //free(state->package);state->package=0;
905 #define FLAG_PUBLIC 256
906 #define FLAG_PROTECTED 512
907 #define FLAG_PRIVATE 1024
908 #define FLAG_PACKAGEINTERNAL 2048
909 #define FLAG_NAMESPACE 4096
911 static slotinfo_t* find_class(const char*name);
913 const char* lookup_namespace(const char*name)
917 const char*url = dict_lookup(s->namespaces, name);
923 registry_find(state->package, name);
924 if(( a = (varinfo_t*)find_class(name) )) {
925 if(a->kind == INFOTYPE_VAR) {
926 if(!a->value || !NS_TYPE(a->value->type))
927 syntaxerror("%s.%s is not a namespace", a->package, a->name);
928 return a->value->ns->name;
934 static namespace_t modifiers2access(modifiers_t*mod)
939 if(mod->flags&FLAG_NAMESPACE) {
940 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
941 syntaxerror("invalid combination of access levels and namespaces");
942 ns.access = ACCESS_NAMESPACE;
943 const char*url = lookup_namespace(mod->ns);
946 syntaxerror("unknown namespace: %s (pass %d)", mod->ns, as3_pass);
952 } else if(mod->flags&FLAG_PUBLIC) {
953 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
954 syntaxerror("invalid combination of access levels");
955 ns.access = ACCESS_PACKAGE;
956 } else if(mod->flags&FLAG_PRIVATE) {
957 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
958 syntaxerror("invalid combination of access levels");
959 ns.access = ACCESS_PRIVATE;
960 } else if(mod->flags&FLAG_PROTECTED) {
961 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
962 syntaxerror("invalid combination of access levels");
963 ns.access = ACCESS_PROTECTED;
965 ns.access = ACCESS_PACKAGEINTERNAL;
970 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse, char is_static)
972 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse, is_static);
975 static void innerfunctions2vars(methodstate_t*m)
977 methodstate_list_t*l = m->innerfunctions;
979 methodstate_t*m = l->methodstate;
981 variable_t* v = new_variable2(state->method, m->info->name, TYPE_FUNCTION(m->info), 0, 0);
982 m->var_index = v->index;
984 m->slot_index = m->is_a_slot;
985 v->is_inner_method = m;
990 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
995 index = new_variable(m, "this", 0, 0, 0);
996 else if(!m->is_global)
997 index = new_variable(m, (flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
999 index = new_variable(m, "globalscope", 0, 0, 0);
1001 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1002 printf("%s %d\n", name, v->index);
1005 parserassert(!index);
1010 for(p=params->list;p;p=p->next) {
1011 variable_t*v = new_variable2(m, p->param->name, p->param->type, 0, 1);
1012 v->is_parameter = 1;
1014 if(as3_pass==2 && m->need_arguments) {
1015 /* arguments can never be used by an innerfunction (the inner functions
1016 have their own arguments var), so it's ok to not initialize this until
1017 pass 2. (We don't know whether we need it before, anyway) */
1018 variable_t*v = new_variable2(m, "arguments", TYPE_ARRAY, 0, 0);
1019 m->need_arguments = v->index;
1023 innerfunctions2vars(m);
1026 m->scope_code = add_scope_code(m->scope_code, m, 0);
1028 /* exchange unresolved identifiers with the actual objects */
1029 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v1) {
1030 if(v1->type && v1->type->kind == INFOTYPE_UNRESOLVED) {
1031 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v1->type);
1032 if(!type || type->kind != INFOTYPE_CLASS) {
1033 syntaxerror("Couldn't find class %s::%s (%s)", v1->type->package, v1->type->name, name);
1040 DICT_ITERATE_ITEMS(m->allvars, char*, name2, variable_t*, v2) {
1041 if(v2->type && v2->type->kind == INFOTYPE_UNRESOLVED) {
1042 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v2->type);
1043 if(!type || type->kind != INFOTYPE_CLASS) {
1044 syntaxerror("Couldn't find class %s::%s (%s)", v2->type->package, v2->type->name, name2);
1054 char*as3_globalclass=0;
1055 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
1058 syntaxerror("inner classes now allowed");
1063 classinfo_list_t*mlist=0;
1065 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
1066 syntaxerror("invalid modifier(s)");
1068 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
1069 syntaxerror("public and internal not supported at the same time.");
1071 if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
1072 syntaxerror("protected and static not supported at the same time.");
1074 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1075 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1076 // all classes extend object
1077 extends = registry_getobjectclass();
1080 /* create the class name, together with the proper attributes */
1084 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
1085 access = ACCESS_PRIVATE; package = internal_filename_package;
1086 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
1087 access = ACCESS_PACKAGEINTERNAL; package = state->package;
1088 } else if(state->package!=internal_filename_package) {
1089 access = ACCESS_PACKAGE; package = state->package;
1091 syntaxerror("public classes only allowed inside a package");
1095 state->cls = rfx_calloc(sizeof(classstate_t));
1096 state->cls->init = methodstate_new();
1097 state->cls->static_init = methodstate_new();
1098 state->cls->static_init->is_static=FLAG_STATIC;
1099 /* notice: we make no effort to initialize the top variable (local0) here,
1100 even though it has special meaning. We just rely on the fact
1101 that pass 1 won't do anything with variables */
1103 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1105 /* set current method to constructor- all code within the class-level (except
1106 static variable initializations) will be executed during construction time */
1107 state->method = state->cls->init;
1109 if(registry_find(package, classname)) {
1110 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1112 /* build info struct */
1113 int num_interfaces = (list_length(implements));
1114 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1115 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1116 state->cls->info->superclass = extends;
1119 classinfo_list_t*l = implements;
1120 for(l=implements;l;l=l->next) {
1121 state->cls->info->interfaces[pos++] = l->classinfo;
1126 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1128 parserassert(state->cls && state->cls->info);
1130 state->method = state->cls->static_init;
1132 function_initvars(state->cls->init, 0, 0, 0, 1);
1133 state->cls->static_init->variable_count=1;
1134 function_initvars(state->cls->static_init, 0, 0, 0, 0);
1136 if(extends && (extends->flags & FLAG_FINAL))
1137 syntaxerror("Can't extend final class '%s'", extends->name);
1140 while(state->cls->info->interfaces[pos]) {
1141 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1142 syntaxerror("'%s' is not an interface",
1143 state->cls->info->interfaces[pos]->name);
1147 /* generate the abc code for this class */
1148 MULTINAME(classname2,state->cls->info);
1149 multiname_t*extends2 = sig2mname(extends);
1151 /* don't add the class to the class index just yet- that will be done later
1153 state->cls->abc = abc_class_new(0, &classname2, extends2);
1154 state->cls->abc->file = global->file;
1156 multiname_destroy(extends2);
1157 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1158 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1159 if(state->cls->info->flags&FLAG_INTERFACE) {
1160 abc_class_interface(state->cls->abc);
1163 for(mlist=implements;mlist;mlist=mlist->next) {
1164 MULTINAME(m, mlist->classinfo);
1165 abc_class_add_interface(state->cls->abc, &m);
1168 state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
1169 list_append(global->classes, state->cls->dependencies);
1171 /* flash.display.MovieClip handling */
1172 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1173 if(state->package && state->package[0]) {
1174 as3_globalclass = concat3(state->package, ".", classname);
1176 as3_globalclass = strdup(classname);
1182 static void endclass()
1185 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1187 c = abc_getlocal_0(c);
1188 c = abc_constructsuper(c, 0);
1189 state->cls->init->header = code_append(state->cls->init->header, c);
1190 state->cls->has_constructor=1;
1192 if(state->cls->init) {
1193 if(state->cls->info->flags&FLAG_INTERFACE) {
1194 if(state->cls->init->header)
1195 syntaxerror("interface can not have class-level code");
1197 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1198 code_t*c = method_header(state->cls->init);
1199 m->body->code = wrap_function(c, 0, m->body->code);
1202 if(state->cls->static_init) {
1203 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1204 code_t*c = method_header(state->cls->static_init);
1205 m->body->code = wrap_function(c, 0, m->body->code);
1208 trait_list_t*trait = state->cls->abc->traits;
1209 /* switch all protected members to the protected ns of this class */
1211 trait_t*t = trait->trait;
1212 if(t->name->ns->access == ACCESS_PROTECTED) {
1213 if(!state->cls->abc->protectedNS) {
1214 char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
1215 state->cls->abc->protectedNS = namespace_new_protected(n);
1216 state->cls->abc->flags |= CLASS_PROTECTED_NS;
1218 t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
1220 trait = trait->next;
1227 void check_code_for_break(code_t*c)
1230 if(c->opcode == OPCODE___BREAK__) {
1231 char*name = string_cstr(c->data[0]);
1232 syntaxerror("Unresolved \"break %s\"", name);
1234 if(c->opcode == OPCODE___CONTINUE__) {
1235 char*name = string_cstr(c->data[0]);
1236 syntaxerror("Unresolved \"continue %s\"", name);
1238 if(c->opcode == OPCODE___RETHROW__) {
1239 syntaxerror("Unresolved \"rethrow\"");
1241 if(c->opcode == OPCODE___FALLTHROUGH__) {
1242 syntaxerror("Unresolved \"fallthrough\"");
1244 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1245 char*name = string_cstr(c->data[0]);
1246 syntaxerror("Can't reference a package (%s) as such", name);
1252 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1254 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1255 if(TYPE_IS_NUMBER(t)) {
1256 xassert(c->type == CONSTANT_FLOAT
1257 || c->type == CONSTANT_INT
1258 || c->type == CONSTANT_UINT);
1259 } else if(TYPE_IS_UINT(t)) {
1260 xassert(c->type == CONSTANT_UINT ||
1261 (c->type == CONSTANT_INT && c->i>=0));
1262 } else if(TYPE_IS_INT(t)) {
1263 xassert(c->type == CONSTANT_INT);
1264 } else if(TYPE_IS_BOOLEAN(t)) {
1265 xassert(c->type == CONSTANT_TRUE
1266 || c->type == CONSTANT_FALSE);
1270 static void check_override(memberinfo_t*m, int flags)
1274 if(m->parent == state->cls->info && !((flags^m->flags)&FLAG_STATIC))
1275 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1277 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1278 if(m->access==ACCESS_PRIVATE)
1280 if(m->flags & FLAG_FINAL)
1281 syntaxerror("can't override final member %s", m->name);
1283 /* allow this. it's no issue.
1284 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1285 syntaxerror("can't override static member %s", m->name);*/
1287 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1288 syntaxerror("can't override non-static member %s with static declaration", m->name);
1290 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1291 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1292 if(m->kind == INFOTYPE_METHOD)
1293 syntaxerror("can't override without explicit 'override' declaration");
1295 syntaxerror("can't override '%s'", m->name);
1300 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1302 methodinfo_t*minfo = 0;
1303 namespace_t ns = modifiers2access(mod);
1306 minfo = methodinfo_register_global(ns.access, state->package, name);
1307 minfo->return_type = return_type;
1308 } else if(getset != KW_GET && getset != KW_SET) {
1310 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0, mod->flags&FLAG_STATIC);
1312 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1314 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name, mod->flags&FLAG_STATIC);
1315 minfo->return_type = return_type;
1316 // getslot on a member slot only returns "undefined", so no need
1317 // to actually store these
1318 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1320 //class getter/setter
1321 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1323 if(getset == KW_GET) {
1325 } else if(params->list && params->list->param && !params->list->next) {
1326 type = params->list->param->type;
1328 syntaxerror("setter function needs to take exactly one argument");
1329 // not sure wether to look into superclasses here, too
1330 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1, mod->flags&FLAG_STATIC);
1332 if(minfo->kind!=INFOTYPE_VAR)
1333 syntaxerror("class already contains a method called '%s'", name);
1334 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1335 syntaxerror("class already contains a field called '%s'", name);
1336 if(minfo->subtype & gs)
1337 syntaxerror("getter/setter for '%s' already defined", name);
1338 /* make a setter or getter into a getset */
1339 minfo->subtype |= gs;
1342 FIXME: this check needs to be done in pass 2
1344 if((!minfo->return_type != !type) ||
1345 (minfo->return_type && type &&
1346 !strcmp(minfo->return_type->name, type->name))) {
1347 syntaxerror("different type in getter and setter: %s and %s",
1348 minfo->return_type?minfo->return_type->name:"*",
1349 type?type->name:"*");
1352 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name, mod->flags&FLAG_STATIC);
1353 minfo->kind = INFOTYPE_VAR; //hack
1354 minfo->subtype = gs;
1355 minfo->return_type = type;
1358 /* can't assign a slot as getter and setter might have different slots */
1359 //minfo->slot = slot;
1361 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1362 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1363 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1368 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1370 //parserassert(state->method && state->method->info);
1372 methodstate_t*parent_method = state->method;
1376 return_type = 0; // not valid in pass 1
1378 v = new_variable2(parent_method, name, 0, 0, 0);
1383 state->new_vars = 1;
1386 state->method = methodstate_new();
1387 state->method->inner = 1;
1388 state->method->is_static = parent_method->is_static;
1389 state->method->variable_count = 0;
1390 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1392 v->is_inner_method = state->method;
1395 NEW(methodinfo_t,minfo);
1396 minfo->kind = INFOTYPE_METHOD;
1397 minfo->access = ACCESS_PACKAGEINTERNAL;
1399 state->method->info = minfo;
1402 list_append(parent_method->innerfunctions, state->method);
1404 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1406 function_initvars(state->method, 1, params, 0, 1);
1410 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1411 state->method->variable_count = 0;
1412 parserassert(state->method);
1414 state->method->info->return_type = return_type;
1415 function_initvars(state->method, 1, params, 0, 1);
1419 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1420 params_t*params, classinfo_t*return_type)
1422 if(state->method && state->method->info) {
1423 syntaxerror("not able to start another method scope");
1426 state->new_vars = 1;
1429 state->method = methodstate_new();
1430 state->method->has_super = 0;
1431 state->method->is_static = mod->flags&FLAG_STATIC;
1434 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1436 state->method->is_global = 1;
1437 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1439 if(state->method->is_constructor)
1440 name = "__as3_constructor__";
1442 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1444 function_initvars(state->method, 1, params, mod->flags, 1);
1446 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1450 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1451 state->method->variable_count = 0;
1452 parserassert(state->method);
1455 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2, mod->flags&FLAG_STATIC);
1456 check_override(m, mod->flags);
1460 state->cls->has_constructor |= state->method->is_constructor;
1463 function_initvars(state->method, 1, params, mod->flags, 1);
1467 static void insert_unresolved(methodstate_t*m, dict_t*xvars, dict_t*allvars)
1469 parserassert(m->inner);
1470 if(m->unresolved_variables) {
1471 dict_t*d = m->unresolved_variables;
1473 DICT_ITERATE_KEY(d, char*, id) {
1474 /* check parent method's variables */
1476 if(dict_contains(allvars, id)) {
1477 m->uses_parent_function = 1;
1478 state->method->uses_slots = 1;
1479 dict_put(xvars, id, 0);
1483 methodstate_list_t*ml = m->innerfunctions;
1485 insert_unresolved(ml->methodstate, xvars, allvars);
1490 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1491 params_t*params, classinfo_t*return_type, code_t*body)
1494 dict_t*xvars = dict_new();
1496 if(state->method->unresolved_variables) {
1497 DICT_ITERATE_KEY(state->method->unresolved_variables, char*, vname) {
1498 if(!state->method->no_variable_scoping && dict_contains(state->method->allvars, vname)) {
1499 variable_t*v = dict_lookup(state->method->allvars, vname);
1500 if(!v->is_inner_method) {
1501 state->method->no_variable_scoping = 1;
1502 as3_warning("function %s uses forward or outer block variable references (%s): switching into compatibility mode", name, vname);
1508 methodstate_list_t*ml = state->method->innerfunctions;
1510 insert_unresolved(ml->methodstate, xvars, state->method->allvars);
1514 if(state->method->uses_slots) {
1515 state->method->slots = dict_new();
1517 DICT_ITERATE_ITEMS(state->method->allvars, char*, name, variable_t*, v) {
1518 if(!name) syntaxerror("internal error");
1519 if(v->index && dict_contains(xvars, name)) {
1520 v->init = v->kill = 0;
1522 if(v->is_inner_method) {
1523 v->is_inner_method->is_a_slot = i;
1526 dict_put(state->method->slots, name, v);
1529 state->method->uses_slots = i;
1530 dict_destroy(state->vars);state->vars = 0;
1531 parserassert(state->new_vars);
1538 /*if(state->method->uses_parent_function){
1539 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1544 multiname_t*type2 = sig2mname(return_type);
1546 if(state->method->inner) {
1547 f = state->method->abc;
1548 abc_method_init(f, global->file, type2, 1);
1549 } else if(state->method->is_constructor) {
1550 f = abc_class_getconstructor(state->cls->abc, type2);
1551 } else if(!state->method->is_global) {
1552 namespace_t ns = modifiers2access(mod);
1553 multiname_t mname = {QNAME, &ns, 0, name};
1554 if(mod->flags&FLAG_STATIC)
1555 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1557 f = abc_class_method(state->cls->abc, type2, &mname);
1558 slot = f->trait->slot_id;
1560 namespace_t mname_ns = {state->method->info->access, state->package};
1561 multiname_t mname = {QNAME, &mname_ns, 0, name};
1563 f = abc_method_new(global->file, type2, 1);
1564 if(!global->init) global->init = abc_initscript(global->file);
1565 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1566 //abc_code_t*c = global->init->method->body->code;
1568 //flash doesn't seem to allow us to access function slots
1569 //state->method->info->slot = slot;
1571 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1572 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1573 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1574 if(params->varargs) f->flags |= METHOD_NEED_REST;
1575 if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
1579 for(p=params->list;p;p=p->next) {
1580 if(params->varargs && !p->next) {
1581 break; //varargs: omit last parameter in function signature
1583 multiname_t*m = sig2mname(p->param->type);
1584 list_append(f->parameters, m);
1585 if(p->param->value) {
1586 check_constant_against_type(p->param->type, p->param->value);
1587 opt=1;list_append(f->optional_parameters, p->param->value);
1589 syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
1592 if(state->method->slots) {
1593 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1595 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1596 multiname_t*type = sig2mname(v->type);
1597 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1598 t->slot_id = v->index;
1603 check_code_for_break(body);
1605 /* Seems this works now.
1606 if(state->method->exceptions && state->method->uses_slots) {
1607 as3_warning("try/catch and activation not supported yet within the same method");
1611 f->body->code = body;
1612 f->body->exceptions = state->method->exceptions;
1613 } else { //interface
1615 syntaxerror("interface methods can't have a method body");
1625 void breakjumpsto(code_t*c, char*name, code_t*jump)
1628 if(c->opcode == OPCODE___BREAK__) {
1629 string_t*name2 = c->data[0];
1630 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1631 c->opcode = OPCODE_JUMP;
1638 void continuejumpsto(code_t*c, char*name, code_t*jump)
1641 if(c->opcode == OPCODE___CONTINUE__) {
1642 string_t*name2 = c->data[0];
1643 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1644 c->opcode = OPCODE_JUMP;
1652 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1657 return abc_coerce_a(c);
1661 // cast an "any" type to a specific type. subject to
1662 // runtime exceptions
1663 return abc_coerce2(c, &m);
1666 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1667 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1668 // allow conversion between number types
1669 if(TYPE_IS_UINT(to))
1670 return abc_convert_u(c);
1671 else if(TYPE_IS_INT(to))
1672 return abc_convert_i(c);
1673 else if(TYPE_IS_NUMBER(to))
1674 return abc_convert_d(c);
1675 return abc_coerce2(c, &m);
1678 if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
1681 if(TYPE_IS_BOOLEAN(to))
1682 return abc_convert_b(c);
1683 if(TYPE_IS_STRING(to))
1684 return abc_convert_s(c);
1685 if(TYPE_IS_OBJECT(to))
1686 return abc_coerce2(c, &m);
1687 if(TYPE_IS_OBJECT(from) && TYPE_IS_XMLLIST(to))
1688 return abc_coerce2(c, &m);
1689 if(TYPE_IS_OBJECT(from) && TYPE_IS_ARRAY(to))
1690 return abc_coerce2(c, &m);
1692 classinfo_t*supertype = from;
1694 if(supertype == to) {
1695 /* target type is one of from's superclasses.
1696 (not sure we need this coerce - as far as the verifier
1697 is concerned, object==object (i think) */
1698 return abc_coerce2(c, &m);
1701 while(supertype->interfaces[t]) {
1702 if(supertype->interfaces[t]==to) {
1703 // target type is one of from's interfaces
1704 return abc_coerce2(c, &m);
1708 supertype = supertype->superclass;
1710 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1712 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1714 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1718 as3_error("can't convert type %s%s%s to %s%s%s",
1719 from->package, from->package[0]?".":"", from->name,
1720 to->package, to->package[0]?".":"", to->name);
1724 code_t* coerce_to_type(code_t*c, classinfo_t*t)
1727 return abc_coerce_a(c);
1728 } else if(TYPE_IS_STRING(t)) {
1729 return abc_coerce_s(c);
1732 return abc_coerce2(c, &m);
1736 char is_pushundefined(code_t*c)
1738 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1741 static const char* get_package_from_name(const char*name)
1743 /* try explicit imports */
1744 dictentry_t* e = dict_get_slot(state->imports, name);
1746 if(!strcmp(e->key, name)) {
1747 slotinfo_t*c = (slotinfo_t*)e->data;
1748 if(c) return c->package;
1754 static namespace_list_t*get_current_imports()
1756 namespace_list_t*searchlist = 0;
1758 list_append(searchlist, namespace_new_package(state->package));
1760 import_list_t*l = state->wildcard_imports;
1762 namespace_t*ns = namespace_new_package(l->import->package);
1763 list_append(searchlist, ns);
1766 list_append(searchlist, namespace_new_package(""));
1767 list_append(searchlist, namespace_new_package(internal_filename_package));
1771 static slotinfo_t* find_class(const char*name)
1775 c = registry_find(state->package, name);
1778 /* try explicit imports */
1779 dictentry_t* e = dict_get_slot(state->imports, name);
1782 if(!strcmp(e->key, name)) {
1783 c = (slotinfo_t*)e->data;
1789 /* try package.* imports */
1790 import_list_t*l = state->wildcard_imports;
1792 //printf("does package %s contain a class %s?\n", l->import->package, name);
1793 c = registry_find(l->import->package, name);
1798 /* try global package */
1799 c = registry_find("", name);
1802 /* try local "filename" package */
1803 c = registry_find(internal_filename_package, name);
1808 typedcode_t push_class(slotinfo_t*a)
1813 if(a->access == ACCESS_PACKAGEINTERNAL &&
1814 strcmp(a->package, state->package) &&
1815 strcmp(a->package, internal_filename_package)
1817 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1818 infotypename(a), a->name, a->package, state->package);
1822 if(a->kind != INFOTYPE_CLASS) {
1824 x.c = abc_findpropstrict2(x.c, &m);
1825 x.c = abc_getproperty2(x.c, &m);
1826 if(a->kind == INFOTYPE_METHOD) {
1827 methodinfo_t*f = (methodinfo_t*)a;
1828 x.t = TYPE_FUNCTION(f);
1830 varinfo_t*v = (varinfo_t*)a;
1835 if(state->cls && state->method == state->cls->static_init) {
1836 /* we're in the static initializer.
1837 record the fact that we're using this class here */
1838 parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
1840 classinfo_t*c = (classinfo_t*)a;
1842 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1843 x.c = abc_getglobalscope(x.c);
1844 x.c = abc_getslot(x.c, c->slot);
1847 x.c = abc_getlex2(x.c, &m);
1849 x.t = TYPE_CLASS(c);
1855 char is_break_or_jump(code_t*c)
1859 if(c->opcode == OPCODE_JUMP ||
1860 c->opcode == OPCODE___BREAK__ ||
1861 c->opcode == OPCODE___CONTINUE__ ||
1862 c->opcode == OPCODE_THROW ||
1863 c->opcode == OPCODE_RETURNVOID ||
1864 c->opcode == OPCODE_RETURNVALUE) {
1870 #define IS_FINALLY_TARGET(op) \
1871 ((op) == OPCODE___CONTINUE__ || \
1872 (op) == OPCODE___BREAK__ || \
1873 (op) == OPCODE_RETURNVOID || \
1874 (op) == OPCODE_RETURNVALUE || \
1875 (op) == OPCODE___RETHROW__)
1877 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1879 #define NEED_EXTRA_STACK_ARG
1880 code_t*finally_label = abc_nop(0);
1881 NEW(lookupswitch_t, l);
1887 code_t*prev = i->prev;
1888 if(IS_FINALLY_TARGET(i->opcode)) {
1891 if(i->opcode == OPCODE___RETHROW__ ||
1892 i->opcode == OPCODE_RETURNVALUE) {
1893 if(i->opcode == OPCODE___RETHROW__)
1894 i->opcode = OPCODE_THROW;
1896 p = abc_coerce_a(p);
1897 p = abc_setlocal(p, tempvar);
1899 p = abc_pushbyte(p, count++);
1900 p = abc_jump(p, finally_label);
1901 code_t*target = p = abc_label(p);
1902 #ifdef NEED_EXTRA_STACK_ARG
1906 p = abc_getlocal(p, tempvar);
1909 p->next = i;i->prev = p;
1910 list_append(l->targets, target);
1916 c = abc_pushbyte(c, -1);
1917 c = code_append(c, finally_label);
1918 c = code_append(c, finally);
1920 #ifdef NEED_EXTRA_STACK_ARG
1923 c = abc_lookupswitch(c, l);
1924 c = l->def = abc_label(c);
1925 #ifdef NEED_EXTRA_STACK_ARG
1932 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1936 code_t*prev = i->prev;
1937 if(IS_FINALLY_TARGET(i->opcode)) {
1938 if(i->opcode == OPCODE___RETHROW__)
1939 i->opcode = OPCODE_THROW;
1940 code_t*end = code_dup(finally);
1941 code_t*start = code_start(end);
1942 if(prev) prev->next = start;
1949 return code_append(c, finally);
1952 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1958 int num_insertion_points=0;
1960 if(IS_FINALLY_TARGET(i->opcode))
1961 num_insertion_points++;
1968 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1973 int simple_version_cost = (1+num_insertion_points)*code_size;
1974 int lookup_version_cost = 4*num_insertion_points + 5;
1976 if(cantdup || simple_version_cost > lookup_version_cost) {
1977 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1978 return insert_finally_lookup(c, finally, tempvar);
1980 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1981 return insert_finally_simple(c, finally, tempvar);
1985 #define PASS1 }} if(as3_pass == 1) {{
1986 #define PASS1END }} if(as3_pass == 2) {{
1987 #define PASS2 }} if(as3_pass == 2) {{
1988 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1989 #define PASS12END }} if(as3_pass == 2) {{
1990 #define PASS_ALWAYS }} {{
1996 /* ------------ code blocks / statements ---------------- */
1998 PROGRAM: MAYBE_PROGRAM_CODE_LIST
2000 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
2001 PROGRAM_CODE_LIST: PROGRAM_CODE
2002 | PROGRAM_CODE_LIST PROGRAM_CODE
2004 PROGRAM_CODE: PACKAGE_DECLARATION
2005 | INTERFACE_DECLARATION
2007 | FUNCTION_DECLARATION
2010 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
2013 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
2014 INPACKAGE_CODE_LIST: INPACKAGE_CODE
2015 | INPACKAGE_CODE_LIST INPACKAGE_CODE
2017 INPACKAGE_CODE: INTERFACE_DECLARATION
2019 | FUNCTION_DECLARATION
2022 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
2023 | '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
2026 MAYBECODE: CODE {$$=$1;}
2027 MAYBECODE: {$$=code_new();}
2029 CODE: CODE CODEPIECE {
2030 $$=code_append($1,$2);
2032 CODE: CODEPIECE {$$=$1;}
2034 // code which may appear outside of methods
2035 CODE_STATEMENT: DEFAULT_NAMESPACE
2036 CODE_STATEMENT: IMPORT
2038 CODE_STATEMENT: FOR_IN
2039 CODE_STATEMENT: WHILE
2040 CODE_STATEMENT: DO_WHILE
2041 CODE_STATEMENT: SWITCH
2043 CODE_STATEMENT: WITH
2045 CODE_STATEMENT: VOIDEXPRESSION
2046 CODE_STATEMENT: USE_NAMESPACE
2047 CODE_STATEMENT: NAMESPACE_DECLARATION
2048 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
2049 CODE_STATEMENT: '{' '}' {$$=0;}
2051 // code which may appear in methods (includes the above)
2052 CODEPIECE: ';' {$$=0;}
2053 CODEPIECE: CODE_STATEMENT
2054 CODEPIECE: VARIABLE_DECLARATION
2059 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
2069 //CODEBLOCK : '{' CODE '}' {$$=$2;}
2070 //CODEBLOCK : '{' '}' {$$=0;}
2071 CODEBLOCK : CODEPIECE ';' {$$=$1;}
2072 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
2074 /* ------------ package init code ------------------- */
2076 PACKAGE_INITCODE: CODE_STATEMENT {
2079 global->init = abc_initscript(global->file);
2080 code_t**cc = &global->init->method->body->code;
2081 *cc = code_append(*cc, $1);
2085 /* ------------ embed code ------------- */
2087 EMBED_START: %prec above_function {
2093 /* ------------ conditional compilation ------------- */
2095 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
2098 char*key = concat3($1,"::",$3);
2099 if(!definitions || !dict_contains(definitions, key)) {
2105 /* ------------ variables --------------------------- */
2108 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
2112 char do_init_variable(char*name)
2114 if(!state->method->no_variable_scoping)
2116 if(!state->new_vars)
2122 MAYBEEXPRESSION : '=' E {$$=$2;}
2123 | {$$=mkdummynode();}
2125 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2126 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2128 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2129 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2131 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2134 if(variable_exists($1))
2135 syntaxerror("Variable %s already defined", $1);
2137 new_variable(state->method, $1, $2, 1, 0);
2143 if(state->method->uses_slots) {
2144 v = find_slot(state->method, $1);
2146 // this variable is stored in a slot
2153 v = new_variable2(state->method, $1, $2, 1, 0);
2156 $$ = slot?abc_getscopeobject(0, 1):0;
2158 typedcode_t val = node_read($3);
2159 if(!is_subtype_of(val.t, $2)) {
2160 syntaxerror("Can't convert %s to %s", val.t->name, $2->name);
2163 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2164 $$ = code_append($$, val.c);
2165 $$ = converttype($$, val.t, $2);
2168 $$ = defaultvalue($$, $2);
2171 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2172 $$ = code_append($$, val.c);
2173 $$ = abc_coerce_a($$);
2175 // don't do anything
2183 $$ = abc_setslot($$, v->index);
2185 $$ = abc_setlocal($$, v->index);
2186 v->init = do_init_variable($1);
2190 /* ------------ control flow ------------------------- */
2192 IF_CODEBLOCK: {PASS12 new_state();} CODEBLOCK {
2193 $$ = var_block($2, state->vars);
2196 MAYBEELSE: %prec below_else {$$ = code_new();}
2197 MAYBEELSE: "else" IF_CODEBLOCK {$$=$2;}
2198 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2200 IF : "if" '(' EXPRESSION ')' IF_CODEBLOCK MAYBEELSE {
2202 $$ = code_append($$, $3.c);
2203 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2205 $$ = code_append($$, $5);
2207 myjmp = $$ = abc_jump($$, 0);
2209 myif->branch = $$ = abc_nop($$);
2211 $$ = code_append($$, $6);
2212 myjmp->branch = $$ = abc_nop($$);
2216 FOR_INIT : {$$=code_new();}
2217 FOR_INIT : VARIABLE_DECLARATION
2218 FOR_INIT : VOIDEXPRESSION
2220 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2221 // (I don't see any easy way to revolve this conflict otherwise, as we
2222 // can't touch VAR_READ without upsetting the precedence about "return")
2223 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2224 PASS1 $$=$2;new_variable(state->method, $2,0,1,0);
2225 PASS2 $$=$2;new_variable(state->method, $2,$3,1,0);
2227 FOR_IN_INIT : T_IDENTIFIER {
2232 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2233 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2235 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' IF_CODEBLOCK {
2236 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2238 $$ = code_append($$, $2);
2239 code_t*loopstart = $$ = abc_label($$);
2240 $$ = code_append($$, $4.c);
2241 code_t*myif = $$ = abc_iffalse($$, 0);
2242 $$ = code_append($$, $8);
2243 code_t*cont = $$ = abc_nop($$);
2244 $$ = code_append($$, $6);
2245 $$ = abc_jump($$, loopstart);
2246 code_t*out = $$ = abc_nop($$);
2247 breakjumpsto($$, $1.name, out);
2248 continuejumpsto($$, $1.name, cont);
2251 $$ = var_block($$, state->vars);
2255 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' IF_CODEBLOCK {
2256 node_t*n = resolve_identifier($2);
2257 typedcode_t w = node_write(n);
2259 int it = alloc_local();
2260 int array = alloc_local();
2263 $$ = code_append($$, $4.c);
2264 $$ = abc_coerce_a($$);
2265 $$ = abc_setlocal($$, array);
2266 $$ = abc_pushbyte($$, 0);
2267 $$ = abc_setlocal($$, it);
2269 code_t*loopstart = $$ = abc_label($$);
2271 $$ = abc_hasnext2($$, array, it);
2272 code_t*myif = $$ = abc_iffalse($$, 0);
2273 $$ = abc_getlocal($$, array);
2274 $$ = abc_getlocal($$, it);
2276 $$ = abc_nextname($$);
2278 $$ = abc_nextvalue($$);
2280 $$ = converttype($$, 0, w.t);
2281 $$ = code_append($$, w.c);
2283 $$ = code_append($$, $6);
2284 $$ = abc_jump($$, loopstart);
2286 code_t*out = $$ = abc_nop($$);
2287 breakjumpsto($$, $1.name, out);
2288 continuejumpsto($$, $1.name, loopstart);
2292 $$ = abc_kill($$, it);
2293 $$ = abc_kill($$, array);
2295 $$ = var_block($$, state->vars);
2299 WHILE : T_WHILE '(' EXPRESSION ')' IF_CODEBLOCK {
2303 code_t*myjmp = $$ = abc_jump($$, 0);
2304 code_t*loopstart = $$ = abc_label($$);
2305 $$ = code_append($$, $5);
2306 code_t*cont = $$ = abc_nop($$);
2307 myjmp->branch = cont;
2308 $$ = code_append($$, $3.c);
2309 $$ = abc_iftrue($$, loopstart);
2310 code_t*out = $$ = abc_nop($$);
2311 breakjumpsto($$, $1, out);
2312 continuejumpsto($$, $1, cont);
2315 DO_WHILE : T_DO IF_CODEBLOCK "while" '(' EXPRESSION ')' {
2317 code_t*loopstart = $$ = abc_label($$);
2318 $$ = code_append($$, $2);
2319 code_t*cont = $$ = abc_nop($$);
2320 $$ = code_append($$, $5.c);
2321 $$ = abc_iftrue($$, loopstart);
2322 code_t*out = $$ = abc_nop($$);
2323 breakjumpsto($$, $1, out);
2324 continuejumpsto($$, $1, cont);
2327 BREAK : "break" %prec prec_none {
2328 $$ = abc___break__(0, "");
2330 BREAK : "break" T_IDENTIFIER {
2331 $$ = abc___break__(0, $2);
2333 CONTINUE : "continue" %prec prec_none {
2334 $$ = abc___continue__(0, "");
2336 CONTINUE : "continue" T_IDENTIFIER {
2337 $$ = abc___continue__(0, $2);
2340 MAYBE_CASE_LIST : {$$=0;}
2341 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2342 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2343 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2344 CASE_LIST: CASE {$$=$1;}
2345 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2347 CASE: "case" E ':' MAYBECODE {
2348 $$ = abc_getlocal(0, state->switch_var);
2349 $$ = code_append($$, node_read($2).c);
2350 code_t*j = $$ = abc_ifne($$, 0);
2351 $$ = code_append($$, $4);
2352 if($$->opcode != OPCODE___BREAK__) {
2353 $$ = abc___fallthrough__($$, "");
2355 code_t*e = $$ = abc_nop($$);
2358 DEFAULT: "default" ':' MAYBECODE {
2361 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2362 $$ = node_read($4).c;
2363 $$ = abc_setlocal($$, state->switch_var);
2364 $$ = code_append($$, $7);
2366 code_t*out = $$ = abc_kill($$, state->switch_var);
2367 breakjumpsto($$, $1, out);
2369 code_t*c = $$,*lastblock=0;
2371 if(c->opcode == OPCODE_IFNE) {
2372 if(!c->next) syntaxerror("internal error in fallthrough handling");
2374 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2376 c->opcode = OPCODE_JUMP;
2377 c->branch = lastblock;
2379 /* fall through end of switch */
2380 c->opcode = OPCODE_NOP;
2386 $$ = var_block($$, state->vars);
2390 /* ------------ try / catch /finally ---------------- */
2392 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2393 state->exception_name=$3;
2394 PASS1 new_variable(state->method, $3, $4, 0, 0);
2395 PASS2 new_variable(state->method, $3, $4, 0, 0);
2398 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2399 multiname_t name = {QNAME, &name_ns, 0, $3};
2401 NEW(abc_exception_t, e)
2402 e->exc_type = sig2mname($4);
2403 e->var_name = multiname_clone(&name);
2407 int i = find_variable_safe(state, $3)->index;
2408 e->target = c = abc_nop(0);
2409 c = abc_setlocal(c, i);
2410 c = code_append(c, code_dup(state->method->scope_code));
2411 c = code_append(c, $8);
2414 c = var_block(c, state->vars);
2417 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2418 $4 = var_block($4, state->vars);
2422 NEW(abc_exception_t, e)
2423 e->exc_type = 0; //all exceptions
2424 e->var_name = 0; //no name
2427 e->to = code_append(e->to, $4);
2433 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2434 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2435 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2436 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2440 list_append($$.l,$2);
2441 $$.finally = $2->to;$2->to=0;
2444 CATCH_FINALLY_LIST: FINALLY {
2448 list_append($$.l,$1);
2449 $$.finally = $1->to;$1->to=0;
2453 TRY : "try" '{' {PASS12 new_state();
2454 state->method->has_exceptions=1;
2455 state->method->late_binding=1;//for invariant scope_code
2456 } MAYBECODE '}' CATCH_FINALLY_LIST {
2457 code_t*out = abc_nop(0);
2459 code_t*start = abc_nop(0);
2460 $$ = code_append(start, $4);
2461 if(!is_break_or_jump($4)) {
2462 $$ = abc_jump($$, out);
2464 code_t*end = $$ = abc_nop($$);
2468 tmp = alloc_local();
2470 abc_exception_list_t*l = $6.l;
2473 abc_exception_t*e = l->abc_exception;
2475 $$ = code_append($$, e->target);
2476 $$ = abc_jump($$, out);
2478 parserassert((ptroff_t)$6.finally);
2480 e->target = $$ = abc_nop($$);
2481 $$ = code_append($$, code_dup(state->method->scope_code));
2482 $$ = abc___rethrow__($$);
2490 $$ = code_append($$, out);
2492 $$ = insert_finally($$, $6.finally, tmp);
2494 list_concat(state->method->exceptions, $6.l);
2496 $$ = var_block($$, state->vars);
2500 /* ------------ throw ------------------------------- */
2502 THROW : "throw" EXPRESSION {
2506 THROW : "throw" %prec prec_none {
2507 if(!state->exception_name)
2508 syntaxerror("re-throw only possible within a catch block");
2509 variable_t*v = find_variable(state, state->exception_name);
2511 $$=abc_getlocal($$, v->index);
2515 /* ------------ with -------------------------------- */
2517 WITH_HEAD : "with" '(' EXPRESSION ')' {
2519 if(state->method->has_exceptions) {
2520 int v = alloc_local();
2521 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2522 state->method->scope_code = abc_pushwith(state->method->scope_code);
2527 WITH : WITH_HEAD CODEBLOCK {
2528 /* remove getlocal;pushwith from scope code again */
2529 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2532 if(state->method->has_exceptions) {
2534 $$ = abc_setlocal($$, $1.number);
2536 $$ = abc_pushwith($$);
2537 $$ = code_append($$, $2);
2538 $$ = abc_popscope($$);
2542 /* ------------ packages and imports ---------------- */
2544 X_IDENTIFIER: T_IDENTIFIER
2545 | "package" {PASS12 $$="package";}
2546 | "namespace" {PASS12 $$="namespace";}
2547 | "NaN" {PASS12 $$="NaN";}
2549 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2550 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2552 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2553 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2554 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2555 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2558 static void state_has_imports()
2560 state->wildcard_imports = list_clone(state->wildcard_imports);
2561 state->imports = dict_clone(state->imports);
2562 state->has_own_imports = 1;
2564 static void import_toplevel(const char*package)
2566 char* s = strdup(package);
2568 dict_put(state->import_toplevel_packages, s, 0);
2569 char*x = strrchr(s, '.');
2578 IMPORT : "import" T_IDENTIFIER {
2580 slotinfo_t*s = registry_find(state->package, $2);
2581 if(!s && as3_pass==1) {as3_schedule_class(state->package, $2);}
2582 state_has_imports();
2583 dict_put(state->imports, state->package, $2);
2586 IMPORT : "import" PACKAGEANDCLASS {
2588 slotinfo_t*s = registry_find($2->package, $2->name);
2589 if(!s && as3_pass==1) {
2590 as3_schedule_class($2->package, $2->name);
2592 /*if(s && s->kind == INFOTYPE_VAR && TYPE_IS_NAMESPACE(s->type)) {
2593 trie_put(active_namespaces, (unsigned char*)$2->name, 0);
2595 state_has_imports();
2596 dict_put(state->imports, $2->name, $2);
2597 import_toplevel($2->package);
2600 IMPORT : "import" PACKAGE '.' '*' {
2602 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2603 as3_schedule_package($2);
2608 state_has_imports();
2609 list_append(state->wildcard_imports, i);
2610 import_toplevel(i->package);
2614 /* ------------ classes and interfaces (header) -------------- */
2616 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2617 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2618 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2619 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2621 $$.flags=$1.flags|$2.flags;
2622 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2623 $$.ns=$1.ns?$1.ns:$2.ns;
2626 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2627 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2628 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2629 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2630 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2631 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2632 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2633 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2634 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2635 | T_IDENTIFIER {PASS12 $$.flags=FLAG_NAMESPACE;
2639 EXTENDS : {PASS12 $$=0;}
2640 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2642 EXTENDS_LIST : {PASS12 $$=list_new();}
2643 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2645 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2646 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2648 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2649 EXTENDS IMPLEMENTS_LIST
2650 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2652 '}' {PASS12 endclass();$$=0;}
2654 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2656 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2657 startclass(&$1,$3,0,$4);}
2658 MAYBE_INTERFACE_BODY
2659 '}' {PASS12 endclass();$$=0;}
2661 /* ------------ classes and interfaces (body) -------------- */
2664 MAYBE_CLASS_BODY : CLASS_BODY
2665 CLASS_BODY : CLASS_BODY_ITEM
2666 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2667 CLASS_BODY_ITEM : ';'
2668 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2669 CLASS_BODY_ITEM : SLOT_DECLARATION
2670 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2671 CLASS_BODY_ITEM : '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
2673 CLASS_BODY_ITEM : CODE_STATEMENT {
2674 code_t*c = state->cls->static_init->header;
2675 c = code_append(c, $1);
2676 state->cls->static_init->header = c;
2679 MAYBE_INTERFACE_BODY :
2680 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2681 INTERFACE_BODY : IDECLARATION
2682 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2684 IDECLARATION : "var" T_IDENTIFIER {
2685 syntaxerror("variable declarations not allowed in interfaces");
2687 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2689 $1.flags |= FLAG_PUBLIC;
2690 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2691 syntaxerror("invalid method modifiers: interface methods always need to be public");
2693 startfunction(&$1,$3,$4,&$6,$8);
2694 endfunction(&$1,$3,$4,&$6,$8, 0);
2695 list_deep_free($6.list);
2698 /* ------------ classes and interfaces (body, slots ) ------- */
2701 static int slotstate_varconst = 0;
2702 static modifiers_t*slotstate_flags = 0;
2703 static void setslotstate(modifiers_t* flags, int varconst)
2705 slotstate_varconst = varconst;
2706 slotstate_flags = flags;
2709 if(flags->flags&FLAG_STATIC) {
2710 state->method = state->cls->static_init;
2712 state->method = state->cls->init;
2715 // reset to "default" state (all in class code is static by default) */
2716 state->method = state->cls->static_init;
2719 parserassert(state->method);
2722 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2724 int flags = modifiers->flags;
2725 namespace_t ns = modifiers2access(modifiers);
2728 multiname_t mname = {QNAME, &ns, 0, name};
2730 trait_list_t**traits;
2734 if(!global->init) global->init = abc_initscript(global->file);
2735 ns.name = state->package;
2736 traits = &global->init->traits;
2737 code = &global->init->method->body->code;
2738 } else if(flags&FLAG_STATIC) {
2740 traits = &state->cls->abc->static_traits;
2741 code = &state->cls->static_init->header;
2743 // instance variable
2744 traits = &state->cls->abc->traits;
2745 code = &state->cls->init->header;
2747 if(ns.access == ACCESS_PROTECTED) {
2748 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2754 *m = *multiname_clone(&mname);
2756 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2760 VARCONST: "var" | "const"
2762 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2764 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2765 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2767 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2770 int flags = slotstate_flags->flags;
2771 namespace_t ns = modifiers2access(slotstate_flags);
2775 varinfo_t* info = 0;
2777 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1, slotstate_flags->flags&FLAG_STATIC);
2779 check_override(i, flags);
2781 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1, slotstate_flags->flags&FLAG_STATIC);
2783 slotinfo_t*i = registry_find(state->package, $1);
2785 syntaxerror("package %s already contains '%s'", state->package, $1);
2787 if(ns.name && ns.name[0]) {
2788 syntaxerror("namespaces not allowed on package-level variables");
2790 info = varinfo_register_global(ns.access, state->package, $1);
2794 info->flags = flags;
2796 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2800 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2804 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2808 t->type_name = multiname_clone(&m);
2810 info->slot = t->slot_id;
2812 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2813 FIXME: is there a way to use slots and still don't have conflicting overrides?
2815 info->slot = t->slot_id = 0;
2817 constant_t cval = $3->type->eval($3);
2818 if(cval.type!=CONSTANT_UNKNOWN) {
2819 /* compile time constant */
2820 t->value = malloc(sizeof(constant_t));
2821 memcpy(t->value, &cval, sizeof(constant_t));
2822 info->value = constant_clone(t->value);
2824 typedcode_t v = node_read($3);
2825 /* initalization code (if needed) */
2827 if(v.c && !is_pushundefined(v.c)) {
2828 c = abc_getlocal_0(c);
2829 c = code_append(c, v.c);
2830 c = converttype(c, v.t, $2);
2832 c = abc_initproperty2(c, &mname);
2834 c = abc_setslot(c, t->slot_id);
2837 *code = code_append(*code, c);
2840 if(slotstate_varconst==KW_CONST) {
2841 t->kind= TRAIT_CONST;
2842 info->flags |= FLAG_CONST;
2849 /* ------------ constants -------------------------------------- */
2851 MAYBECONSTANT: {$$=0;}
2852 MAYBECONSTANT: '=' E {
2853 $$ = malloc(sizeof(constant_t));
2854 *$$ = node_eval($2);
2855 if($$->type == CONSTANT_UNKNOWN) {
2856 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2860 CONSTANT : T_INT {$$ = constant_new_int($1);}
2862 $$ = constant_new_uint($1);
2864 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2865 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2866 CONSTANT : "true" {$$ = constant_new_true($1);}
2867 CONSTANT : "false" {$$ = constant_new_false($1);}
2868 CONSTANT : "null" {$$ = constant_new_null($1);}
2869 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2870 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2872 /* ---------------------------xml ------------------------------ */
2875 static int xml_level = 0;
2879 multiname_t m = {QNAME, &stdns, 0, "XML"};
2882 v.c = abc_getlex2(v.c, &m);
2883 v.c = code_append(v.c, node_read($1).c);
2884 v.c = abc_construct(v.c, 1);
2889 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2890 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2891 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2893 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2896 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2899 XMLTEXT : {$$=mkstringnode("");}
2900 XMLTEXT : XMLTEXT XMLEXPR1 {
2901 $$ = mkaddnode($1,$2);
2903 XMLTEXT : XMLTEXT T_STRING {
2904 char* str = string_cstr(&$2);
2905 $$ = mkaddnode($1,mkstringnode(str));
2908 XMLTEXT : XMLTEXT '>' {
2909 $$ = mkaddnode($1, mkstringnode(">"));
2911 XML2 : XMLNODE XMLTEXT {
2912 $$ = mkaddnode($1,$2);
2914 XML2 : XML2 XMLNODE XMLTEXT {
2915 $$ = mkaddnode($1, mkaddnode($2,$3));
2917 XML_ID_OR_EXPR: T_IDENTIFIER {
2918 $$ = mkstringnode($1);
2920 XML_ID_OR_EXPR: XMLEXPR2 {
2924 MAYBE_XMLATTRIBUTES: {
2925 $$ = mkstringnode("");
2927 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {
2928 $$ = mkaddnode(mkstringnode(" "),$1);
2931 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2932 //$$ = allocprintf("<%s%s/>", $2, $3, $5, $8);
2933 $$ = mkaddnode(mkaddnode(mkaddnode(mkstringnode("<"),$2),$3),mkstringnode("/>"));
2935 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2936 //$$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2937 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2938 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),mkstringnode("</")),$8),mkstringnode(">"));
2940 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2941 //$$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2942 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2943 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),$6),mkstringnode("</")),$9),mkstringnode(">"));
2946 XMLATTRIBUTES: XMLATTRIBUTE {
2949 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {
2950 $$ = mkaddnode($1, mkaddnode(mkstringnode(" "),$2));
2952 XMLATTRIBUTE: XMLEXPR2 {
2955 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2956 char* str = string_cstr(&$3);
2957 $$ = mkaddnode($1, mkstringnode(concat2("=",str)));
2960 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2961 $$ = mkaddnode($1, mkaddnode(mkstringnode("=\""), mkaddnode($3, mkstringnode("\""))));
2963 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2964 $$ = mkaddnode(mkaddnode(mkstringnode(concat2($1,"=\"")), $3), mkstringnode("\""));
2966 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2967 char* str = string_cstr(&$3);
2968 $$=mkstringnode(allocprintf("%s=%s", $1,str));
2970 free($1);free((char*)$3.str);
2973 /* ------------ classes and interfaces (body, functions) ------- */
2975 // non-vararg version
2978 memset(&$$,0,sizeof($$));
2980 MAYBE_PARAM_LIST: PARAM_LIST {
2986 MAYBE_PARAM_LIST: "..." PARAM {
2988 memset(&$$,0,sizeof($$));
2990 list_append($$.list, $2);
2992 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2996 list_append($$.list, $4);
3000 PARAM_LIST: PARAM_LIST ',' PARAM {
3003 list_append($$.list, $3);
3007 memset(&$$,0,sizeof($$));
3008 list_append($$.list, $1);
3011 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
3013 $$ = rfx_calloc(sizeof(param_t));
3019 PARAM: T_IDENTIFIER MAYBECONSTANT {
3021 $$ = rfx_calloc(sizeof(param_t));
3023 $$->type = TYPE_ANY;
3031 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
3032 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
3035 endfunction(&$1,$3,$4,&$6,0,0);
3037 if(!state->method->info) syntaxerror("internal error");
3039 code_t*c = method_header(state->method);
3040 c = wrap_function(c, 0, $11);
3042 endfunction(&$1,$3,$4,&$6,$8,c);
3044 list_deep_free($6.list);
3048 MAYBE_IDENTIFIER: T_IDENTIFIER
3049 MAYBE_IDENTIFIER: {PASS12 $$=0;}
3050 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
3051 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
3054 endfunction(0,0,$2,&$4,0,0);
3056 methodinfo_t*f = state->method->info;
3057 if(!f || !f->kind) syntaxerror("internal error");
3059 code_t*c = method_header(state->method);
3060 c = wrap_function(c, 0, $9);
3062 int index = state->method->var_index;
3063 endfunction(0,0,$2,&$4,$6,c);
3065 $$.c = abc_getlocal(0, index);
3066 $$.t = TYPE_FUNCTION(f);
3068 PASS12 list_deep_free($4.list);
3072 /* ------------- package + class ids --------------- */
3074 CLASS: X_IDENTIFIER {
3075 PASS1 NEW(unresolvedinfo_t,c);
3076 memset(c, 0, sizeof(*c));
3077 c->kind = INFOTYPE_UNRESOLVED;
3079 c->package = get_package_from_name($1);
3081 c->nsset = get_current_imports();
3082 /* make the compiler look for this class in the current directory,
3084 as3_schedule_class_noerror(state->package, $1);
3086 $$ = (classinfo_t*)c;
3088 slotinfo_t*s = find_class($1);
3089 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
3090 $$ = (classinfo_t*)s;
3094 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
3095 PASS1 NEW(unresolvedinfo_t,c);
3096 memset(c, 0, sizeof(*c));
3097 c->kind = INFOTYPE_UNRESOLVED;
3100 $$ = (classinfo_t*)c;
3102 slotinfo_t*s = registry_find($1, $3);
3103 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
3105 $$ = (classinfo_t*)s;
3109 CLASS_SPEC: PACKAGEANDCLASS
3112 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
3113 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
3115 TYPE : CLASS_SPEC {PASS12 $$=$1;}
3116 | '*' {PASS12 $$=TYPE_ANY;}
3117 | "void" {PASS12 $$=TYPE_VOID;}
3119 | "String" {$$=registry_getstringclass();}
3120 | "int" {$$=registry_getintclass();}
3121 | "uint" {$$=registry_getuintclass();}
3122 | "Boolean" {$$=registry_getbooleanclass();}
3123 | "Number" {$$=registry_getnumberclass();}
3126 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
3127 MAYBETYPE: {PASS12 $$=0;}
3129 /* ----------function calls, delete, constructor calls ------ */
3131 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3132 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3134 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3135 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3136 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3138 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3142 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3143 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3144 $$.number= $1.number+1;
3145 $$.cc = code_append($1.cc, $2.c);
3149 NEW : "new" E XX MAYBE_PARAM_VALUES {
3150 typedcode_t v = node_read($2);
3152 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3154 code_t*paramcode = $4.cc;
3155 if($$.c->opcode == OPCODE_GETPROPERTY) {
3156 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3157 $$.c = code_cutlast($$.c);
3158 $$.c = code_append($$.c, paramcode);
3159 $$.c = abc_constructprop2($$.c, name, $4.number);
3160 multiname_destroy(name);
3161 } else if(is_getlocal($$.c)) {
3162 $$.c = code_append($$.c, paramcode);
3163 $$.c = abc_construct($$.c, $4.number);
3164 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3166 classinfo_t*c = v.t->data;
3168 $$.c = abc_findpropstrict2(0, &m);
3169 $$.c = code_append($$.c, paramcode);
3170 $$.c = abc_constructprop2($$.c, &m, $4.number);
3171 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3172 int slot = (int)(ptroff_t)$$.c->data[0];
3173 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3174 multiname_t*name = t->name;
3175 $$.c = code_cutlast($$.c);
3176 $$.c = code_append($$.c, paramcode);
3177 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3179 $$.c = code_append($$.c, paramcode);
3180 $$.c = abc_construct($$.c, $4.number);
3184 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3187 $$.c = abc_coerce_a($$.c);
3192 /* TODO: use abc_call (for calling local variables),
3193 abc_callstatic (for calling own methods)
3196 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3198 typedcode_t v = node_read($1);
3200 if($$.c->opcode == OPCODE_COERCE_A) {
3201 $$.c = code_cutlast($$.c);
3203 code_t*paramcode = $3.cc;
3206 if($$.c->opcode == OPCODE_GETPROPERTY) {
3207 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3208 $$.c = code_cutlast($$.c);
3209 $$.c = code_append($$.c, paramcode);
3210 $$.c = abc_callproperty2($$.c, name, $3.number);
3211 multiname_destroy(name);
3212 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3213 int slot = (int)(ptroff_t)$$.c->data[0];
3214 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3215 if(t->kind!=TRAIT_METHOD) {
3216 //ok: flash allows to assign closures to members.
3218 multiname_t*name = t->name;
3219 $$.c = code_cutlast($$.c);
3220 $$.c = code_append($$.c, paramcode);
3221 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3222 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3223 } else if($$.c->opcode == OPCODE_GETSUPER) {
3224 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3225 $$.c = code_cutlast($$.c);
3226 $$.c = code_append($$.c, paramcode);
3227 $$.c = abc_callsuper2($$.c, name, $3.number);
3228 multiname_destroy(name);
3230 $$.c = abc_getglobalscope($$.c);
3231 $$.c = code_append($$.c, paramcode);
3232 $$.c = abc_call($$.c, $3.number);
3235 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3236 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3237 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3238 // calling a class is like a typecast
3239 $$.t = (classinfo_t*)v.t->data;
3242 $$.c = abc_coerce_a($$.c);
3246 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3247 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3248 if(!state->method) syntaxerror("super() not allowed outside of a function");
3249 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3252 $$.c = abc_getlocal_0($$.c);
3254 $$.c = code_append($$.c, $3.cc);
3256 this is dependent on the control path, check this somewhere else
3257 if(state->method->has_super)
3258 syntaxerror("constructor may call super() only once");
3260 state->method->has_super = 1;
3262 $$.c = abc_constructsuper($$.c, $3.number);
3263 $$.c = abc_pushundefined($$.c);
3267 DELETE: "delete" E {
3268 typedcode_t v = node_read($2);
3270 if($$.c->opcode == OPCODE_COERCE_A) {
3271 $$.c = code_cutlast($$.c);
3273 multiname_t*name = 0;
3274 if($$.c->opcode == OPCODE_GETPROPERTY) {
3275 $$.c->opcode = OPCODE_DELETEPROPERTY;
3276 } else if($$.c->opcode == OPCODE_GETSLOT) {
3277 int slot = (int)(ptroff_t)$$.c->data[0];
3278 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3279 $$.c = code_cutlast($$.c);
3280 $$.c = abc_deleteproperty2($$.c, name);
3282 $$.c = abc_getlocal_0($$.c);
3283 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3284 $$.c = abc_deleteproperty2($$.c, &m);
3286 $$.t = TYPE_BOOLEAN;
3289 RETURN: "return" %prec prec_none {
3290 $$ = abc_returnvoid(0);
3292 RETURN: "return" EXPRESSION {
3294 $$ = abc_returnvalue($$);
3297 // ----------------------- expression types -------------------------------------
3299 NONCOMMAEXPRESSION : E %prec below_lt {
3302 EXPRESSION : COMMA_EXPRESSION {
3305 COMMA_EXPRESSION : E %prec below_lt {
3306 $$ = mkmultinode(&node_comma, $1);
3308 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3309 $$ = multinode_extend($1, $3);
3311 VOIDEXPRESSION : E %prec below_minus {
3314 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3316 $$ = code_append($$, node_exec($3));
3319 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3320 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3322 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3323 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3324 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3325 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3326 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3328 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3330 $$.cc = code_append($$.cc, $1);
3331 $$.cc = code_append($$.cc, $3.c);
3334 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3336 $$.number = $1.number+2;
3337 $$.cc = code_append($$.cc, $3);
3338 $$.cc = code_append($$.cc, $5.c);
3341 // ----------------------- expression evaluation -------------------------------------
3343 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3344 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3345 E : NEW {$$ = mkcodenode($1);}
3346 E : DELETE {$$ = mkcodenode($1);}
3347 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3348 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3351 $$ = mkconstnode($1);
3362 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3364 v.c = abc_getlex2(v.c, &m);
3365 v.c = abc_pushstring(v.c, $1.pattern);
3366 v.c = abc_construct(v.c, 1);
3368 v.c = abc_getlex2(v.c, &m);
3369 v.c = abc_pushstring(v.c, $1.pattern);
3370 v.c = abc_pushstring(v.c, $1.options);
3371 v.c = abc_construct(v.c, 2);
3379 state->method->need_arguments = 1;
3382 v.c = abc_getlocal(0, state->method->need_arguments);
3388 E : '[' MAYBE_EXPRESSION_LIST ']' {
3391 v.c = code_append(v.c, $2.cc);
3392 v.c = abc_newarray(v.c, $2.number);
3393 v.t = registry_getarrayclass();
3398 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3401 v.c = code_append(v.c, $2.cc);
3402 v.c = abc_newobject(v.c, $2.number/2);
3403 v.t = registry_getobjectclass();
3407 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3408 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3409 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3410 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3411 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3412 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3413 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3414 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3415 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3416 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3417 E : '!' E {$$ = mknode1(&node_not, $2);}
3418 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3419 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3420 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3421 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3422 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3423 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3424 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3425 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3426 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3427 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3428 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3429 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3430 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3431 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3432 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3433 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3434 E : "typeof" E {$$ = mknode1(&node_typeof, $2);}
3435 E : "void" E {$$ = mknode1(&node_void, $2);}
3436 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3437 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3438 E : '-' E {$$ = mknode1(&node_neg, $2);}
3439 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3440 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3441 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3442 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3443 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3444 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3445 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3446 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3447 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3448 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3449 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3450 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3451 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3452 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3454 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3455 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3456 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3457 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3459 E : "super" '.' T_IDENTIFIER
3460 { if(!state->cls->info)
3461 syntaxerror("super keyword not allowed outside a class");
3462 classinfo_t*t = state->cls->info->superclass;
3463 if(!t) t = TYPE_OBJECT;
3464 memberinfo_t*f = findmember_nsset(t, $3, 1, 0);
3465 MEMBER_MULTINAME(m, f, $3);
3468 v.c = abc_getlocal_0(v.c);
3469 v.c = abc_getsuper2(v.c, &m);
3470 v.t = slotinfo_gettype((slotinfo_t*)f);
3474 E : '@' T_IDENTIFIER {
3476 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3477 v.c = abc_getlex2(0, &m);
3482 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3485 typedcode_t v = node_read($1);
3486 typedcode_t w = node_read($5);
3488 int index = alloc_local();
3489 int result = alloc_local();
3490 int tmp = alloc_local();
3491 int xml = alloc_local();
3493 c = code_append(c, v.c);
3494 c = abc_checkfilter(c);
3495 c = abc_coerce_a(c); //hasnext2 converts to *
3496 c = abc_setlocal(c, xml);
3497 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3498 c = abc_getlex2(c, &m);
3499 c = abc_construct(c, 0);
3500 c = abc_setlocal(c, result);
3501 c = abc_pushbyte(c, 0);
3502 c = abc_setlocal(c, index);
3503 code_t*jmp = c = abc_jump(c, 0);
3504 code_t*loop = c = abc_label(c);
3505 c = abc_getlocal(c, xml);
3506 c = abc_getlocal(c, index);
3507 c = abc_nextvalue(c);
3509 c = abc_setlocal(c, tmp);
3510 c = abc_pushwith(c);
3511 c = code_append(c, w.c);
3512 c = abc_popscope(c);
3513 code_t*b = c = abc_iffalse(c, 0);
3514 c = abc_getlocal(c, result);
3515 c = abc_getlocal(c, index);
3516 c = abc_getlocal(c, tmp);
3517 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3518 c = abc_setproperty2(c, &m2);
3519 c = b->branch = jmp->branch = abc_nop(c);
3520 c = abc_kill(c, tmp);
3521 c = abc_hasnext2(c, xml, index);
3522 c = abc_iftrue(c, loop);
3523 c = abc_getlocal(c, result);
3524 c = abc_kill(c, xml);
3525 c = abc_kill(c, result);
3526 c = abc_kill(c, index);
3528 c = var_block(c, state->vars);
3536 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3537 ID_OR_NS : '*' {$$="*";}
3538 SUBNODE: X_IDENTIFIER
3542 node_t* resolve_identifier(const char*name);
3543 node_t* get_descendants(node_t*e,const char*ns,const char*subnode,char multi, char attr)
3545 typedcode_t v = node_read(e);
3548 multiname_t m = {0,0,0,subnode};
3549 namespace_t zero = {ZERONAMESPACE,"*"};
3550 if(!strcmp(ns,"*")) {
3552 m.type = attr?QNAMEA:QNAME;
3554 typedcode_t w = node_read(resolve_identifier(ns));
3555 if(!TYPE_IS_NAMESPACE(w.t)) {
3556 as3_softwarning("%s might not be a namespace", ns);
3558 v.c = code_append(v.c, w.c);
3559 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3560 m.type = attr?RTQNAMEA:RTQNAME;
3564 v.c = abc_getproperty2(v.c, &m);
3566 v.c = abc_getdescendants2(v.c, &m);
3569 if(TYPE_IS_XML(v.t)) {
3572 v.c = abc_coerce_a(v.c);
3575 return mkcodenode(v);
3579 E : E '.' ID_OR_NS "::" SUBNODE {
3580 $$ = get_descendants($1, $3, $5, 0, 0);
3582 E : E ".." SUBNODE {
3583 typedcode_t v = node_read($1);
3584 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3585 v.c = abc_getdescendants2(v.c, &m);
3589 E : E ".." ID_OR_NS "::" SUBNODE {
3590 $$ = get_descendants($1, $3, $5, 1, 0);
3592 E : E '.' '[' E ']' {
3593 typedcode_t v = node_read($1);
3594 typedcode_t w = node_read($4);
3595 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3596 v.c = code_append(v.c, w.c);
3597 v.c = converttype(w.c, w.t, TYPE_STRING);
3598 v.c = abc_getproperty2(v.c, &m);
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_getproperty2(v.c, &m);
3611 E : E '.' '@' ID_OR_NS "::" SUBNODE {
3612 $$ = get_descendants($1, $4, $6, 0, 1);
3615 E : E ".." '@' SUBNODE {
3616 typedcode_t v = node_read($1);
3617 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3618 v.c = abc_getdescendants2(v.c, &m);
3622 E : E ".." '@' ID_OR_NS "::" SUBNODE {
3623 $$ = get_descendants($1, $4, $6, 1, 1);
3626 E : E '.' '@' '[' E ']' {
3627 typedcode_t v = node_read($1);
3628 typedcode_t w = node_read($5);
3629 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3630 v.c = code_append(v.c, w.c);
3631 v.c = converttype(w.c, w.t, TYPE_STRING);
3632 v.c = abc_getproperty2(v.c, &m);
3636 E : E ".." '@' '[' E ']' {
3637 typedcode_t v = node_read($1);
3638 typedcode_t w = node_read($5);
3639 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3640 v.c = code_append(v.c, w.c);
3641 v.c = converttype(w.c, w.t, TYPE_STRING);
3642 v.c = abc_getdescendants2(v.c, &m);
3647 MEMBER : E '.' SUBNODE {
3648 typedcode_t v1 = node_read($1);
3650 classinfo_t*t = v1.t;
3652 if(TYPE_IS_CLASS(t) && t->data) {
3656 if(TYPE_IS_XML(t) && !findmember_nsset(t, $3, 1, is_static)) {
3657 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3658 $$.c = abc_getproperty2($$.c, &m);
3659 $$.c = abc_coerce_a($$.c);
3660 $$.t = TYPE_XMLLIST;
3662 if(t->subtype==INFOTYPE_UNRESOLVED) {
3663 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3665 memberinfo_t*f = findmember_nsset(t, $3, 1, is_static);
3667 if(f && !is_static != !(f->flags&FLAG_STATIC))
3669 if(f && f->slot && !noslot) {
3670 $$.c = abc_getslot($$.c, f->slot);
3673 if(!TYPE_IS_XMLLIST(t)) {
3674 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3677 MEMBER_MULTINAME(m, f, $3);
3678 $$.c = abc_getproperty2($$.c, &m);
3680 /* determine type */
3681 $$.t = slotinfo_gettype((slotinfo_t*)f);
3683 $$.c = abc_coerce_a($$.c);
3685 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3686 string_t*package = v1.c->data[0];
3687 char*package2 = concat3(package->str, ".", $3);
3689 slotinfo_t*a = registry_find(package->str, $3);
3692 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3693 registry_ispackage(package2)) {
3695 $$.c->data[0] = string_new4(package2);
3698 syntaxerror("couldn't resolve %s", package2);
3701 /* when resolving a property on an unknown type, we do know the
3702 name of the property (and don't seem to need the package), but
3703 we need to make avm2 try out all access modes */
3704 as3_softwarning("Resolving %s on unknown type", $3);
3705 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3706 $$.c = abc_getproperty2($$.c, &m);
3707 $$.c = abc_coerce_a($$.c);
3713 node_t* var_read(variable_t*v)
3716 o.c = abc_getlocal(0, v->index);
3718 return mkcodenode(o);
3721 node_t* resolve_identifier(const char*name)
3731 /* look at variables */
3732 if((v = find_variable(state, name))) {
3733 // name is a local variable
3736 if((v = find_slot(state->method, name))) {
3737 o.c = abc_getscopeobject(o.c, 1);
3738 o.c = abc_getslot(o.c, v->index);
3740 return mkcodenode(o);
3743 int i_am_static = state->method->is_static;
3745 if(!state->method->inner && !state->xmlfilter && state->cls)
3747 /* look at current class' members */
3748 if((f = findmember_nsset(state->cls->info, name, 1, i_am_static)))
3750 // name is a member or attribute in this class
3751 int var_is_static = (f->flags&FLAG_STATIC);
3753 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3754 /* if the variable is a constant (and we know what is evaluates to), we
3755 can just use the value itself */
3756 varinfo_t*v = (varinfo_t*)f;
3758 return mkconstnode(v->value);
3762 if(var_is_static >= i_am_static) {
3763 if(f->kind == INFOTYPE_METHOD) {
3764 o.t = TYPE_FUNCTION(f);
3769 if(var_is_static && !i_am_static) {
3770 /* access to a static member from a non-static location.
3771 do this via findpropstrict:
3772 there doesn't seem to be any non-lookup way to access
3773 static properties of a class */
3774 state->method->late_binding = 1;
3776 namespace_t ns = {f->access, f->package};
3777 multiname_t m = {QNAME, &ns, 0, name};
3778 o.c = abc_findpropstrict2(o.c, &m);
3779 o.c = abc_getproperty2(o.c, &m);
3780 return mkcodenode(o);
3781 } else if(f->slot>0) {
3782 o.c = abc_getlocal_0(o.c);
3783 o.c = abc_getslot(o.c, f->slot);
3784 return mkcodenode(o);
3786 MEMBER_MULTINAME(m, f, name);
3787 o.c = abc_getlocal_0(o.c);
3788 o.c = abc_getproperty2(o.c, &m);
3789 return mkcodenode(o);
3793 /* special case: it's allowed to access non-static constants
3794 from a static context */
3795 if(i_am_static && (f=findmember_nsset(state->cls->info, name, 1, 0))) {
3796 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3797 varinfo_t*v = (varinfo_t*)f;
3799 return mkconstnode(v->value);
3805 /* look at actual classes, in the current package and imported */
3806 if(!state->xmlfilter && (a = find_class(name))) {
3808 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3809 o.c = abc_getlocal_0(0);
3810 o.t = TYPE_CLASS((classinfo_t*)a);
3814 return mkcodenode(o);
3817 /* look through package prefixes */
3818 if(!state->xmlfilter &&
3819 (dict_contains(state->import_toplevel_packages, name) ||
3820 registry_ispackage(name))) {
3821 o.c = abc___pushpackage__(o.c, (char*)name);
3823 return mkcodenode(o); //?
3826 /* unknown object, let the avm2 resolve it */
3828 if(!state->method->inner && !state->xmlfilter) {
3829 /* we really should make inner functions aware of the class context */
3830 as3_warning("Couldn't resolve '%s', doing late binding", name);
3832 state->method->late_binding = 1;
3834 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3837 o.c = abc_findpropstrict2(o.c, &m);
3838 o.c = abc_getproperty2(o.c, &m);
3839 return mkcodenode(o);
3844 VAR_READ : T_IDENTIFIER {
3846 /* Queue unresolved identifiers for checking against the parent
3847 function's variables.
3848 We consider everything which is not a local variable "unresolved".
3849 This encompasses class names, members of the surrounding class
3850 etc. which is *correct* because local variables of the parent function
3854 if(!find_variable(state, $1)) {
3855 unknown_variable($1);
3856 /* let the compiler know that it might want to check the current directory/package
3857 for this identifier- maybe there's a file $1.as defining $1. */
3858 as3_schedule_class_noerror(state->package, $1);
3864 $$ = resolve_identifier($1);
3867 // ----------------- namespaces -------------------------------------------------
3870 void add_active_url(const char*url)
3874 list_append(state->active_namespace_urls, n);
3878 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3880 NEW(namespace_decl_t,n);
3885 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3887 NEW(namespace_decl_t,n);
3892 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3894 NEW(namespace_decl_t,n);
3899 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3901 dict_put(state->namespaces, (unsigned char*)$2->name, (void*)$2->url);
3903 namespace_t access = modifiers2access(&$1);
3904 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3905 var->type = TYPE_NAMESPACE;
3907 ns.access = ACCESS_NAMESPACE;
3909 var->value = constant_new_namespace(&ns);
3912 MULTINAME(m, TYPE_NAMESPACE);
3913 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3914 t->value = var->value;
3915 t->type_name = multiname_clone(&m);
3921 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3924 $$ = code_append($$, node_read($4).c);
3925 $$ = abc_dxnslate($$);
3928 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3931 varinfo_t*s = (varinfo_t*)$3;
3932 if(s->kind == INFOTYPE_UNRESOLVED) {
3933 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3935 syntaxerror("Couldn't resolve namespace %s", $3->name);
3938 if(!s || s->kind != INFOTYPE_VAR)
3939 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3940 if(!s->value || !NS_TYPE(s->value->type))
3941 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3943 const char*url = s->value->ns->name;
3944 dict_put(state->namespaces, (unsigned char*)$3->name, (void*)url);
3945 add_active_url(url);