3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
31 #include "tokenizer.h"
48 enum yytokentype token;
50 classinfo_t*classinfo;
51 classinfo_list_t*classinfo_list;
53 slotinfo_list_t*slotinfo_list;
56 unsigned int number_uint;
60 //typedcode_list_t*value_list;
61 codeandnumber_t value_list;
67 for_start_t for_start;
68 abc_exception_t *exception;
71 namespace_decl_t* namespace_decl;
74 abc_exception_list_t *l;
80 %token<id> T_IDENTIFIER T_NAMESPACE
82 %token<regexp> T_REGEXP
84 %token<number_int> T_INT
85 %token<number_uint> T_UINT
86 %token<number_float> T_FLOAT
88 %token<id> T_FOR "for"
89 %token<id> T_WHILE "while"
91 %token<id> T_SWITCH "switch"
93 %token<token> KW_IMPLEMENTS "implements"
94 %token<token> KW_NAMESPACE "namespace"
95 %token<token> KW_PACKAGE "package"
96 %token<token> KW_PROTECTED "protected"
97 %token<token> KW_ARGUMENTS "arguments"
98 %token<token> KW_PUBLIC "public"
99 %token<token> KW_PRIVATE "private"
100 %token<token> KW_USE "use"
101 %token<token> KW_INTERNAL "internal"
102 %token<token> KW_NEW "new"
103 %token<token> KW_NATIVE "native"
104 %token<token> KW_FUNCTION "function"
105 %token<token> KW_FINALLY "finally"
106 %token<token> KW_UNDEFINED "undefined"
107 %token<token> KW_NAN "NaN"
108 %token<token> KW_CONTINUE "continue"
109 %token<token> KW_CLASS "class"
110 %token<token> KW_CONST "const"
111 %token<token> KW_CATCH "catch"
112 %token<token> KW_CASE "case"
113 %token<token> KW_SET "set"
114 %token<token> KW_VOID "void"
115 %token<token> KW_THROW "throw"
116 %token<token> KW_STATIC "static"
117 %token<token> KW_WITH "with"
118 %token<token> KW_INSTANCEOF "instanceof"
119 %token<token> KW_IMPORT "import"
120 %token<token> KW_RETURN "return"
121 %token<token> KW_TYPEOF "typeof"
122 %token<token> KW_INTERFACE "interface"
123 %token<token> KW_NULL "null"
124 %token<token> KW_VAR "var"
125 %token<token> KW_DYNAMIC "dynamic"
126 %token<token> KW_OVERRIDE "override"
127 %token<token> KW_FINAL "final"
128 %token<token> KW_EACH "each"
129 %token<token> KW_GET "get"
130 %token<token> KW_TRY "try"
131 %token<token> KW_SUPER "super"
132 %token<token> KW_EXTENDS "extends"
133 %token<token> KW_FALSE "false"
134 %token<token> KW_TRUE "true"
135 %token<token> KW_BOOLEAN "Boolean"
136 %token<token> KW_UINT "uint"
137 %token<token> KW_INT "int"
138 %token<token> KW_NUMBER "Number"
139 %token<token> KW_STRING "String"
140 %token<token> KW_DEFAULT "default"
141 %token<token> KW_DEFAULT_XML "default xml"
142 %token<token> KW_DELETE "delete"
143 %token<token> KW_IF "if"
144 %token<token> KW_ELSE "else"
145 %token<token> KW_BREAK "break"
146 %token<token> KW_IS "is"
147 %token<token> KW_IN "in"
148 %token<token> KW_AS "as"
150 %token<token> T_DICTSTART "{ (dictionary)"
151 %token<token> T_EQEQ "=="
152 %token<token> T_EQEQEQ "==="
153 %token<token> T_NE "!="
154 %token<token> T_NEE "!=="
155 %token<token> T_LE "<="
156 %token<token> T_GE ">="
157 %token<token> T_ORBY "|="
158 %token<token> T_DIVBY "/="
159 %token<token> T_MODBY "%="
160 %token<token> T_MULBY "*="
161 %token<token> T_ANDBY "&="
162 %token<token> T_PLUSBY "+="
163 %token<token> T_MINUSBY "-="
164 %token<token> T_XORBY "^="
165 %token<token> T_SHRBY ">>="
166 %token<token> T_SHLBY "<<="
167 %token<token> T_USHRBY ">>>="
168 %token<token> T_OROR "||"
169 %token<token> T_ANDAND "&&"
170 %token<token> T_COLONCOLON "::"
171 %token<token> T_MINUSMINUS "--"
172 %token<token> T_PLUSPLUS "++"
173 %token<token> T_DOTDOT ".."
174 %token<token> T_DOTDOTDOT "..."
175 %token<token> T_SHL "<<"
176 %token<token> T_USHR ">>>"
177 %token<token> T_SHR ">>"
179 %type <number_int> CONDITIONAL_COMPILATION EMBED_START
180 %type <for_start> FOR_START
181 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER ID_OR_NS SUBNODE
182 %type <namespace_decl> NAMESPACE_ID
183 %type <token> VARCONST
185 %type <code> CODEPIECE CODE_STATEMENT
186 %type <code> CODEBLOCK IF_CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
187 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
188 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
189 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
190 %type <exception> CATCH FINALLY
191 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
192 %type <code> CLASS_DECLARATION
193 %type <code> NAMESPACE_DECLARATION
194 %type <code> INTERFACE_DECLARATION
195 %type <code> VOIDEXPRESSION
196 %type <value> EXPRESSION NONCOMMAEXPRESSION
197 %type <node> MAYBEEXPRESSION
199 %type <node> E COMMA_EXPRESSION
200 %type <node> VAR_READ
201 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
202 %type <value> INNERFUNCTION
203 %type <code> USE_NAMESPACE DEFAULT_NAMESPACE
204 %type <code> FOR_INIT
206 %type <classinfo> MAYBETYPE
209 %type <params> PARAM_LIST
210 %type <params> MAYBE_PARAM_LIST
211 %type <flags> MAYBE_MODIFIERS
212 %type <flags> MODIFIER_LIST
213 %type <flags> MODIFIER
214 %type <constant> CONSTANT MAYBECONSTANT
215 %type <classinfo_list> IMPLEMENTS_LIST
216 %type <classinfo> EXTENDS CLASS_SPEC
217 %type <classinfo_list> EXTENDS_LIST
218 %type <classinfo> CLASS PACKAGEANDCLASS
219 %type <classinfo_list> CLASS_SPEC_LIST
220 %type <node> XMLEXPR1 XMLEXPR2 XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT XML_ID_OR_EXPR XML
221 %type <classinfo> TYPE
222 //%type <token> VARIABLE
225 //%type <token> T_IDENTIFIER
226 %type <value> FUNCTIONCALL
227 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES
228 %type <value_list> MAYBE_DICT_EXPRPAIR_LIST DICT_EXPRPAIR_LIST WITH_HEAD
231 // precedence: from low to high
235 %left below_semicolon
238 %nonassoc below_assignment // for ?:, contrary to spec
239 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
246 %nonassoc "==" "!=" "===" "!=="
247 %nonassoc "is" "as" "in"
249 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
250 %left "<<" ">>" ">>>"
254 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
256 %nonassoc below_curly
260 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
262 %left T_IDENTIFIER "arguments"
263 %left above_identifier
267 // needed for "return" precedence:
268 %nonassoc T_STRING T_REGEXP
269 %nonassoc T_INT T_UINT T_FLOAT KW_NAN
271 %nonassoc "false" "true" "null" "undefined" "super" "function"
278 static int a3_error(char*s)
280 syntaxerror("%s", s);
281 return 0; //make gcc happy
284 static void parsererror(const char*file, int line, const char*f)
286 syntaxerror("internal error in %s, %s:%d", f, file, line);
289 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
292 static char* concat2(const char* t1, const char* t2)
296 char*text = malloc(l1+l2+1);
297 memcpy(text , t1, l1);
298 memcpy(text+l1, t2, l2);
302 static char* concat3(const char* t1, const char* t2, const char* t3)
307 char*text = malloc(l1+l2+l3+1);
308 memcpy(text , t1, l1);
309 memcpy(text+l1, t2, l2);
310 memcpy(text+l1+l2, t3, l3);
315 typedef struct _import {
318 DECLARE_LIST(import);
320 DECLARE(methodstate);
321 DECLARE_LIST(methodstate);
323 typedef struct _classstate {
329 methodstate_t*static_init;
331 //code_t*static_init;
332 parsedclass_t*dependencies;
334 char has_constructor;
337 struct _methodstate {
348 dict_t*unresolved_variables;
351 char uses_parent_function;
352 char no_variable_scoping;
360 int var_index; // for inner methods
361 int slot_index; // for inner methods
362 char is_a_slot; // for inner methods
367 abc_exception_list_t*exceptions;
369 methodstate_list_t*innerfunctions;
372 void methodstate_destroy(methodstate_t*m)
374 dict_destroy(m->unresolved_variables);
375 m->unresolved_variables = 0;
376 list_free(m->innerfunctions);m->innerfunctions=0;
379 typedef struct _state {
384 import_list_t*wildcard_imports;
385 dict_t*import_toplevel_packages;
388 namespace_list_t*active_namespace_urls;
390 char has_own_imports;
391 char new_vars; // e.g. transition between two functions
392 char xmlfilter; // are we inside a xmlobj..() filter?
395 methodstate_t*method;
402 dict_t*allvars; // also contains variables from sublevels
405 typedef struct _global {
408 parsedclass_list_t*classes;
409 abc_script_t*classinit;
411 abc_script_t*init; //package-level code
414 dict_t*file2token2info;
417 static global_t*global = 0;
418 static state_t* state = 0;
422 /* protected handling here is a big hack: we just assume the protectedns
423 is package:class. the correct approach would be to add the proper
424 namespace to all protected members in the registry, even though that
425 would slow down searching */
426 #define MEMBER_MULTINAME(m,f,n) \
430 m##_ns.access = ((slotinfo_t*)(f))->access; \
431 if(m##_ns.access == ACCESS_NAMESPACE) \
432 m##_ns.name = ((slotinfo_t*)(f))->package; \
433 else if(m##_ns.access == ACCESS_PROTECTED && (f)->parent) \
434 m##_ns.name = concat3((f)->parent->package,":",(f)->parent->name); \
439 m.namespace_set = 0; \
440 m.name = ((slotinfo_t*)(f))->name; \
442 m.type = MULTINAME; \
444 m.namespace_set = &nopackage_namespace_set; \
448 /* warning: list length of namespace set is undefined */
449 #define MULTINAME_LATE(m, access, package) \
450 namespace_t m##_ns = {access, package}; \
451 namespace_set_t m##_nsset; \
452 namespace_list_t m##_l;m##_l.next = 0; \
453 m##_nsset.namespaces = &m##_l; \
454 m##_nsset = m##_nsset; \
455 m##_l.namespace = &m##_ns; \
456 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
458 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
459 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
460 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
461 static namespace_t stdns = {ACCESS_PACKAGE, ""};
462 static namespace_list_t nl4 = {&stdns,0};
463 static namespace_list_t nl3 = {&ns3,&nl4};
464 static namespace_list_t nl2 = {&ns2,&nl3};
465 static namespace_list_t nl1 = {&ns1,&nl2};
466 static namespace_set_t nopackage_namespace_set = {&nl1};
468 static dict_t*definitions=0;
469 void as3_set_define(const char*c)
472 definitions = dict_new();
473 if(!dict_contains(definitions,c))
474 dict_put(definitions,c,0);
477 static void new_state()
480 state_t*oldstate = state;
482 memcpy(s, state, sizeof(state_t)); //shallow copy
484 s->imports = dict_new();
486 if(!s->import_toplevel_packages) {
487 s->import_toplevel_packages = dict_new();
491 state->has_own_imports = 0;
492 state->vars = dict_new();
493 state->old = oldstate;
496 trie_remember(active_namespaces);
499 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
502 static void state_destroy(state_t*state)
504 if(state->has_own_imports) {
505 list_free(state->wildcard_imports);
506 dict_destroy(state->imports);state->imports=0;
508 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
509 dict_destroy(state->imports);state->imports=0;
512 dict_destroy(state->vars);state->vars=0;
514 if(state->new_vars && state->allvars) {
515 parserassert(!state->old || state->old->allvars != state->allvars);
516 DICT_ITERATE_DATA(state->allvars, void*, data) {
519 dict_destroy(state->allvars);
522 list_free(state->active_namespace_urls)
523 state->active_namespace_urls = 0;
528 static void old_state()
530 trie_rollback(active_namespaces);
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");
561 active_namespaces = trie_new();
564 state->package = internal_filename_package = strdup(filename);
565 state->allvars = dict_new();
567 global->token2info = dict_lookup(global->file2token2info,
568 current_filename // use long version
570 if(!global->token2info) {
571 global->token2info = dict_new2(&ptr_type);
572 dict_put(global->file2token2info, current_filename, global->token2info);
576 state->method = rfx_calloc(sizeof(methodstate_t));
577 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
578 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
580 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
581 state->method->variable_count = 0;
583 syntaxerror("internal error: skewed tokencount");
584 function_initvars(state->method, 0, 0, 0, 1);
591 if(!state || state->level!=1) {
592 syntaxerror("unexpected end of file in pass %d", as3_pass);
596 dict_del(global->file2token2info, current_filename);
597 code_t*header = method_header(state->method);
598 //if(global->init->method->body->code || global->init->traits) {
600 code_t*c = wrap_function(header, 0, global->init->method->body->code);
601 global->init->method->body->code = abc_returnvoid(c);
602 free(state->method);state->method=0;
606 //free(state->package);state->package=0; // used in registry
607 state_destroy(state);state=0;
610 void initialize_parser()
612 global = rfx_calloc(sizeof(global_t));
613 global->file = abc_file_new();
614 global->file->flags &= ~ABCFILE_LAZY;
615 global->file2token2info = dict_new();
616 global->token2info = 0;
617 global->classinit = abc_initscript(global->file);
620 void* finish_parser()
622 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
623 global->token2info=0;
625 initcode_add_classlist(global->classinit, global->classes);
630 typedef struct _variable {
636 methodstate_t*is_inner_method;
639 static variable_t* find_variable(state_t*s, char*name)
641 if(s->method->no_variable_scoping) {
642 return dict_lookup(s->allvars, name);
647 v = dict_lookup(s->vars, name);
649 if(s->new_vars) break;
655 static variable_t* find_slot(methodstate_t*m, const char*name)
658 return dict_lookup(m->slots, name);
662 static variable_t* find_variable_safe(state_t*s, char*name)
664 variable_t* v = find_variable(s, name);
666 syntaxerror("undefined variable: %s", name);
670 static char variable_exists(char*name)
672 return dict_contains(state->vars, name);
675 static code_t*defaultvalue(code_t*c, classinfo_t*type)
677 if(TYPE_IS_INT(type)) {
678 c = abc_pushbyte(c, 0);
679 } else if(TYPE_IS_UINT(type)) {
680 c = abc_pushuint(c, 0);
681 } else if(TYPE_IS_FLOAT(type)) {
683 } else if(TYPE_IS_BOOLEAN(type)) {
684 c = abc_pushfalse(c);
685 } else if(TYPE_IS_STRING(type)) {
689 //c = abc_pushundefined(c);
690 syntaxerror("internal error: can't generate default value for * type");
694 c = abc_coerce2(c, &m);
699 static int alloc_local()
701 return state->method->variable_count++;
704 static variable_t* new_variable2(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
707 variable_t*v = find_slot(method, name);
715 v->index = alloc_local();
717 v->init = v->kill = init;
720 if(!method->no_variable_scoping)
722 if(dict_contains(state->vars, name)) {
724 syntaxerror("variable %s already defined", name);
726 dict_put(state->vars, name, v);
728 if(method->no_variable_scoping &&
730 dict_contains(state->allvars, name))
732 variable_t*v = dict_lookup(state->allvars, name);
734 syntaxerror("variable %s already defined.", name);
737 dict_put(state->allvars, name, v);
742 static int new_variable(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
744 return new_variable2(method, name, type, init, maybeslot)->index;
747 #define TEMPVARNAME "__as3_temp__"
750 variable_t*v = find_variable(state, TEMPVARNAME);
755 i = new_variable(state->method, TEMPVARNAME, 0, 0, 0);
760 static code_t* var_block(code_t*body, dict_t*vars)
765 DICT_ITERATE_DATA(vars, variable_t*, v) {
766 if(v->type && v->init) {
767 c = defaultvalue(c, v->type);
768 c = abc_setlocal(c, v->index);
770 if(v->type && v->kill) {
771 k = abc_kill(k, v->index);
778 if(x->opcode== OPCODE___BREAK__ ||
779 x->opcode== OPCODE___CONTINUE__) {
780 /* link kill code before break/continue */
781 code_t*e = code_dup(k);
782 code_t*s = code_start(e);
794 c = code_append(c, body);
795 c = code_append(c, k);
799 static void unknown_variable(char*name)
801 if(!state->method->unresolved_variables)
802 state->method->unresolved_variables = dict_new();
803 if(!dict_contains(state->method->unresolved_variables, name))
804 dict_put(state->method->unresolved_variables, name, 0);
807 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
809 if(m->uses_slots || m->innerfunctions || (m->late_binding && !m->inner)) {
810 c = abc_getlocal_0(c);
811 c = abc_pushscope(c);
814 /* FIXME: this alloc_local() causes variable indexes to be
815 different in pass2 than in pass1 */
816 if(!m->activation_var) {
817 m->activation_var = alloc_local();
820 c = abc_newactivation(c);
822 c = abc_pushscope(c);
823 c = abc_setlocal(c, m->activation_var);
825 c = abc_getlocal(c, m->activation_var);
826 c = abc_pushscope(c);
832 static code_t* method_header(methodstate_t*m)
836 c = add_scope_code(c, m, 1);
838 methodstate_list_t*l = m->innerfunctions;
840 parserassert(l->methodstate->abc);
841 if(m->uses_slots && l->methodstate->is_a_slot) {
842 c = abc_getscopeobject(c, 1);
843 c = abc_newfunction(c, l->methodstate->abc);
845 c = abc_setlocal(c, l->methodstate->var_index);
846 c = abc_setslot(c, l->methodstate->slot_index);
848 c = abc_newfunction(c, l->methodstate->abc);
849 c = abc_setlocal(c, l->methodstate->var_index);
851 free(l->methodstate);l->methodstate=0;
855 c = code_append(c, m->header);
858 if(m->is_constructor && !m->has_super) {
859 // call default constructor
860 c = abc_getlocal_0(c);
861 c = abc_constructsuper(c, 0);
865 /* all parameters that are used by inner functions
866 need to be copied from local to slot */
867 parserassert(m->activation_var);
868 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
869 if(v->is_parameter) {
870 c = abc_getlocal(c, m->activation_var);
871 c = abc_getlocal(c, v->index);
872 c = abc_setslot(c, v->index);
876 list_free(m->innerfunctions);
877 m->innerfunctions = 0;
882 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
884 c = code_append(c, header);
885 c = code_append(c, var_block(body, state->method->no_variable_scoping?state->allvars:state->vars));
886 /* append return if necessary */
887 if(!c || (c->opcode != OPCODE_RETURNVOID &&
888 c->opcode != OPCODE_RETURNVALUE)) {
889 c = abc_returnvoid(c);
894 static void startpackage(char*name)
897 state->package = strdup(name);
899 static void endpackage()
901 //used e.g. in classinfo_register:
902 //free(state->package);state->package=0;
906 #define FLAG_PUBLIC 256
907 #define FLAG_PROTECTED 512
908 #define FLAG_PRIVATE 1024
909 #define FLAG_PACKAGEINTERNAL 2048
910 #define FLAG_NAMESPACE 4096
912 static namespace_t modifiers2access(modifiers_t*mod)
917 if(mod->flags&FLAG_NAMESPACE) {
918 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
919 syntaxerror("invalid combination of access levels and namespaces");
920 ns.access = ACCESS_NAMESPACE;
922 const char*url = (const char*)trie_lookup(active_namespaces, (unsigned char*)mod->ns);
924 /* shouldn't happen- the tokenizer only reports something as a namespace
925 if it was already registered */
926 trie_dump(active_namespaces);
927 syntaxerror("unknown namespace: %s", mod->ns);
930 } else if(mod->flags&FLAG_PUBLIC) {
931 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
932 syntaxerror("invalid combination of access levels");
933 ns.access = ACCESS_PACKAGE;
934 } else if(mod->flags&FLAG_PRIVATE) {
935 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
936 syntaxerror("invalid combination of access levels");
937 ns.access = ACCESS_PRIVATE;
938 } else if(mod->flags&FLAG_PROTECTED) {
939 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
940 syntaxerror("invalid combination of access levels");
941 ns.access = ACCESS_PROTECTED;
943 ns.access = ACCESS_PACKAGEINTERNAL;
947 static slotinfo_t* find_class(const char*name);
949 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
951 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
954 static void innerfunctions2vars(methodstate_t*m)
956 methodstate_list_t*l = m->innerfunctions;
958 methodstate_t*m = l->methodstate;
960 variable_t* v = new_variable2(state->method, m->info->name, TYPE_FUNCTION(m->info), 0, 0);
961 m->var_index = v->index;
963 m->slot_index = m->is_a_slot;
964 v->is_inner_method = m;
969 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
974 index = new_variable(m, "this", 0, 0, 0);
975 else if(!m->is_global)
976 index = new_variable(m, (flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
978 index = new_variable(m, "globalscope", 0, 0, 0);
980 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
981 printf("%s %d\n", name, v->index);
984 parserassert(!index);
989 for(p=params->list;p;p=p->next) {
990 variable_t*v = new_variable2(m, p->param->name, p->param->type, 0, 1);
993 if(as3_pass==2 && m->need_arguments) {
994 /* arguments can never be used by an innerfunction (the inner functions
995 have their own arguments var), so it's ok to not initialize this until
996 pass 2. (We don't know whether we need it before, anyway) */
997 variable_t*v = new_variable2(m, "arguments", TYPE_ARRAY, 0, 0);
998 m->need_arguments = v->index;
1002 innerfunctions2vars(m);
1005 m->scope_code = add_scope_code(m->scope_code, m, 0);
1007 /* exchange unresolved identifiers with the actual objects */
1008 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
1009 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
1010 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
1011 if(!type || type->kind != INFOTYPE_CLASS) {
1012 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
1022 char*as3_globalclass=0;
1023 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
1026 syntaxerror("inner classes now allowed");
1031 classinfo_list_t*mlist=0;
1033 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
1034 syntaxerror("invalid modifier(s)");
1036 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
1037 syntaxerror("public and internal not supported at the same time.");
1039 if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
1040 syntaxerror("protected and static not supported at the same time.");
1042 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1043 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1044 // all classes extend object
1045 extends = registry_getobjectclass();
1048 /* create the class name, together with the proper attributes */
1052 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
1053 access = ACCESS_PRIVATE; package = internal_filename_package;
1054 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
1055 access = ACCESS_PACKAGEINTERNAL; package = state->package;
1056 } else if(state->package!=internal_filename_package) {
1057 access = ACCESS_PACKAGE; package = state->package;
1059 syntaxerror("public classes only allowed inside a package");
1063 state->cls = rfx_calloc(sizeof(classstate_t));
1064 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1065 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1066 state->cls->static_init->is_static=FLAG_STATIC;
1067 /* notice: we make no effort to initialize the top variable (local0) here,
1068 even though it has special meaning. We just rely on the fact
1069 that pass 1 won't do anything with variables */
1071 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1073 /* set current method to constructor- all code within the class-level (except
1074 static variable initializations) will be executed during construction time */
1075 state->method = state->cls->init;
1077 if(registry_find(package, classname)) {
1078 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1080 /* build info struct */
1081 int num_interfaces = (list_length(implements));
1082 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1083 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1084 state->cls->info->superclass = extends;
1087 classinfo_list_t*l = implements;
1088 for(l=implements;l;l=l->next) {
1089 state->cls->info->interfaces[pos++] = l->classinfo;
1094 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1096 parserassert(state->cls && state->cls->info);
1098 state->method = state->cls->static_init;
1100 function_initvars(state->cls->init, 0, 0, 0, 1);
1101 state->cls->static_init->variable_count=1;
1102 function_initvars(state->cls->static_init, 0, 0, 0, 0);
1104 if(extends && (extends->flags & FLAG_FINAL))
1105 syntaxerror("Can't extend final class '%s'", extends->name);
1108 while(state->cls->info->interfaces[pos]) {
1109 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1110 syntaxerror("'%s' is not an interface",
1111 state->cls->info->interfaces[pos]->name);
1115 /* generate the abc code for this class */
1116 MULTINAME(classname2,state->cls->info);
1117 multiname_t*extends2 = sig2mname(extends);
1119 /* don't add the class to the class index just yet- that will be done later
1121 state->cls->abc = abc_class_new(0, &classname2, extends2);
1122 state->cls->abc->file = global->file;
1124 multiname_destroy(extends2);
1125 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1126 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1127 if(state->cls->info->flags&FLAG_INTERFACE) {
1128 abc_class_interface(state->cls->abc);
1131 for(mlist=implements;mlist;mlist=mlist->next) {
1132 MULTINAME(m, mlist->classinfo);
1133 abc_class_add_interface(state->cls->abc, &m);
1136 state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
1137 list_append(global->classes, state->cls->dependencies);
1139 /* flash.display.MovieClip handling */
1140 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1141 if(state->package && state->package[0]) {
1142 as3_globalclass = concat3(state->package, ".", classname);
1144 as3_globalclass = strdup(classname);
1150 static void endclass()
1153 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1155 c = abc_getlocal_0(c);
1156 c = abc_constructsuper(c, 0);
1157 state->cls->init->header = code_append(state->cls->init->header, c);
1158 state->cls->has_constructor=1;
1160 if(state->cls->init) {
1161 if(state->cls->info->flags&FLAG_INTERFACE) {
1162 if(state->cls->init->header)
1163 syntaxerror("interface can not have class-level code");
1165 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1166 code_t*c = method_header(state->cls->init);
1167 m->body->code = wrap_function(c, 0, m->body->code);
1170 if(state->cls->static_init) {
1171 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1172 code_t*c = method_header(state->cls->static_init);
1173 m->body->code = wrap_function(c, 0, m->body->code);
1176 trait_list_t*trait = state->cls->abc->traits;
1177 /* switch all protected members to the protected ns of this class */
1179 trait_t*t = trait->trait;
1180 if(t->name->ns->access == ACCESS_PROTECTED) {
1181 if(!state->cls->abc->protectedNS) {
1182 char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
1183 state->cls->abc->protectedNS = namespace_new_protected(n);
1184 state->cls->abc->flags |= CLASS_PROTECTED_NS;
1186 t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
1188 trait = trait->next;
1195 void check_code_for_break(code_t*c)
1198 if(c->opcode == OPCODE___BREAK__) {
1199 char*name = string_cstr(c->data[0]);
1200 syntaxerror("Unresolved \"break %s\"", name);
1202 if(c->opcode == OPCODE___CONTINUE__) {
1203 char*name = string_cstr(c->data[0]);
1204 syntaxerror("Unresolved \"continue %s\"", name);
1206 if(c->opcode == OPCODE___RETHROW__) {
1207 syntaxerror("Unresolved \"rethrow\"");
1209 if(c->opcode == OPCODE___FALLTHROUGH__) {
1210 syntaxerror("Unresolved \"fallthrough\"");
1212 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1213 char*name = string_cstr(c->data[0]);
1214 syntaxerror("Can't reference a package (%s) as such", name);
1220 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1222 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1223 if(TYPE_IS_NUMBER(t)) {
1224 xassert(c->type == CONSTANT_FLOAT
1225 || c->type == CONSTANT_INT
1226 || c->type == CONSTANT_UINT);
1227 } else if(TYPE_IS_UINT(t)) {
1228 xassert(c->type == CONSTANT_UINT ||
1229 (c->type == CONSTANT_INT && c->i>=0));
1230 } else if(TYPE_IS_INT(t)) {
1231 xassert(c->type == CONSTANT_INT);
1232 } else if(TYPE_IS_BOOLEAN(t)) {
1233 xassert(c->type == CONSTANT_TRUE
1234 || c->type == CONSTANT_FALSE);
1238 static void check_override(memberinfo_t*m, int flags)
1242 if(m->parent == state->cls->info)
1243 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1245 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1246 if(m->access==ACCESS_PRIVATE)
1248 if(m->flags & FLAG_FINAL)
1249 syntaxerror("can't override final member %s", m->name);
1251 /* allow this. it's no issue.
1252 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1253 syntaxerror("can't override static member %s", m->name);*/
1255 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1256 syntaxerror("can't override non-static member %s with static declaration", m->name);
1258 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1259 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1260 if(m->kind == INFOTYPE_METHOD)
1261 syntaxerror("can't override without explicit 'override' declaration");
1263 syntaxerror("can't override '%s'", m->name);
1268 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1270 methodinfo_t*minfo = 0;
1271 namespace_t ns = modifiers2access(mod);
1274 minfo = methodinfo_register_global(ns.access, state->package, name);
1275 minfo->return_type = return_type;
1276 } else if(getset != KW_GET && getset != KW_SET) {
1278 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1280 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1282 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1283 minfo->return_type = return_type;
1284 // getslot on a member slot only returns "undefined", so no need
1285 // to actually store these
1286 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1288 //class getter/setter
1289 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1291 if(getset == KW_GET) {
1293 } else if(params->list && params->list->param && !params->list->next) {
1294 type = params->list->param->type;
1296 syntaxerror("setter function needs to take exactly one argument");
1297 // not sure wether to look into superclasses here, too
1298 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1300 if(minfo->kind!=INFOTYPE_VAR)
1301 syntaxerror("class already contains a method called '%s'", name);
1302 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1303 syntaxerror("class already contains a field called '%s'", name);
1304 if(minfo->subtype & gs)
1305 syntaxerror("getter/setter for '%s' already defined", name);
1306 /* make a setter or getter into a getset */
1307 minfo->subtype |= gs;
1310 FIXME: this check needs to be done in pass 2
1312 if((!minfo->return_type != !type) ||
1313 (minfo->return_type && type &&
1314 !strcmp(minfo->return_type->name, type->name))) {
1315 syntaxerror("different type in getter and setter: %s and %s",
1316 minfo->return_type?minfo->return_type->name:"*",
1317 type?type->name:"*");
1320 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1321 minfo->kind = INFOTYPE_VAR; //hack
1322 minfo->subtype = gs;
1323 minfo->return_type = type;
1326 /* can't assign a slot as getter and setter might have different slots */
1327 //minfo->slot = slot;
1329 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1330 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1331 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1336 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1338 //parserassert(state->method && state->method->info);
1340 methodstate_t*parent_method = state->method;
1344 return_type = 0; // not valid in pass 1
1346 v = new_variable2(parent_method, name, 0, 0, 0);
1351 state->new_vars = 1;
1352 state->allvars = dict_new();
1355 state->method = rfx_calloc(sizeof(methodstate_t));
1356 state->method->inner = 1;
1357 state->method->is_static = parent_method->is_static;
1358 state->method->variable_count = 0;
1359 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1361 v->is_inner_method = state->method;
1364 NEW(methodinfo_t,minfo);
1365 minfo->kind = INFOTYPE_METHOD;
1366 minfo->access = ACCESS_PACKAGEINTERNAL;
1368 state->method->info = minfo;
1371 list_append(parent_method->innerfunctions, state->method);
1373 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1375 function_initvars(state->method, 1, params, 0, 1);
1379 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1380 state->method->variable_count = 0;
1381 parserassert(state->method);
1383 state->method->info->return_type = return_type;
1384 function_initvars(state->method, 1, params, 0, 1);
1388 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1389 params_t*params, classinfo_t*return_type)
1391 if(state->method && state->method->info) {
1392 syntaxerror("not able to start another method scope");
1395 state->new_vars = 1;
1396 state->allvars = dict_new();
1399 state->method = rfx_calloc(sizeof(methodstate_t));
1400 state->method->has_super = 0;
1401 state->method->is_static = mod->flags&FLAG_STATIC;
1404 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1406 state->method->is_global = 1;
1407 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1409 if(state->method->is_constructor)
1410 name = "__as3_constructor__";
1412 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1414 function_initvars(state->method, 1, params, mod->flags, 1);
1416 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1420 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1421 state->method->variable_count = 0;
1422 parserassert(state->method);
1425 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1426 check_override(m, mod->flags);
1430 state->cls->has_constructor |= state->method->is_constructor;
1433 function_initvars(state->method, 1, params, mod->flags, 1);
1437 static void insert_unresolved(methodstate_t*m, dict_t*xvars, dict_t*allvars)
1439 parserassert(m->inner);
1440 if(m->unresolved_variables) {
1441 dict_t*d = m->unresolved_variables;
1443 DICT_ITERATE_KEY(d, char*, id) {
1444 /* check parent method's variables */
1446 if(dict_contains(allvars, id)) {
1447 m->uses_parent_function = 1;
1448 state->method->uses_slots = 1;
1449 dict_put(xvars, id, 0);
1453 methodstate_list_t*ml = m->innerfunctions;
1455 insert_unresolved(ml->methodstate, xvars, allvars);
1460 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1461 params_t*params, classinfo_t*return_type, code_t*body)
1464 dict_t*xvars = dict_new();
1466 if(state->method->unresolved_variables) {
1467 DICT_ITERATE_KEY(state->method->unresolved_variables, char*, vname) {
1468 if(!state->method->no_variable_scoping && dict_contains(state->allvars, vname)) {
1469 variable_t*v = dict_lookup(state->allvars, vname);
1470 if(!v->is_inner_method) {
1471 state->method->no_variable_scoping = 1;
1472 as3_warning("function %s uses forward or outer block variable references (%s): switching into compatiblity mode", name, vname);
1478 methodstate_list_t*ml = state->method->innerfunctions;
1480 insert_unresolved(ml->methodstate, xvars, state->allvars);
1484 if(state->method->uses_slots) {
1485 state->method->slots = dict_new();
1487 DICT_ITERATE_ITEMS(state->allvars, char*, name, variable_t*, v) {
1488 if(!name) syntaxerror("internal error");
1489 if(v->index && dict_contains(xvars, name)) {
1490 v->init = v->kill = 0;
1492 if(v->is_inner_method) {
1493 v->is_inner_method->is_a_slot = i;
1496 dict_put(state->method->slots, name, v);
1499 state->method->uses_slots = i;
1500 dict_destroy(state->vars);state->vars = 0;
1501 parserassert(state->new_vars);
1502 dict_destroy(state->allvars);state->allvars = 0;
1509 /*if(state->method->uses_parent_function){
1510 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1515 multiname_t*type2 = sig2mname(return_type);
1517 if(state->method->inner) {
1518 f = state->method->abc;
1519 abc_method_init(f, global->file, type2, 1);
1520 } else if(state->method->is_constructor) {
1521 f = abc_class_getconstructor(state->cls->abc, type2);
1522 } else if(!state->method->is_global) {
1523 namespace_t ns = modifiers2access(mod);
1524 multiname_t mname = {QNAME, &ns, 0, name};
1525 if(mod->flags&FLAG_STATIC)
1526 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1528 f = abc_class_method(state->cls->abc, type2, &mname);
1529 slot = f->trait->slot_id;
1531 namespace_t mname_ns = {state->method->info->access, state->package};
1532 multiname_t mname = {QNAME, &mname_ns, 0, name};
1534 f = abc_method_new(global->file, type2, 1);
1535 if(!global->init) global->init = abc_initscript(global->file);
1536 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1537 //abc_code_t*c = global->init->method->body->code;
1539 //flash doesn't seem to allow us to access function slots
1540 //state->method->info->slot = slot;
1542 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1543 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1544 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1545 if(params->varargs) f->flags |= METHOD_NEED_REST;
1546 if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
1550 for(p=params->list;p;p=p->next) {
1551 if(params->varargs && !p->next) {
1552 break; //varargs: omit last parameter in function signature
1554 multiname_t*m = sig2mname(p->param->type);
1555 list_append(f->parameters, m);
1556 if(p->param->value) {
1557 check_constant_against_type(p->param->type, p->param->value);
1558 opt=1;list_append(f->optional_parameters, p->param->value);
1560 syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
1563 if(state->method->slots) {
1564 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1566 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1567 multiname_t*type = sig2mname(v->type);
1568 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1569 t->slot_id = v->index;
1574 check_code_for_break(body);
1576 /* Seems this works now.
1577 if(state->method->exceptions && state->method->uses_slots) {
1578 as3_warning("try/catch and activation not supported yet within the same method");
1582 f->body->code = body;
1583 f->body->exceptions = state->method->exceptions;
1584 } else { //interface
1586 syntaxerror("interface methods can't have a method body");
1596 void breakjumpsto(code_t*c, char*name, code_t*jump)
1599 if(c->opcode == OPCODE___BREAK__) {
1600 string_t*name2 = c->data[0];
1601 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1602 c->opcode = OPCODE_JUMP;
1609 void continuejumpsto(code_t*c, char*name, code_t*jump)
1612 if(c->opcode == OPCODE___CONTINUE__) {
1613 string_t*name2 = c->data[0];
1614 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1615 c->opcode = OPCODE_JUMP;
1623 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1628 return abc_coerce_a(c);
1632 // cast an "any" type to a specific type. subject to
1633 // runtime exceptions
1634 return abc_coerce2(c, &m);
1637 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1638 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1639 // allow conversion between number types
1640 if(TYPE_IS_UINT(to))
1641 return abc_convert_u(c);
1642 else if(TYPE_IS_INT(to))
1643 return abc_convert_i(c);
1644 else if(TYPE_IS_NUMBER(to))
1645 return abc_convert_d(c);
1646 return abc_coerce2(c, &m);
1649 if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
1652 if(TYPE_IS_BOOLEAN(to))
1653 return abc_convert_b(c);
1654 if(TYPE_IS_STRING(to))
1655 return abc_convert_s(c);
1656 if(TYPE_IS_OBJECT(to))
1657 return abc_coerce2(c, &m);
1658 if(TYPE_IS_OBJECT(from) && TYPE_IS_XMLLIST(to))
1659 return abc_coerce2(c, &m);
1660 if(TYPE_IS_OBJECT(from) && TYPE_IS_ARRAY(to))
1661 return abc_coerce2(c, &m);
1663 classinfo_t*supertype = from;
1665 if(supertype == to) {
1666 /* target type is one of from's superclasses.
1667 (not sure we need this coerce - as far as the verifier
1668 is concerned, object==object (i think) */
1669 return abc_coerce2(c, &m);
1672 while(supertype->interfaces[t]) {
1673 if(supertype->interfaces[t]==to) {
1674 // target type is one of from's interfaces
1675 return abc_coerce2(c, &m);
1679 supertype = supertype->superclass;
1681 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1683 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1685 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1688 as3_error("can't convert type %s%s%s to %s%s%s",
1689 from->package, from->package[0]?".":"", from->name,
1690 to->package, to->package[0]?".":"", to->name);
1694 code_t* coerce_to_type(code_t*c, classinfo_t*t)
1697 return abc_coerce_a(c);
1698 } else if(TYPE_IS_STRING(t)) {
1699 return abc_coerce_s(c);
1702 return abc_coerce2(c, &m);
1706 char is_pushundefined(code_t*c)
1708 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1711 static const char* get_package_from_name(const char*name)
1713 /* try explicit imports */
1714 dictentry_t* e = dict_get_slot(state->imports, name);
1716 if(!strcmp(e->key, name)) {
1717 slotinfo_t*c = (slotinfo_t*)e->data;
1718 if(c) return c->package;
1724 static namespace_list_t*get_current_imports()
1726 namespace_list_t*searchlist = 0;
1728 list_append(searchlist, namespace_new_package(state->package));
1730 import_list_t*l = state->wildcard_imports;
1732 namespace_t*ns = namespace_new_package(l->import->package);
1733 list_append(searchlist, ns);
1736 list_append(searchlist, namespace_new_package(""));
1737 list_append(searchlist, namespace_new_package(internal_filename_package));
1741 static slotinfo_t* find_class(const char*name)
1745 c = registry_find(state->package, name);
1748 /* try explicit imports */
1749 dictentry_t* e = dict_get_slot(state->imports, name);
1752 if(!strcmp(e->key, name)) {
1753 c = (slotinfo_t*)e->data;
1759 /* try package.* imports */
1760 import_list_t*l = state->wildcard_imports;
1762 //printf("does package %s contain a class %s?\n", l->import->package, name);
1763 c = registry_find(l->import->package, name);
1768 /* try global package */
1769 c = registry_find("", name);
1772 /* try local "filename" package */
1773 c = registry_find(internal_filename_package, name);
1778 typedcode_t push_class(slotinfo_t*a)
1783 if(a->access == ACCESS_PACKAGEINTERNAL &&
1784 strcmp(a->package, state->package) &&
1785 strcmp(a->package, internal_filename_package)
1787 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1788 infotypename(a), a->name, a->package, state->package);
1792 if(a->kind != INFOTYPE_CLASS) {
1794 x.c = abc_findpropstrict2(x.c, &m);
1795 x.c = abc_getproperty2(x.c, &m);
1796 if(a->kind == INFOTYPE_METHOD) {
1797 methodinfo_t*f = (methodinfo_t*)a;
1798 x.t = TYPE_FUNCTION(f);
1800 varinfo_t*v = (varinfo_t*)a;
1805 if(state->cls && state->method == state->cls->static_init) {
1806 /* we're in the static initializer.
1807 record the fact that we're using this class here */
1808 parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
1810 classinfo_t*c = (classinfo_t*)a;
1812 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1813 x.c = abc_getglobalscope(x.c);
1814 x.c = abc_getslot(x.c, c->slot);
1817 x.c = abc_getlex2(x.c, &m);
1819 x.t = TYPE_CLASS(c);
1825 char is_break_or_jump(code_t*c)
1829 if(c->opcode == OPCODE_JUMP ||
1830 c->opcode == OPCODE___BREAK__ ||
1831 c->opcode == OPCODE___CONTINUE__ ||
1832 c->opcode == OPCODE_THROW ||
1833 c->opcode == OPCODE_RETURNVOID ||
1834 c->opcode == OPCODE_RETURNVALUE) {
1840 #define IS_FINALLY_TARGET(op) \
1841 ((op) == OPCODE___CONTINUE__ || \
1842 (op) == OPCODE___BREAK__ || \
1843 (op) == OPCODE_RETURNVOID || \
1844 (op) == OPCODE_RETURNVALUE || \
1845 (op) == OPCODE___RETHROW__)
1847 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1849 #define NEED_EXTRA_STACK_ARG
1850 code_t*finally_label = abc_nop(0);
1851 NEW(lookupswitch_t, l);
1857 code_t*prev = i->prev;
1858 if(IS_FINALLY_TARGET(i->opcode)) {
1861 if(i->opcode == OPCODE___RETHROW__ ||
1862 i->opcode == OPCODE_RETURNVALUE) {
1863 if(i->opcode == OPCODE___RETHROW__)
1864 i->opcode = OPCODE_THROW;
1866 p = abc_coerce_a(p);
1867 p = abc_setlocal(p, tempvar);
1869 p = abc_pushbyte(p, count++);
1870 p = abc_jump(p, finally_label);
1871 code_t*target = p = abc_label(p);
1872 #ifdef NEED_EXTRA_STACK_ARG
1876 p = abc_getlocal(p, tempvar);
1879 p->next = i;i->prev = p;
1880 list_append(l->targets, target);
1886 c = abc_pushbyte(c, -1);
1887 c = code_append(c, finally_label);
1888 c = code_append(c, finally);
1890 #ifdef NEED_EXTRA_STACK_ARG
1893 c = abc_lookupswitch(c, l);
1894 c = l->def = abc_label(c);
1895 #ifdef NEED_EXTRA_STACK_ARG
1902 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1906 code_t*prev = i->prev;
1907 if(IS_FINALLY_TARGET(i->opcode)) {
1908 if(i->opcode == OPCODE___RETHROW__)
1909 i->opcode = OPCODE_THROW;
1910 code_t*end = code_dup(finally);
1911 code_t*start = code_start(end);
1912 if(prev) prev->next = start;
1919 return code_append(c, finally);
1922 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1928 int num_insertion_points=0;
1930 if(IS_FINALLY_TARGET(i->opcode))
1931 num_insertion_points++;
1938 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1943 int simple_version_cost = (1+num_insertion_points)*code_size;
1944 int lookup_version_cost = 4*num_insertion_points + 5;
1946 if(cantdup || simple_version_cost > lookup_version_cost) {
1947 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1948 return insert_finally_lookup(c, finally, tempvar);
1950 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1951 return insert_finally_simple(c, finally, tempvar);
1955 #define PASS1 }} if(as3_pass == 1) {{
1956 #define PASS1END }} if(as3_pass == 2) {{
1957 #define PASS2 }} if(as3_pass == 2) {{
1958 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1959 #define PASS12END }} if(as3_pass == 2) {{
1960 #define PASS_ALWAYS }} {{
1966 /* ------------ code blocks / statements ---------------- */
1968 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1970 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1971 PROGRAM_CODE_LIST: PROGRAM_CODE
1972 | PROGRAM_CODE_LIST PROGRAM_CODE
1974 PROGRAM_CODE: PACKAGE_DECLARATION
1975 | INTERFACE_DECLARATION
1977 | FUNCTION_DECLARATION
1980 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1983 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1984 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1985 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1987 INPACKAGE_CODE: INTERFACE_DECLARATION
1989 | FUNCTION_DECLARATION
1992 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1993 | '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
1996 MAYBECODE: CODE {$$=$1;}
1997 MAYBECODE: {$$=code_new();}
1999 CODE: CODE CODEPIECE {
2000 $$=code_append($1,$2);
2002 CODE: CODEPIECE {$$=$1;}
2004 // code which may appear outside of methods
2005 CODE_STATEMENT: DEFAULT_NAMESPACE
2006 CODE_STATEMENT: IMPORT
2008 CODE_STATEMENT: FOR_IN
2009 CODE_STATEMENT: WHILE
2010 CODE_STATEMENT: DO_WHILE
2011 CODE_STATEMENT: SWITCH
2013 CODE_STATEMENT: WITH
2015 CODE_STATEMENT: VOIDEXPRESSION
2016 CODE_STATEMENT: USE_NAMESPACE
2017 CODE_STATEMENT: NAMESPACE_DECLARATION
2018 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
2019 CODE_STATEMENT: '{' '}' {$$=0;}
2021 // code which may appear in methods (includes the above)
2022 CODEPIECE: ';' {$$=0;}
2023 CODEPIECE: CODE_STATEMENT
2024 CODEPIECE: VARIABLE_DECLARATION
2029 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
2039 //CODEBLOCK : '{' CODE '}' {$$=$2;}
2040 //CODEBLOCK : '{' '}' {$$=0;}
2041 CODEBLOCK : CODEPIECE ';' {$$=$1;}
2042 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
2044 /* ------------ package init code ------------------- */
2046 PACKAGE_INITCODE: CODE_STATEMENT {
2049 global->init = abc_initscript(global->file);
2050 code_t**cc = &global->init->method->body->code;
2051 *cc = code_append(*cc, $1);
2055 /* ------------ embed code ------------- */
2057 EMBED_START: %prec above_function {
2063 /* ------------ conditional compilation ------------- */
2065 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
2068 char*key = concat3($1,"::",$3);
2069 if(!definitions || !dict_contains(definitions, key)) {
2075 /* ------------ variables --------------------------- */
2078 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
2082 char do_init_variable(char*name)
2084 if(!state->method->no_variable_scoping)
2086 if(!state->new_vars)
2092 MAYBEEXPRESSION : '=' E {$$=$2;}
2093 | {$$=mkdummynode();}
2095 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2096 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2098 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2099 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2101 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2104 if(variable_exists($1))
2105 syntaxerror("Variable %s already defined", $1);
2107 new_variable(state->method, $1, 0, 1, 0);
2113 if(state->method->uses_slots) {
2114 v = find_slot(state->method, $1);
2116 // this variable is stored in a slot
2123 v = new_variable2(state->method, $1, $2, 1, 0);
2126 $$ = slot?abc_getscopeobject(0, 1):0;
2128 typedcode_t val = node_read($3);
2129 if(!is_subtype_of(val.t, $2)) {
2130 syntaxerror("Can't convert %s to %s", val.t->name, $2->name);
2133 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2134 $$ = code_append($$, val.c);
2135 $$ = converttype($$, val.t, $2);
2138 $$ = defaultvalue($$, $2);
2141 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2142 $$ = code_append($$, val.c);
2143 $$ = abc_coerce_a($$);
2145 // don't do anything
2153 $$ = abc_setslot($$, v->index);
2155 $$ = abc_setlocal($$, v->index);
2156 v->init = do_init_variable($1);
2160 /* ------------ control flow ------------------------- */
2162 IF_CODEBLOCK: {PASS12 new_state();} CODEBLOCK {
2163 $$ = var_block($2, state->vars);
2166 MAYBEELSE: %prec below_else {$$ = code_new();}
2167 MAYBEELSE: "else" IF_CODEBLOCK {$$=$2;}
2168 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2170 IF : "if" '(' EXPRESSION ')' IF_CODEBLOCK MAYBEELSE {
2172 $$ = code_append($$, $3.c);
2173 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2175 $$ = code_append($$, $5);
2177 myjmp = $$ = abc_jump($$, 0);
2179 myif->branch = $$ = abc_nop($$);
2181 $$ = code_append($$, $6);
2182 myjmp->branch = $$ = abc_nop($$);
2186 FOR_INIT : {$$=code_new();}
2187 FOR_INIT : VARIABLE_DECLARATION
2188 FOR_INIT : VOIDEXPRESSION
2190 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2191 // (I don't see any easy way to revolve this conflict otherwise, as we
2192 // can't touch VAR_READ without upsetting the precedence about "return")
2193 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2194 PASS1 $$=$2;new_variable(state->method, $2,0,1,0);
2195 PASS2 $$=$2;new_variable(state->method, $2,$3,1,0);
2197 FOR_IN_INIT : T_IDENTIFIER {
2202 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2203 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2205 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' IF_CODEBLOCK {
2206 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2208 $$ = code_append($$, $2);
2209 code_t*loopstart = $$ = abc_label($$);
2210 $$ = code_append($$, $4.c);
2211 code_t*myif = $$ = abc_iffalse($$, 0);
2212 $$ = code_append($$, $8);
2213 code_t*cont = $$ = abc_nop($$);
2214 $$ = code_append($$, $6);
2215 $$ = abc_jump($$, loopstart);
2216 code_t*out = $$ = abc_nop($$);
2217 breakjumpsto($$, $1.name, out);
2218 continuejumpsto($$, $1.name, cont);
2221 $$ = var_block($$, state->vars);
2225 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' IF_CODEBLOCK {
2226 node_t*n = resolve_identifier($2);
2227 typedcode_t w = node_write(n);
2229 int it = alloc_local();
2230 int array = alloc_local();
2233 $$ = code_append($$, $4.c);
2234 $$ = abc_coerce_a($$);
2235 $$ = abc_setlocal($$, array);
2236 $$ = abc_pushbyte($$, 0);
2237 $$ = abc_setlocal($$, it);
2239 code_t*loopstart = $$ = abc_label($$);
2241 $$ = abc_hasnext2($$, array, it);
2242 code_t*myif = $$ = abc_iffalse($$, 0);
2243 $$ = abc_getlocal($$, array);
2244 $$ = abc_getlocal($$, it);
2246 $$ = abc_nextname($$);
2248 $$ = abc_nextvalue($$);
2250 $$ = converttype($$, 0, w.t);
2251 $$ = code_append($$, w.c);
2253 $$ = code_append($$, $6);
2254 $$ = abc_jump($$, loopstart);
2256 code_t*out = $$ = abc_nop($$);
2257 breakjumpsto($$, $1.name, out);
2258 continuejumpsto($$, $1.name, loopstart);
2262 $$ = abc_kill($$, it);
2263 $$ = abc_kill($$, array);
2265 $$ = var_block($$, state->vars);
2269 WHILE : T_WHILE '(' EXPRESSION ')' IF_CODEBLOCK {
2273 code_t*myjmp = $$ = abc_jump($$, 0);
2274 code_t*loopstart = $$ = abc_label($$);
2275 $$ = code_append($$, $5);
2276 code_t*cont = $$ = abc_nop($$);
2277 myjmp->branch = cont;
2278 $$ = code_append($$, $3.c);
2279 $$ = abc_iftrue($$, loopstart);
2280 code_t*out = $$ = abc_nop($$);
2281 breakjumpsto($$, $1, out);
2282 continuejumpsto($$, $1, cont);
2285 DO_WHILE : T_DO IF_CODEBLOCK "while" '(' EXPRESSION ')' {
2287 code_t*loopstart = $$ = abc_label($$);
2288 $$ = code_append($$, $2);
2289 code_t*cont = $$ = abc_nop($$);
2290 $$ = code_append($$, $5.c);
2291 $$ = abc_iftrue($$, loopstart);
2292 code_t*out = $$ = abc_nop($$);
2293 breakjumpsto($$, $1, out);
2294 continuejumpsto($$, $1, cont);
2297 BREAK : "break" %prec prec_none {
2298 $$ = abc___break__(0, "");
2300 BREAK : "break" T_IDENTIFIER {
2301 $$ = abc___break__(0, $2);
2303 CONTINUE : "continue" %prec prec_none {
2304 $$ = abc___continue__(0, "");
2306 CONTINUE : "continue" T_IDENTIFIER {
2307 $$ = abc___continue__(0, $2);
2310 MAYBE_CASE_LIST : {$$=0;}
2311 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2312 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2313 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2314 CASE_LIST: CASE {$$=$1;}
2315 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2317 CASE: "case" E ':' MAYBECODE {
2318 $$ = abc_getlocal(0, state->switch_var);
2319 $$ = code_append($$, node_read($2).c);
2320 code_t*j = $$ = abc_ifne($$, 0);
2321 $$ = code_append($$, $4);
2322 if($$->opcode != OPCODE___BREAK__) {
2323 $$ = abc___fallthrough__($$, "");
2325 code_t*e = $$ = abc_nop($$);
2328 DEFAULT: "default" ':' MAYBECODE {
2331 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2332 $$ = node_read($4).c;
2333 $$ = abc_setlocal($$, state->switch_var);
2334 $$ = code_append($$, $7);
2336 code_t*out = $$ = abc_kill($$, state->switch_var);
2337 breakjumpsto($$, $1, out);
2339 code_t*c = $$,*lastblock=0;
2341 if(c->opcode == OPCODE_IFNE) {
2342 if(!c->next) syntaxerror("internal error in fallthrough handling");
2344 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2346 c->opcode = OPCODE_JUMP;
2347 c->branch = lastblock;
2349 /* fall through end of switch */
2350 c->opcode = OPCODE_NOP;
2356 $$ = var_block($$, state->vars);
2360 /* ------------ try / catch /finally ---------------- */
2362 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2363 state->exception_name=$3;
2364 PASS1 new_variable(state->method, $3, 0, 0, 0);
2365 PASS2 new_variable(state->method, $3, $4, 0, 0);
2368 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2369 multiname_t name = {QNAME, &name_ns, 0, $3};
2371 NEW(abc_exception_t, e)
2372 e->exc_type = sig2mname($4);
2373 e->var_name = multiname_clone(&name);
2377 int i = find_variable_safe(state, $3)->index;
2378 e->target = c = abc_nop(0);
2379 c = abc_setlocal(c, i);
2380 c = code_append(c, code_dup(state->method->scope_code));
2381 c = code_append(c, $8);
2384 c = var_block(c, state->vars);
2387 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2388 $4 = var_block($4, state->vars);
2392 NEW(abc_exception_t, e)
2393 e->exc_type = 0; //all exceptions
2394 e->var_name = 0; //no name
2397 e->to = code_append(e->to, $4);
2403 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2404 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2405 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2406 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2410 list_append($$.l,$2);
2411 $$.finally = $2->to;$2->to=0;
2414 CATCH_FINALLY_LIST: FINALLY {
2418 list_append($$.l,$1);
2419 $$.finally = $1->to;$1->to=0;
2423 TRY : "try" '{' {PASS12 new_state();
2424 state->method->has_exceptions=1;
2425 state->method->late_binding=1;//for invariant scope_code
2426 } MAYBECODE '}' CATCH_FINALLY_LIST {
2427 code_t*out = abc_nop(0);
2429 code_t*start = abc_nop(0);
2430 $$ = code_append(start, $4);
2431 if(!is_break_or_jump($4)) {
2432 $$ = abc_jump($$, out);
2434 code_t*end = $$ = abc_nop($$);
2438 tmp = alloc_local();
2440 abc_exception_list_t*l = $6.l;
2443 abc_exception_t*e = l->abc_exception;
2445 $$ = code_append($$, e->target);
2446 $$ = abc_jump($$, out);
2448 parserassert((ptroff_t)$6.finally);
2450 e->target = $$ = abc_nop($$);
2451 $$ = code_append($$, code_dup(state->method->scope_code));
2452 $$ = abc___rethrow__($$);
2460 $$ = code_append($$, out);
2462 $$ = insert_finally($$, $6.finally, tmp);
2464 list_concat(state->method->exceptions, $6.l);
2466 $$ = var_block($$, state->vars);
2470 /* ------------ throw ------------------------------- */
2472 THROW : "throw" EXPRESSION {
2476 THROW : "throw" %prec prec_none {
2477 if(!state->exception_name)
2478 syntaxerror("re-throw only possible within a catch block");
2479 variable_t*v = find_variable(state, state->exception_name);
2481 $$=abc_getlocal($$, v->index);
2485 /* ------------ with -------------------------------- */
2487 WITH_HEAD : "with" '(' EXPRESSION ')' {
2489 if(state->method->has_exceptions) {
2490 int v = alloc_local();
2491 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2492 state->method->scope_code = abc_pushwith(state->method->scope_code);
2497 WITH : WITH_HEAD CODEBLOCK {
2498 /* remove getlocal;pushwith from scope code again */
2499 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2502 if(state->method->has_exceptions) {
2504 $$ = abc_setlocal($$, $1.number);
2506 $$ = abc_pushwith($$);
2507 $$ = code_append($$, $2);
2508 $$ = abc_popscope($$);
2512 /* ------------ packages and imports ---------------- */
2514 X_IDENTIFIER: T_IDENTIFIER
2515 | "package" {PASS12 $$="package";}
2516 | "namespace" {PASS12 $$="namespace";}
2517 | "NaN" {PASS12 $$="NaN";}
2518 | T_NAMESPACE {PASS12 $$=$1;}
2520 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2521 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2523 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2524 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2525 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2526 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2529 static void state_has_imports()
2531 state->wildcard_imports = list_clone(state->wildcard_imports);
2532 state->imports = dict_clone(state->imports);
2533 state->has_own_imports = 1;
2535 static void import_toplevel(const char*package)
2537 char* s = strdup(package);
2539 dict_put(state->import_toplevel_packages, s, 0);
2540 char*x = strrchr(s, '.');
2549 IMPORT : "import" T_IDENTIFIER {
2551 slotinfo_t*s = registry_find(state->package, $2);
2552 if(!s && as3_pass==1) {as3_schedule_class(state->package, $2);}
2553 state_has_imports();
2554 dict_put(state->imports, state->package, $2);
2557 IMPORT : "import" PACKAGEANDCLASS {
2559 slotinfo_t*s = registry_find($2->package, $2->name);
2560 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2561 as3_schedule_class($2->package, $2->name);
2563 state_has_imports();
2564 dict_put(state->imports, $2->name, $2);
2565 import_toplevel($2->package);
2568 IMPORT : "import" PACKAGE '.' '*' {
2570 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2571 as3_schedule_package($2);
2576 state_has_imports();
2577 list_append(state->wildcard_imports, i);
2578 import_toplevel(i->package);
2582 /* ------------ classes and interfaces (header) -------------- */
2584 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2585 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2586 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2587 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2589 $$.flags=$1.flags|$2.flags;
2590 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2591 $$.ns=$1.ns?$1.ns:$2.ns;
2594 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2595 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2596 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2597 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2598 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2599 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2600 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2601 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2602 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2603 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2607 EXTENDS : {PASS12 $$=0;}
2608 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2610 EXTENDS_LIST : {PASS12 $$=list_new();}
2611 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2613 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2614 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2616 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2617 EXTENDS IMPLEMENTS_LIST
2618 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2620 '}' {PASS12 endclass();$$=0;}
2622 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2624 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2625 startclass(&$1,$3,0,$4);}
2626 MAYBE_INTERFACE_BODY
2627 '}' {PASS12 endclass();$$=0;}
2629 /* ------------ classes and interfaces (body) -------------- */
2632 MAYBE_CLASS_BODY : CLASS_BODY
2633 CLASS_BODY : CLASS_BODY_ITEM
2634 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2635 CLASS_BODY_ITEM : ';'
2636 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2637 CLASS_BODY_ITEM : SLOT_DECLARATION
2638 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2640 CLASS_BODY_ITEM : CODE_STATEMENT {
2641 code_t*c = state->cls->static_init->header;
2642 c = code_append(c, $1);
2643 state->cls->static_init->header = c;
2646 MAYBE_INTERFACE_BODY :
2647 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2648 INTERFACE_BODY : IDECLARATION
2649 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2651 IDECLARATION : "var" T_IDENTIFIER {
2652 syntaxerror("variable declarations not allowed in interfaces");
2654 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2656 $1.flags |= FLAG_PUBLIC;
2657 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2658 syntaxerror("invalid method modifiers: interface methods always need to be public");
2660 startfunction(&$1,$3,$4,&$6,$8);
2661 endfunction(&$1,$3,$4,&$6,$8, 0);
2662 list_deep_free($6.list);
2665 /* ------------ classes and interfaces (body, slots ) ------- */
2668 static int slotstate_varconst = 0;
2669 static modifiers_t*slotstate_flags = 0;
2670 static void setslotstate(modifiers_t* flags, int varconst)
2672 slotstate_varconst = varconst;
2673 slotstate_flags = flags;
2676 if(flags->flags&FLAG_STATIC) {
2677 state->method = state->cls->static_init;
2679 state->method = state->cls->init;
2682 // reset to "default" state (all in class code is static by default) */
2683 state->method = state->cls->static_init;
2686 parserassert(state->method);
2689 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2691 int flags = modifiers->flags;
2692 namespace_t ns = modifiers2access(modifiers);
2695 multiname_t mname = {QNAME, &ns, 0, name};
2697 trait_list_t**traits;
2701 if(!global->init) global->init = abc_initscript(global->file);
2702 ns.name = state->package;
2703 traits = &global->init->traits;
2704 code = &global->init->method->body->code;
2705 } else if(flags&FLAG_STATIC) {
2707 traits = &state->cls->abc->static_traits;
2708 code = &state->cls->static_init->header;
2710 // instance variable
2711 traits = &state->cls->abc->traits;
2712 code = &state->cls->init->header;
2714 if(ns.access == ACCESS_PROTECTED) {
2715 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2721 *m = *multiname_clone(&mname);
2723 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2727 VARCONST: "var" | "const"
2729 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2731 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2732 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2734 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2737 int flags = slotstate_flags->flags;
2738 namespace_t ns = modifiers2access(slotstate_flags);
2742 varinfo_t* info = 0;
2744 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2746 check_override(i, flags);
2748 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2750 slotinfo_t*i = registry_find(state->package, $1);
2752 syntaxerror("package %s already contains '%s'", state->package, $1);
2754 if(ns.name && ns.name[0]) {
2755 syntaxerror("namespaces not allowed on package-level variables");
2757 info = varinfo_register_global(ns.access, state->package, $1);
2761 info->flags = flags;
2763 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2767 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2771 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2775 t->type_name = multiname_clone(&m);
2777 info->slot = t->slot_id;
2779 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2780 FIXME: is there a way to use slots and still don't have conflicting overrides?
2782 info->slot = t->slot_id = 0;
2784 constant_t cval = $3->type->eval($3);
2785 if(cval.type!=CONSTANT_UNKNOWN) {
2786 /* compile time constant */
2787 t->value = malloc(sizeof(constant_t));
2788 memcpy(t->value, &cval, sizeof(constant_t));
2789 info->value = constant_clone(t->value);
2791 typedcode_t v = node_read($3);
2792 /* initalization code (if needed) */
2794 if(v.c && !is_pushundefined(v.c)) {
2795 c = abc_getlocal_0(c);
2796 c = code_append(c, v.c);
2797 c = converttype(c, v.t, $2);
2799 c = abc_initproperty2(c, &mname);
2801 c = abc_setslot(c, t->slot_id);
2804 *code = code_append(*code, c);
2807 if(slotstate_varconst==KW_CONST) {
2808 t->kind= TRAIT_CONST;
2809 info->flags |= FLAG_CONST;
2816 /* ------------ constants -------------------------------------- */
2818 MAYBECONSTANT: {$$=0;}
2819 MAYBECONSTANT: '=' E {
2820 $$ = malloc(sizeof(constant_t));
2821 *$$ = node_eval($2);
2822 if($$->type == CONSTANT_UNKNOWN) {
2823 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2827 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2828 CONSTANT : T_INT {$$ = constant_new_int($1);}
2830 $$ = constant_new_uint($1);
2832 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2833 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2834 CONSTANT : "true" {$$ = constant_new_true($1);}
2835 CONSTANT : "false" {$$ = constant_new_false($1);}
2836 CONSTANT : "null" {$$ = constant_new_null($1);}
2837 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2838 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2840 /*CONSTANT : T_NAMESPACE {
2842 $$ = constant_new_namespace(namespace_new_namespace($1.url));
2845 /* ---------------------------xml ------------------------------ */
2848 static int xml_level = 0;
2852 multiname_t m = {QNAME, &stdns, 0, "XML"};
2855 v.c = abc_getlex2(v.c, &m);
2856 v.c = code_append(v.c, node_read($1).c);
2857 v.c = abc_construct(v.c, 1);
2862 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2863 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2864 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2866 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2869 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2872 XMLTEXT : {$$=mkstringnode("");}
2873 XMLTEXT : XMLTEXT XMLEXPR1 {
2874 $$ = mkaddnode($1,$2);
2876 XMLTEXT : XMLTEXT T_STRING {
2877 char* str = string_cstr(&$2);
2878 $$ = mkaddnode($1,mkstringnode(str));
2881 XMLTEXT : XMLTEXT '>' {
2882 $$ = mkaddnode($1, mkstringnode(">"));
2884 XML2 : XMLNODE XMLTEXT {
2885 $$ = mkaddnode($1,$2);
2887 XML2 : XML2 XMLNODE XMLTEXT {
2888 $$ = mkaddnode($1, mkaddnode($2,$3));
2890 XML_ID_OR_EXPR: T_IDENTIFIER {
2891 $$ = mkstringnode($1);
2893 XML_ID_OR_EXPR: XMLEXPR2 {
2897 MAYBE_XMLATTRIBUTES: {
2898 $$ = mkstringnode("");
2900 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {
2901 $$ = mkaddnode(mkstringnode(" "),$1);
2904 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2905 //$$ = allocprintf("<%s%s/>", $2, $3, $5, $8);
2906 $$ = mkaddnode(mkaddnode(mkaddnode(mkstringnode("<"),$2),$3),mkstringnode("/>"));
2908 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2909 //$$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2910 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2911 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),mkstringnode("</")),$8),mkstringnode(">"));
2913 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2914 //$$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2915 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2916 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),$6),mkstringnode("</")),$9),mkstringnode(">"));
2919 XMLATTRIBUTES: XMLATTRIBUTE {
2922 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {
2923 $$ = mkaddnode($1, mkaddnode(mkstringnode(" "),$2));
2925 XMLATTRIBUTE: XMLEXPR2 {
2928 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2929 char* str = string_cstr(&$3);
2930 $$ = mkaddnode($1, mkstringnode(concat2("=",str)));
2933 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2934 $$ = mkaddnode($1, mkaddnode(mkstringnode("=\""), mkaddnode($3, mkstringnode("\""))));
2936 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2937 $$ = mkaddnode(mkaddnode(mkstringnode(concat2($1,"=\"")), $3), mkstringnode("\""));
2939 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2940 char* str = string_cstr(&$3);
2941 $$=mkstringnode(allocprintf("%s=%s", $1,str));
2943 free($1);free((char*)$3.str);
2946 /* ------------ classes and interfaces (body, functions) ------- */
2948 // non-vararg version
2951 memset(&$$,0,sizeof($$));
2953 MAYBE_PARAM_LIST: PARAM_LIST {
2959 MAYBE_PARAM_LIST: "..." PARAM {
2961 memset(&$$,0,sizeof($$));
2963 list_append($$.list, $2);
2965 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2969 list_append($$.list, $4);
2973 PARAM_LIST: PARAM_LIST ',' PARAM {
2976 list_append($$.list, $3);
2980 memset(&$$,0,sizeof($$));
2981 list_append($$.list, $1);
2984 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2986 $$ = rfx_calloc(sizeof(param_t));
2992 PARAM: T_IDENTIFIER MAYBECONSTANT {
2994 $$ = rfx_calloc(sizeof(param_t));
2996 $$->type = TYPE_ANY;
3004 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
3005 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
3008 endfunction(&$1,$3,$4,&$6,0,0);
3010 if(!state->method->info) syntaxerror("internal error");
3012 code_t*c = method_header(state->method);
3013 c = wrap_function(c, 0, $11);
3015 endfunction(&$1,$3,$4,&$6,$8,c);
3017 list_deep_free($6.list);
3021 MAYBE_IDENTIFIER: T_IDENTIFIER
3022 MAYBE_IDENTIFIER: {PASS12 $$=0;}
3023 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
3024 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
3027 endfunction(0,0,$2,&$4,0,0);
3029 methodinfo_t*f = state->method->info;
3030 if(!f || !f->kind) syntaxerror("internal error");
3032 code_t*c = method_header(state->method);
3033 c = wrap_function(c, 0, $9);
3035 int index = state->method->var_index;
3036 endfunction(0,0,$2,&$4,$6,c);
3038 $$.c = abc_getlocal(0, index);
3039 $$.t = TYPE_FUNCTION(f);
3041 PASS12 list_deep_free($4.list);
3045 /* ------------- package + class ids --------------- */
3047 CLASS: X_IDENTIFIER {
3048 PASS1 NEW(unresolvedinfo_t,c);
3049 memset(c, 0, sizeof(*c));
3050 c->kind = INFOTYPE_UNRESOLVED;
3052 c->package = get_package_from_name($1);
3054 c->nsset = get_current_imports();
3055 /* make the compiler look for this class in the current directory,
3057 as3_schedule_class_noerror(state->package, $1);
3059 $$ = (classinfo_t*)c;
3061 slotinfo_t*s = find_class($1);
3062 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
3063 $$ = (classinfo_t*)s;
3066 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
3067 PASS1 NEW(unresolvedinfo_t,c);
3068 memset(c, 0, sizeof(*c));
3069 c->kind = INFOTYPE_UNRESOLVED;
3072 $$ = (classinfo_t*)c;
3074 slotinfo_t*s = registry_find($1, $3);
3075 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
3077 $$ = (classinfo_t*)s;
3080 CLASS_SPEC: PACKAGEANDCLASS
3083 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
3084 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
3086 TYPE : CLASS_SPEC {PASS12 $$=$1;}
3087 | '*' {PASS12 $$=TYPE_ANY;}
3088 | "void" {PASS12 $$=TYPE_VOID;}
3090 | "String" {$$=registry_getstringclass();}
3091 | "int" {$$=registry_getintclass();}
3092 | "uint" {$$=registry_getuintclass();}
3093 | "Boolean" {$$=registry_getbooleanclass();}
3094 | "Number" {$$=registry_getnumberclass();}
3097 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
3098 MAYBETYPE: {PASS12 $$=0;}
3100 /* ----------function calls, delete, constructor calls ------ */
3102 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3103 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3105 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3106 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3107 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3109 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3113 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3114 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3115 $$.number= $1.number+1;
3116 $$.cc = code_append($1.cc, $2.c);
3120 NEW : "new" E XX MAYBE_PARAM_VALUES {
3121 typedcode_t v = node_read($2);
3123 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3125 code_t*paramcode = $4.cc;
3126 if($$.c->opcode == OPCODE_GETPROPERTY) {
3127 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3128 $$.c = code_cutlast($$.c);
3129 $$.c = code_append($$.c, paramcode);
3130 $$.c = abc_constructprop2($$.c, name, $4.number);
3131 multiname_destroy(name);
3132 } else if(is_getlocal($$.c)) {
3133 $$.c = code_append($$.c, paramcode);
3134 $$.c = abc_construct($$.c, $4.number);
3135 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3137 classinfo_t*c = v.t->data;
3139 $$.c = abc_findpropstrict2(0, &m);
3140 $$.c = code_append($$.c, paramcode);
3141 $$.c = abc_constructprop2($$.c, &m, $4.number);
3142 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3143 int slot = (int)(ptroff_t)$$.c->data[0];
3144 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3145 multiname_t*name = t->name;
3146 $$.c = code_cutlast($$.c);
3147 $$.c = code_append($$.c, paramcode);
3148 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3150 $$.c = code_append($$.c, paramcode);
3151 $$.c = abc_construct($$.c, $4.number);
3155 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3158 $$.c = abc_coerce_a($$.c);
3163 /* TODO: use abc_call (for calling local variables),
3164 abc_callstatic (for calling own methods)
3167 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3169 typedcode_t v = node_read($1);
3171 if($$.c->opcode == OPCODE_COERCE_A) {
3172 $$.c = code_cutlast($$.c);
3174 code_t*paramcode = $3.cc;
3177 if($$.c->opcode == OPCODE_GETPROPERTY) {
3178 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3179 $$.c = code_cutlast($$.c);
3180 $$.c = code_append($$.c, paramcode);
3181 $$.c = abc_callproperty2($$.c, name, $3.number);
3182 multiname_destroy(name);
3183 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3184 int slot = (int)(ptroff_t)$$.c->data[0];
3185 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3186 if(t->kind!=TRAIT_METHOD) {
3187 //ok: flash allows to assign closures to members.
3189 multiname_t*name = t->name;
3190 $$.c = code_cutlast($$.c);
3191 $$.c = code_append($$.c, paramcode);
3192 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3193 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3194 } else if($$.c->opcode == OPCODE_GETSUPER) {
3195 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3196 $$.c = code_cutlast($$.c);
3197 $$.c = code_append($$.c, paramcode);
3198 $$.c = abc_callsuper2($$.c, name, $3.number);
3199 multiname_destroy(name);
3201 $$.c = abc_getglobalscope($$.c);
3202 $$.c = code_append($$.c, paramcode);
3203 $$.c = abc_call($$.c, $3.number);
3206 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3207 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3208 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3209 // calling a class is like a typecast
3210 $$.t = (classinfo_t*)v.t->data;
3213 $$.c = abc_coerce_a($$.c);
3217 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3218 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3219 if(!state->method) syntaxerror("super() not allowed outside of a function");
3220 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3223 $$.c = abc_getlocal_0($$.c);
3225 $$.c = code_append($$.c, $3.cc);
3227 this is dependent on the control path, check this somewhere else
3228 if(state->method->has_super)
3229 syntaxerror("constructor may call super() only once");
3231 state->method->has_super = 1;
3233 $$.c = abc_constructsuper($$.c, $3.number);
3234 $$.c = abc_pushundefined($$.c);
3238 DELETE: "delete" E {
3239 typedcode_t v = node_read($2);
3241 if($$.c->opcode == OPCODE_COERCE_A) {
3242 $$.c = code_cutlast($$.c);
3244 multiname_t*name = 0;
3245 if($$.c->opcode == OPCODE_GETPROPERTY) {
3246 $$.c->opcode = OPCODE_DELETEPROPERTY;
3247 } else if($$.c->opcode == OPCODE_GETSLOT) {
3248 int slot = (int)(ptroff_t)$$.c->data[0];
3249 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3250 $$.c = code_cutlast($$.c);
3251 $$.c = abc_deleteproperty2($$.c, name);
3253 $$.c = abc_getlocal_0($$.c);
3254 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3255 $$.c = abc_deleteproperty2($$.c, &m);
3257 $$.t = TYPE_BOOLEAN;
3260 RETURN: "return" %prec prec_none {
3261 $$ = abc_returnvoid(0);
3263 RETURN: "return" EXPRESSION {
3265 $$ = abc_returnvalue($$);
3268 // ----------------------- expression types -------------------------------------
3270 NONCOMMAEXPRESSION : E %prec below_lt {
3273 EXPRESSION : COMMA_EXPRESSION {
3276 COMMA_EXPRESSION : E %prec below_lt {
3277 $$ = mkmultinode(&node_comma, $1);
3279 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3280 $$ = multinode_extend($1, $3);
3282 VOIDEXPRESSION : E %prec below_minus {
3285 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3287 $$ = code_append($$, node_exec($3));
3290 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3291 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3293 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3294 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3295 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3296 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3297 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3299 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3301 $$.cc = code_append($$.cc, $1);
3302 $$.cc = code_append($$.cc, $3.c);
3305 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3307 $$.number = $1.number+2;
3308 $$.cc = code_append($$.cc, $3);
3309 $$.cc = code_append($$.cc, $5.c);
3312 // ----------------------- expression evaluation -------------------------------------
3314 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3315 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3316 E : NEW {$$ = mkcodenode($1);}
3317 E : DELETE {$$ = mkcodenode($1);}
3318 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3319 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3322 $$ = mkconstnode($1);
3333 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3335 v.c = abc_getlex2(v.c, &m);
3336 v.c = abc_pushstring(v.c, $1.pattern);
3337 v.c = abc_construct(v.c, 1);
3339 v.c = abc_getlex2(v.c, &m);
3340 v.c = abc_pushstring(v.c, $1.pattern);
3341 v.c = abc_pushstring(v.c, $1.options);
3342 v.c = abc_construct(v.c, 2);
3350 state->method->need_arguments = 1;
3353 v.c = abc_getlocal(0, state->method->need_arguments);
3359 E : '[' MAYBE_EXPRESSION_LIST ']' {
3362 v.c = code_append(v.c, $2.cc);
3363 v.c = abc_newarray(v.c, $2.number);
3364 v.t = registry_getarrayclass();
3369 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3372 v.c = code_append(v.c, $2.cc);
3373 v.c = abc_newobject(v.c, $2.number/2);
3374 v.t = registry_getobjectclass();
3378 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3379 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3380 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3381 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3382 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3383 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3384 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3385 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3386 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3387 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3388 E : '!' E {$$ = mknode1(&node_not, $2);}
3389 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3390 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3391 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3392 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3393 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3394 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3395 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3396 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3397 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3398 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3399 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3400 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3401 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3402 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3403 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3404 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3405 E : "typeof" E {$$ = mknode1(&node_typeof, $2);}
3406 E : "void" E {$$ = mknode1(&node_void, $2);}
3407 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3408 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3409 E : '-' E {$$ = mknode1(&node_neg, $2);}
3410 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3411 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3412 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3413 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3414 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3415 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3416 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3417 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3418 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3419 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3420 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3421 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3422 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3423 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3425 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3426 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3427 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3428 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3430 E : "super" '.' T_IDENTIFIER
3431 { if(!state->cls->info)
3432 syntaxerror("super keyword not allowed outside a class");
3433 classinfo_t*t = state->cls->info->superclass;
3434 if(!t) t = TYPE_OBJECT;
3435 memberinfo_t*f = findmember_nsset(t, $3, 1);
3436 MEMBER_MULTINAME(m, f, $3);
3439 v.c = abc_getlocal_0(v.c);
3440 v.c = abc_getsuper2(v.c, &m);
3441 v.t = slotinfo_gettype((slotinfo_t*)f);
3445 E : '@' T_IDENTIFIER {
3447 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3448 v.c = abc_getlex2(0, &m);
3453 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3456 typedcode_t v = node_read($1);
3457 typedcode_t w = node_read($5);
3459 int index = alloc_local();
3460 int result = alloc_local();
3461 int tmp = alloc_local();
3462 int xml = alloc_local();
3464 c = code_append(c, v.c);
3465 c = abc_checkfilter(c);
3466 c = abc_coerce_a(c); //hasnext2 converts to *
3467 c = abc_setlocal(c, xml);
3468 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3469 c = abc_getlex2(c, &m);
3470 c = abc_construct(c, 0);
3471 c = abc_setlocal(c, result);
3472 c = abc_pushbyte(c, 0);
3473 c = abc_setlocal(c, index);
3474 code_t*jmp = c = abc_jump(c, 0);
3475 code_t*loop = c = abc_label(c);
3476 c = abc_getlocal(c, xml);
3477 c = abc_getlocal(c, index);
3478 c = abc_nextvalue(c);
3480 c = abc_setlocal(c, tmp);
3481 c = abc_pushwith(c);
3482 c = code_append(c, w.c);
3483 c = abc_popscope(c);
3484 code_t*b = c = abc_iffalse(c, 0);
3485 c = abc_getlocal(c, result);
3486 c = abc_getlocal(c, index);
3487 c = abc_getlocal(c, tmp);
3488 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3489 c = abc_setproperty2(c, &m2);
3490 c = b->branch = jmp->branch = abc_nop(c);
3491 c = abc_kill(c, tmp);
3492 c = abc_hasnext2(c, xml, index);
3493 c = abc_iftrue(c, loop);
3494 c = abc_getlocal(c, result);
3495 c = abc_kill(c, xml);
3496 c = abc_kill(c, result);
3497 c = abc_kill(c, index);
3499 c = var_block(c, state->vars);
3507 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3508 ID_OR_NS : '*' {$$="*";}
3509 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3510 SUBNODE: X_IDENTIFIER
3514 MAYBE_NS: T_IDENTIFIER "::" {$$=$1;}
3515 | T_NAMESPACE "::" {$$=(char*)$1;}
3516 | '*' "::" {$$="*";}
3519 E : E '.' ID_OR_NS "::" SUBNODE {
3520 typedcode_t v = node_read($1);
3521 typedcode_t w = node_read(resolve_identifier($3));
3522 v.c = code_append(v.c, w.c);
3523 if(!TYPE_IS_NAMESPACE(w.t)) {
3524 as3_softwarning("%s might not be a namespace", $3);
3526 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3527 multiname_t m = {RTQNAME, 0, 0, $5};
3528 v.c = abc_getproperty2(v.c, &m);
3529 if(TYPE_IS_XML(v.t)) {
3532 v.c = abc_coerce_a(v.c);
3537 E : E ".." SUBNODE {
3538 typedcode_t v = node_read($1);
3539 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3540 v.c = abc_getdescendants2(v.c, &m);
3544 E : E '.' '[' E ']' {
3545 typedcode_t v = node_read($1);
3546 typedcode_t w = node_read($4);
3547 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3548 v.c = code_append(v.c, w.c);
3549 v.c = converttype(w.c, w.t, TYPE_STRING);
3550 v.c = abc_getproperty2(v.c, &m);
3555 E : E '.' '@' SUBNODE {
3556 typedcode_t v = node_read($1);
3557 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3558 v.c = abc_getproperty2(v.c, &m);
3562 E : E ".." '@' SUBNODE {
3563 typedcode_t v = node_read($1);
3564 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3565 v.c = abc_getdescendants2(v.c, &m);
3569 E : E '.' '@' '[' E ']' {
3570 typedcode_t v = node_read($1);
3571 typedcode_t w = node_read($5);
3572 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3573 v.c = code_append(v.c, w.c);
3574 v.c = converttype(w.c, w.t, TYPE_STRING);
3575 v.c = abc_getproperty2(v.c, &m);
3579 E : E ".." '@' '[' E ']' {
3580 typedcode_t v = node_read($1);
3581 typedcode_t w = node_read($5);
3582 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3583 v.c = code_append(v.c, w.c);
3584 v.c = converttype(w.c, w.t, TYPE_STRING);
3585 v.c = abc_getdescendants2(v.c, &m);
3590 MEMBER : E '.' SUBNODE {
3591 typedcode_t v1 = node_read($1);
3593 classinfo_t*t = v1.t;
3595 if(TYPE_IS_CLASS(t) && t->data) {
3599 if(TYPE_IS_XML(t)) {
3600 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3601 $$.c = abc_getproperty2($$.c, &m);
3602 $$.c = abc_coerce_a($$.c);
3603 $$.t = TYPE_XMLLIST;
3605 if(t->subtype==INFOTYPE_UNRESOLVED) {
3606 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3608 memberinfo_t*f = findmember_nsset(t, $3, 1);
3610 if(f && !is_static != !(f->flags&FLAG_STATIC))
3612 if(f && f->slot && !noslot) {
3613 $$.c = abc_getslot($$.c, f->slot);
3616 if(!TYPE_IS_XMLLIST(t)) {
3617 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3620 MEMBER_MULTINAME(m, f, $3);
3621 $$.c = abc_getproperty2($$.c, &m);
3623 /* determine type */
3624 $$.t = slotinfo_gettype((slotinfo_t*)f);
3626 $$.c = abc_coerce_a($$.c);
3628 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3629 string_t*package = v1.c->data[0];
3630 char*package2 = concat3(package->str, ".", $3);
3632 slotinfo_t*a = registry_find(package->str, $3);
3635 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3636 registry_ispackage(package2)) {
3638 $$.c->data[0] = string_new4(package2);
3641 syntaxerror("couldn't resolve %s", package2);
3644 /* when resolving a property on an unknown type, we do know the
3645 name of the property (and don't seem to need the package), but
3646 we need to make avm2 try out all access modes */
3647 as3_softwarning("Resolving %s on unknown type", $3);
3648 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3649 $$.c = abc_getproperty2($$.c, &m);
3650 $$.c = abc_coerce_a($$.c);
3656 node_t* var_read(variable_t*v)
3659 o.c = abc_getlocal(0, v->index);
3661 return mkcodenode(o);
3664 node_t* resolve_identifier(char*name)
3674 /* look at variables */
3675 if((v = find_variable(state, name))) {
3676 // name is a local variable
3679 if((v = find_slot(state->method, name))) {
3680 o.c = abc_getscopeobject(o.c, 1);
3681 o.c = abc_getslot(o.c, v->index);
3683 return mkcodenode(o);
3686 int i_am_static = state->method->is_static;
3688 /* look at current class' members */
3689 if(!state->method->inner &&
3690 !state->xmlfilter &&
3692 (f = findmember_nsset(state->cls->info, name, 1)))
3694 // name is a member or attribute in this class
3695 int var_is_static = (f->flags&FLAG_STATIC);
3697 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3698 /* if the variable is a constant (and we know what is evaluates to), we
3699 can just use the value itself */
3700 varinfo_t*v = (varinfo_t*)f;
3702 return mkconstnode(v->value);
3706 if(var_is_static >= i_am_static) {
3707 if(f->kind == INFOTYPE_METHOD) {
3708 o.t = TYPE_FUNCTION(f);
3713 if(var_is_static && !i_am_static) {
3714 /* access to a static member from a non-static location.
3715 do this via findpropstrict:
3716 there doesn't seem to be any non-lookup way to access
3717 static properties of a class */
3718 state->method->late_binding = 1;
3720 namespace_t ns = {f->access, f->package};
3721 multiname_t m = {QNAME, &ns, 0, name};
3722 o.c = abc_findpropstrict2(o.c, &m);
3723 o.c = abc_getproperty2(o.c, &m);
3724 return mkcodenode(o);
3725 } else if(f->slot>0) {
3726 o.c = abc_getlocal_0(o.c);
3727 o.c = abc_getslot(o.c, f->slot);
3728 return mkcodenode(o);
3730 MEMBER_MULTINAME(m, f, name);
3731 o.c = abc_getlocal_0(o.c);
3732 o.c = abc_getproperty2(o.c, &m);
3733 return mkcodenode(o);
3738 /* look at actual classes, in the current package and imported */
3739 if(!state->xmlfilter && (a = find_class(name))) {
3740 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3741 o.c = abc_getlocal_0(0);
3742 o.t = TYPE_CLASS((classinfo_t*)a);
3746 return mkcodenode(o);
3749 /* look through package prefixes */
3750 if(!state->xmlfilter &&
3751 (dict_contains(state->import_toplevel_packages, name) ||
3752 registry_ispackage(name))) {
3753 o.c = abc___pushpackage__(o.c, name);
3755 return mkcodenode(o); //?
3758 /* unknown object, let the avm2 resolve it */
3760 if(!state->method->inner && !state->xmlfilter) {
3761 /* we really should make inner functions aware of the class context */
3762 as3_warning("Couldn't resolve '%s', doing late binding", name);
3764 state->method->late_binding = 1;
3766 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3769 o.c = abc_findpropstrict2(o.c, &m);
3770 o.c = abc_getproperty2(o.c, &m);
3771 return mkcodenode(o);
3776 VAR_READ : T_IDENTIFIER {
3778 /* Queue unresolved identifiers for checking against the parent
3779 function's variables.
3780 We consider everything which is not a local variable "unresolved".
3781 This encompasses class names, members of the surrounding class
3782 etc. which is *correct* because local variables of the parent function
3786 if(!find_variable(state, $1)) {
3787 unknown_variable($1);
3788 /* let the compiler know that it might want to check the current directory/package
3789 for this identifier- maybe there's a file $1.as defining $1. */
3790 as3_schedule_class_noerror(state->package, $1);
3796 $$ = resolve_identifier($1);
3799 // ----------------- namespaces -------------------------------------------------
3802 void add_active_url(const char*url)
3806 list_append(state->active_namespace_urls, n);
3810 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3812 NEW(namespace_decl_t,n);
3817 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3819 NEW(namespace_decl_t,n);
3824 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3826 NEW(namespace_decl_t,n);
3831 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3833 trie_put(active_namespaces, (unsigned char*)$2->name, (void*)$2->url);
3835 namespace_t access = modifiers2access(&$1);
3836 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3837 var->type = TYPE_NAMESPACE;
3839 ns.access = ACCESS_NAMESPACE;
3841 var->value = constant_new_namespace(&ns);
3844 MULTINAME(m, TYPE_NAMESPACE);
3845 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3846 t->value = var->value;
3847 t->type_name = multiname_clone(&m);
3853 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3855 as3_warning("default xml namespaces not supported yet");
3859 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3861 const char*url = $3->name;
3863 varinfo_t*s = (varinfo_t*)$3;
3864 if(s->kind == INFOTYPE_UNRESOLVED) {
3865 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3867 syntaxerror("Couldn't resolve namespace %s", $3->name);
3870 if(!s || s->kind != INFOTYPE_VAR)
3871 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3872 if(!s->value || !NS_TYPE(s->value->type))
3873 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3874 url = s->value->ns->name;
3876 trie_put(active_namespaces, (unsigned char*)$3->name, (void*)url);
3877 add_active_url(url);