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 typedef struct _state {
377 import_list_t*wildcard_imports;
378 dict_t*import_toplevel_packages;
381 namespace_list_t*active_namespace_urls;
383 char has_own_imports;
384 char new_vars; // e.g. transition between two functions
385 char xmlfilter; // are we inside a xmlobj..() filter?
388 methodstate_t*method;
395 dict_t*allvars; // also contains variables from sublevels
398 typedef struct _global {
401 parsedclass_list_t*classes;
402 abc_script_t*classinit;
404 abc_script_t*init; //package-level code
407 dict_t*file2token2info;
410 static global_t*global = 0;
411 static state_t* state = 0;
415 /* protected handling here is a big hack: we just assume the protectedns
416 is package:class. the correct approach would be to add the proper
417 namespace to all protected members in the registry, even though that
418 would slow down searching */
419 #define MEMBER_MULTINAME(m,f,n) \
423 m##_ns.access = ((slotinfo_t*)(f))->access; \
424 if(m##_ns.access == ACCESS_NAMESPACE) \
425 m##_ns.name = ((slotinfo_t*)(f))->package; \
426 else if(m##_ns.access == ACCESS_PROTECTED && (f)->parent) \
427 m##_ns.name = concat3((f)->parent->package,":",(f)->parent->name); \
432 m.namespace_set = 0; \
433 m.name = ((slotinfo_t*)(f))->name; \
435 m.type = MULTINAME; \
437 m.namespace_set = &nopackage_namespace_set; \
441 /* warning: list length of namespace set is undefined */
442 #define MULTINAME_LATE(m, access, package) \
443 namespace_t m##_ns = {access, package}; \
444 namespace_set_t m##_nsset; \
445 namespace_list_t m##_l;m##_l.next = 0; \
446 m##_nsset.namespaces = &m##_l; \
447 m##_nsset = m##_nsset; \
448 m##_l.namespace = &m##_ns; \
449 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
451 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
452 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
453 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
454 static namespace_t stdns = {ACCESS_PACKAGE, ""};
455 static namespace_list_t nl4 = {&stdns,0};
456 static namespace_list_t nl3 = {&ns3,&nl4};
457 static namespace_list_t nl2 = {&ns2,&nl3};
458 static namespace_list_t nl1 = {&ns1,&nl2};
459 static namespace_set_t nopackage_namespace_set = {&nl1};
461 static dict_t*definitions=0;
462 void as3_set_define(const char*c)
465 definitions = dict_new();
466 if(!dict_contains(definitions,c))
467 dict_put(definitions,c,0);
470 static void new_state()
473 state_t*oldstate = state;
475 memcpy(s, state, sizeof(state_t)); //shallow copy
477 s->imports = dict_new();
479 if(!s->import_toplevel_packages) {
480 s->import_toplevel_packages = dict_new();
484 state->has_own_imports = 0;
485 state->vars = dict_new();
486 state->old = oldstate;
489 trie_remember(active_namespaces);
492 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
495 static void state_destroy(state_t*state)
497 if(state->has_own_imports) {
498 list_free(state->wildcard_imports);
499 dict_destroy(state->imports);state->imports=0;
501 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
502 dict_destroy(state->imports);state->imports=0;
505 dict_destroy(state->vars);state->vars=0;
507 if(state->new_vars && state->allvars) {
508 parserassert(!state->old || state->old->allvars != state->allvars);
509 DICT_ITERATE_DATA(state->allvars, void*, data) {
512 dict_destroy(state->allvars);
515 list_free(state->active_namespace_urls)
516 state->active_namespace_urls = 0;
521 static void old_state()
523 trie_rollback(active_namespaces);
525 if(!state || !state->old)
526 syntaxerror("invalid nesting");
527 state_t*leaving = state;
531 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
532 free(leaving->method);
535 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
540 state_destroy(leaving);
543 static code_t* method_header(methodstate_t*m);
544 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
545 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0);
548 static char* internal_filename_package = 0;
549 void initialize_file(char*filename)
552 syntaxerror("invalid call to initialize_file during parsing of another file");
555 active_namespaces = trie_new();
558 state->package = internal_filename_package = strdup(filename);
559 state->allvars = dict_new();
561 global->token2info = dict_lookup(global->file2token2info,
562 current_filename // use long version
564 if(!global->token2info) {
565 global->token2info = dict_new2(&ptr_type);
566 dict_put(global->file2token2info, current_filename, global->token2info);
570 state->method = rfx_calloc(sizeof(methodstate_t));
571 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
572 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
574 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
575 state->method->variable_count = 0;
577 syntaxerror("internal error: skewed tokencount");
578 function_initvars(state->method, 0, 0, 0, 1);
585 if(!state || state->level!=1) {
586 syntaxerror("unexpected end of file in pass %d", as3_pass);
590 dict_del(global->file2token2info, current_filename);
591 code_t*header = method_header(state->method);
592 //if(global->init->method->body->code || global->init->traits) {
594 code_t*c = wrap_function(header, 0, global->init->method->body->code);
595 global->init->method->body->code = abc_returnvoid(c);
596 free(state->method);state->method=0;
600 //free(state->package);state->package=0; // used in registry
601 state_destroy(state);state=0;
604 void initialize_parser()
606 global = rfx_calloc(sizeof(global_t));
607 global->file = abc_file_new();
608 global->file->flags &= ~ABCFILE_LAZY;
609 global->file2token2info = dict_new();
610 global->token2info = 0;
611 global->classinit = abc_initscript(global->file);
614 void* finish_parser()
616 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
617 global->token2info=0;
619 initcode_add_classlist(global->classinit, global->classes);
624 typedef struct _variable {
630 methodstate_t*is_inner_method;
633 static variable_t* find_variable(state_t*s, char*name)
635 if(s->method->no_variable_scoping) {
636 return dict_lookup(s->allvars, name);
641 v = dict_lookup(s->vars, name);
643 if(s->new_vars) break;
649 static variable_t* find_slot(state_t*s, const char*name)
651 if(s->method && s->method->slots)
652 return dict_lookup(s->method->slots, name);
656 static variable_t* find_variable_safe(state_t*s, char*name)
658 variable_t* v = find_variable(s, name);
660 syntaxerror("undefined variable: %s", name);
664 static char variable_exists(char*name)
666 return dict_contains(state->vars, name);
669 static code_t*defaultvalue(code_t*c, classinfo_t*type)
671 if(TYPE_IS_INT(type)) {
672 c = abc_pushbyte(c, 0);
673 } else if(TYPE_IS_UINT(type)) {
674 c = abc_pushuint(c, 0);
675 } else if(TYPE_IS_FLOAT(type)) {
677 } else if(TYPE_IS_BOOLEAN(type)) {
678 c = abc_pushfalse(c);
679 } else if(TYPE_IS_STRING(type)) {
683 //c = abc_pushundefined(c);
684 syntaxerror("internal error: can't generate default value for * type");
688 c = abc_coerce2(c, &m);
693 static int alloc_local()
695 return state->method->variable_count++;
698 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
701 variable_t*v = find_slot(state, name);
709 v->index = alloc_local();
711 v->init = v->kill = init;
714 if(!state->method->no_variable_scoping)
716 if(dict_contains(state->vars, name))
717 syntaxerror("variable %s already defined", name);
718 dict_put(state->vars, name, v);
720 if(state->method->no_variable_scoping &&
722 dict_contains(state->allvars, name))
724 variable_t*v = dict_lookup(state->allvars, name);
726 syntaxerror("variable %s already defined.", name);
729 dict_put(state->allvars, name, v);
734 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
736 return new_variable2(name, type, init, maybeslot)->index;
739 #define TEMPVARNAME "__as3_temp__"
742 variable_t*v = find_variable(state, TEMPVARNAME);
747 i = new_variable(TEMPVARNAME, 0, 0, 0);
752 static code_t* var_block(code_t*body, dict_t*vars)
757 DICT_ITERATE_DATA(vars, variable_t*, v) {
758 if(v->type && v->init) {
759 c = defaultvalue(c, v->type);
760 c = abc_setlocal(c, v->index);
762 if(v->type && v->kill) {
763 k = abc_kill(k, v->index);
770 if(x->opcode== OPCODE___BREAK__ ||
771 x->opcode== OPCODE___CONTINUE__) {
772 /* link kill code before break/continue */
773 code_t*e = code_dup(k);
774 code_t*s = code_start(e);
786 c = code_append(c, body);
787 c = code_append(c, k);
791 static void unknown_variable(char*name)
793 if(!state->method->unresolved_variables)
794 state->method->unresolved_variables = dict_new();
795 if(!dict_contains(state->method->unresolved_variables, name))
796 dict_put(state->method->unresolved_variables, name, 0);
799 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
801 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
802 c = abc_getlocal_0(c);
803 c = abc_pushscope(c);
806 /* FIXME: this alloc_local() causes variable indexes to be
807 different in pass2 than in pass1 */
808 if(!m->activation_var) {
809 m->activation_var = alloc_local();
812 c = abc_newactivation(c);
814 c = abc_pushscope(c);
815 c = abc_setlocal(c, m->activation_var);
817 c = abc_getlocal(c, m->activation_var);
818 c = abc_pushscope(c);
824 static code_t* method_header(methodstate_t*m)
828 c = add_scope_code(c, m, 1);
830 methodstate_list_t*l = m->innerfunctions;
832 parserassert(l->methodstate->abc);
833 if(m->uses_slots && l->methodstate->is_a_slot) {
834 c = abc_getscopeobject(c, 1);
835 c = abc_newfunction(c, l->methodstate->abc);
837 c = abc_setlocal(c, l->methodstate->var_index);
838 c = abc_setslot(c, l->methodstate->slot_index);
840 c = abc_newfunction(c, l->methodstate->abc);
841 c = abc_setlocal(c, l->methodstate->var_index);
843 free(l->methodstate);l->methodstate=0;
847 c = code_append(c, m->header);
850 if(m->is_constructor && !m->has_super) {
851 // call default constructor
852 c = abc_getlocal_0(c);
853 c = abc_constructsuper(c, 0);
857 /* all parameters that are used by inner functions
858 need to be copied from local to slot */
859 parserassert(m->activation_var);
860 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
861 if(v->is_parameter) {
862 c = abc_getlocal(c, m->activation_var);
863 c = abc_getlocal(c, v->index);
864 c = abc_setslot(c, v->index);
868 list_free(m->innerfunctions);
869 m->innerfunctions = 0;
874 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
876 c = code_append(c, header);
877 c = code_append(c, var_block(body, state->method->no_variable_scoping?state->allvars:state->vars));
878 /* append return if necessary */
879 if(!c || (c->opcode != OPCODE_RETURNVOID &&
880 c->opcode != OPCODE_RETURNVALUE)) {
881 c = abc_returnvoid(c);
886 static void startpackage(char*name)
889 state->package = strdup(name);
891 static void endpackage()
893 //used e.g. in classinfo_register:
894 //free(state->package);state->package=0;
898 #define FLAG_PUBLIC 256
899 #define FLAG_PROTECTED 512
900 #define FLAG_PRIVATE 1024
901 #define FLAG_PACKAGEINTERNAL 2048
902 #define FLAG_NAMESPACE 4096
904 static namespace_t modifiers2access(modifiers_t*mod)
909 if(mod->flags&FLAG_NAMESPACE) {
910 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
911 syntaxerror("invalid combination of access levels and namespaces");
912 ns.access = ACCESS_NAMESPACE;
914 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
916 /* shouldn't happen- the tokenizer only reports something as a namespace
917 if it was already registered */
918 trie_dump(active_namespaces);
919 syntaxerror("unknown namespace: %s", mod->ns);
922 } else if(mod->flags&FLAG_PUBLIC) {
923 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
924 syntaxerror("invalid combination of access levels");
925 ns.access = ACCESS_PACKAGE;
926 } else if(mod->flags&FLAG_PRIVATE) {
927 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
928 syntaxerror("invalid combination of access levels");
929 ns.access = ACCESS_PRIVATE;
930 } else if(mod->flags&FLAG_PROTECTED) {
931 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
932 syntaxerror("invalid combination of access levels");
933 ns.access = ACCESS_PROTECTED;
935 ns.access = ACCESS_PACKAGEINTERNAL;
939 static slotinfo_t* find_class(const char*name);
941 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
943 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
946 static void innerfunctions2vars(methodstate_t*m)
948 methodstate_list_t*l = m->innerfunctions;
950 methodstate_t*m = l->methodstate;
952 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 0);
953 m->var_index = v->index;
955 m->slot_index = m->is_a_slot;
956 v->is_inner_method = m;
961 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
966 index = new_variable("this", 0, 0, 0);
967 else if(!m->is_global)
968 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
970 index = new_variable("globalscope", 0, 0, 0);
971 parserassert(!index);
976 for(p=params->list;p;p=p->next) {
977 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
980 if(as3_pass==2 && m->need_arguments) {
981 /* arguments can never be used by an innerfunction (the inner functions
982 have their own arguments var), so it's ok to not initialize this until
983 pass 2. (We don't know whether we need it before, anyway) */
984 variable_t*v = new_variable2("arguments", TYPE_ARRAY, 0, 0);
985 m->need_arguments = v->index;
989 innerfunctions2vars(m);
992 m->scope_code = add_scope_code(m->scope_code, m, 0);
994 /* exchange unresolved identifiers with the actual objects */
995 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
996 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
997 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
998 if(!type || type->kind != INFOTYPE_CLASS) {
999 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
1009 char*as3_globalclass=0;
1010 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
1013 syntaxerror("inner classes now allowed");
1018 classinfo_list_t*mlist=0;
1020 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
1021 syntaxerror("invalid modifier(s)");
1023 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
1024 syntaxerror("public and internal not supported at the same time.");
1026 if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
1027 syntaxerror("protected and static not supported at the same time.");
1029 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1030 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1031 // all classes extend object
1032 extends = registry_getobjectclass();
1035 /* create the class name, together with the proper attributes */
1039 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
1040 access = ACCESS_PRIVATE; package = internal_filename_package;
1041 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
1042 access = ACCESS_PACKAGEINTERNAL; package = state->package;
1043 } else if(state->package!=internal_filename_package) {
1044 access = ACCESS_PACKAGE; package = state->package;
1046 syntaxerror("public classes only allowed inside a package");
1050 state->cls = rfx_calloc(sizeof(classstate_t));
1051 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1052 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1053 state->cls->static_init->is_static=FLAG_STATIC;
1054 state->cls->static_init->variable_count=1;
1055 /* notice: we make no effort to initialize the top variable (local0) here,
1056 even though it has special meaning. We just rely on the fact
1057 that pass 1 won't do anything with variables */
1059 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1061 /* set current method to constructor- all code within the class-level (except
1062 static variable initializations) will be executed during construction time */
1063 state->method = state->cls->init;
1065 if(registry_find(package, classname)) {
1066 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1068 /* build info struct */
1069 int num_interfaces = (list_length(implements));
1070 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1071 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1072 state->cls->info->superclass = extends;
1075 classinfo_list_t*l = implements;
1076 for(l=implements;l;l=l->next) {
1077 state->cls->info->interfaces[pos++] = l->classinfo;
1082 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1084 state->method = state->cls->init;
1085 parserassert(state->cls && state->cls->info);
1087 function_initvars(state->cls->init, 0, 0, 0, 1);
1088 function_initvars(state->cls->static_init, 0, 0, 0, 0);
1090 if(extends && (extends->flags & FLAG_FINAL))
1091 syntaxerror("Can't extend final class '%s'", extends->name);
1094 while(state->cls->info->interfaces[pos]) {
1095 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1096 syntaxerror("'%s' is not an interface",
1097 state->cls->info->interfaces[pos]->name);
1101 /* generate the abc code for this class */
1102 MULTINAME(classname2,state->cls->info);
1103 multiname_t*extends2 = sig2mname(extends);
1105 /* don't add the class to the class index just yet- that will be done later
1107 state->cls->abc = abc_class_new(0, &classname2, extends2);
1108 state->cls->abc->file = global->file;
1110 multiname_destroy(extends2);
1111 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1112 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1113 if(state->cls->info->flags&FLAG_INTERFACE) {
1114 abc_class_interface(state->cls->abc);
1117 for(mlist=implements;mlist;mlist=mlist->next) {
1118 MULTINAME(m, mlist->classinfo);
1119 abc_class_add_interface(state->cls->abc, &m);
1122 state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
1123 list_append(global->classes, state->cls->dependencies);
1125 /* flash.display.MovieClip handling */
1126 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1127 if(state->package && state->package[0]) {
1128 as3_globalclass = concat3(state->package, ".", classname);
1130 as3_globalclass = strdup(classname);
1136 static void endclass()
1139 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1141 c = abc_getlocal_0(c);
1142 c = abc_constructsuper(c, 0);
1143 state->cls->init->header = code_append(state->cls->init->header, c);
1144 state->cls->has_constructor=1;
1146 if(state->cls->init) {
1147 if(state->cls->info->flags&FLAG_INTERFACE) {
1148 if(state->cls->init->header)
1149 syntaxerror("interface can not have class-level code");
1151 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1152 code_t*c = method_header(state->cls->init);
1153 m->body->code = wrap_function(c, 0, m->body->code);
1156 if(state->cls->static_init) {
1157 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1158 code_t*c = method_header(state->cls->static_init);
1159 m->body->code = wrap_function(c, 0, m->body->code);
1162 trait_list_t*trait = state->cls->abc->traits;
1163 /* switch all protected members to the protected ns of this class */
1165 trait_t*t = trait->trait;
1166 if(t->name->ns->access == ACCESS_PROTECTED) {
1167 if(!state->cls->abc->protectedNS) {
1168 char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
1169 state->cls->abc->protectedNS = namespace_new_protected(n);
1170 state->cls->abc->flags |= CLASS_PROTECTED_NS;
1172 t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
1174 trait = trait->next;
1181 void check_code_for_break(code_t*c)
1184 if(c->opcode == OPCODE___BREAK__) {
1185 char*name = string_cstr(c->data[0]);
1186 syntaxerror("Unresolved \"break %s\"", name);
1188 if(c->opcode == OPCODE___CONTINUE__) {
1189 char*name = string_cstr(c->data[0]);
1190 syntaxerror("Unresolved \"continue %s\"", name);
1192 if(c->opcode == OPCODE___RETHROW__) {
1193 syntaxerror("Unresolved \"rethrow\"");
1195 if(c->opcode == OPCODE___FALLTHROUGH__) {
1196 syntaxerror("Unresolved \"fallthrough\"");
1198 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1199 char*name = string_cstr(c->data[0]);
1200 syntaxerror("Can't reference a package (%s) as such", name);
1206 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1208 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1209 if(TYPE_IS_NUMBER(t)) {
1210 xassert(c->type == CONSTANT_FLOAT
1211 || c->type == CONSTANT_INT
1212 || c->type == CONSTANT_UINT);
1213 } else if(TYPE_IS_UINT(t)) {
1214 xassert(c->type == CONSTANT_UINT ||
1215 (c->type == CONSTANT_INT && c->i>=0));
1216 } else if(TYPE_IS_INT(t)) {
1217 xassert(c->type == CONSTANT_INT);
1218 } else if(TYPE_IS_BOOLEAN(t)) {
1219 xassert(c->type == CONSTANT_TRUE
1220 || c->type == CONSTANT_FALSE);
1224 static void check_override(memberinfo_t*m, int flags)
1228 if(m->parent == state->cls->info)
1229 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1231 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1232 if(m->access==ACCESS_PRIVATE)
1234 if(m->flags & FLAG_FINAL)
1235 syntaxerror("can't override final member %s", m->name);
1237 /* allow this. it's no issue.
1238 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1239 syntaxerror("can't override static member %s", m->name);*/
1241 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1242 syntaxerror("can't override non-static member %s with static declaration", m->name);
1244 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1245 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1246 if(m->kind == INFOTYPE_METHOD)
1247 syntaxerror("can't override without explicit 'override' declaration");
1249 syntaxerror("can't override '%s'", m->name);
1254 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1256 methodinfo_t*minfo = 0;
1257 namespace_t ns = modifiers2access(mod);
1260 minfo = methodinfo_register_global(ns.access, state->package, name);
1261 minfo->return_type = return_type;
1262 } else if(getset != KW_GET && getset != KW_SET) {
1264 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1266 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1268 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1269 minfo->return_type = return_type;
1270 // getslot on a member slot only returns "undefined", so no need
1271 // to actually store these
1272 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1274 //class getter/setter
1275 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1277 if(getset == KW_GET) {
1279 } else if(params->list && params->list->param && !params->list->next) {
1280 type = params->list->param->type;
1282 syntaxerror("setter function needs to take exactly one argument");
1283 // not sure wether to look into superclasses here, too
1284 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1286 if(minfo->kind!=INFOTYPE_VAR)
1287 syntaxerror("class already contains a method called '%s'", name);
1288 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1289 syntaxerror("class already contains a field called '%s'", name);
1290 if(minfo->subtype & gs)
1291 syntaxerror("getter/setter for '%s' already defined", name);
1292 /* make a setter or getter into a getset */
1293 minfo->subtype |= gs;
1296 FIXME: this check needs to be done in pass 2
1298 if((!minfo->return_type != !type) ||
1299 (minfo->return_type && type &&
1300 !strcmp(minfo->return_type->name, type->name))) {
1301 syntaxerror("different type in getter and setter: %s and %s",
1302 minfo->return_type?minfo->return_type->name:"*",
1303 type?type->name:"*");
1306 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1307 minfo->kind = INFOTYPE_VAR; //hack
1308 minfo->subtype = gs;
1309 minfo->return_type = type;
1312 /* can't assign a slot as getter and setter might have different slots */
1313 //minfo->slot = slot;
1315 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1316 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1317 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1322 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1324 //parserassert(state->method && state->method->info);
1326 methodstate_t*parent_method = state->method;
1329 return_type = 0; // not valid in pass 1
1333 state->new_vars = 1;
1334 state->allvars = dict_new();
1337 state->method = rfx_calloc(sizeof(methodstate_t));
1338 state->method->inner = 1;
1339 state->method->is_static = parent_method->is_static;
1340 state->method->variable_count = 0;
1341 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1343 NEW(methodinfo_t,minfo);
1344 minfo->kind = INFOTYPE_METHOD;
1345 minfo->access = ACCESS_PACKAGEINTERNAL;
1347 state->method->info = minfo;
1350 list_append(parent_method->innerfunctions, state->method);
1352 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1354 function_initvars(state->method, 1, params, 0, 1);
1358 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1359 state->method->variable_count = 0;
1360 parserassert(state->method);
1362 state->method->info->return_type = return_type;
1363 function_initvars(state->method, 1, params, 0, 1);
1367 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1368 params_t*params, classinfo_t*return_type)
1370 if(state->method && state->method->info) {
1371 syntaxerror("not able to start another method scope");
1374 state->new_vars = 1;
1375 state->allvars = dict_new();
1378 state->method = rfx_calloc(sizeof(methodstate_t));
1379 state->method->has_super = 0;
1380 state->method->is_static = mod->flags&FLAG_STATIC;
1383 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1385 state->method->is_global = 1;
1386 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1388 if(state->method->is_constructor)
1389 name = "__as3_constructor__";
1391 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1393 function_initvars(state->method, 1, params, mod->flags, 1);
1395 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1399 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1400 state->method->variable_count = 0;
1401 parserassert(state->method);
1404 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1405 check_override(m, mod->flags);
1409 state->cls->has_constructor |= state->method->is_constructor;
1412 function_initvars(state->method, 1, params, mod->flags, 1);
1416 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1417 params_t*params, classinfo_t*return_type, code_t*body)
1420 innerfunctions2vars(state->method);
1422 methodstate_list_t*ml = state->method->innerfunctions;
1424 dict_t*xvars = dict_new();
1426 if(state->method->unresolved_variables) {
1427 DICT_ITERATE_KEY(state->method->unresolved_variables, char*, vname) {
1428 if(dict_contains(state->allvars, vname)) {
1429 state->method->no_variable_scoping = 1;
1430 as3_warning("function %s uses forward or outer block variable references (%s): switching into compatiblity mode", name, vname);
1437 methodstate_t*m = ml->methodstate;
1438 parserassert(m->inner);
1439 if(m->unresolved_variables) {
1440 dict_t*d = m->unresolved_variables;
1442 DICT_ITERATE_KEY(d, char*, id) {
1443 /* check parent method's variables */
1445 if((v=find_variable(state, id))) {
1446 m->uses_parent_function = 1;
1447 state->method->uses_slots = 1;
1448 dict_put(xvars, id, 0);
1451 dict_destroy(m->unresolved_variables);
1452 m->unresolved_variables = 0;
1457 if(state->method->uses_slots) {
1458 state->method->slots = dict_new();
1460 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1461 if(!name) syntaxerror("internal error");
1462 if(v->index && dict_contains(xvars, name)) {
1463 v->init = v->kill = 0;
1465 if(v->is_inner_method) {
1466 v->is_inner_method->is_a_slot = i;
1469 dict_put(state->method->slots, name, v);
1472 state->method->uses_slots = i;
1473 dict_destroy(state->vars);state->vars = 0;
1474 parserassert(state->new_vars);
1475 dict_destroy(state->allvars);state->allvars = 0;
1482 /*if(state->method->uses_parent_function){
1483 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1488 multiname_t*type2 = sig2mname(return_type);
1490 if(state->method->inner) {
1491 f = state->method->abc;
1492 abc_method_init(f, global->file, type2, 1);
1493 } else if(state->method->is_constructor) {
1494 f = abc_class_getconstructor(state->cls->abc, type2);
1495 } else if(!state->method->is_global) {
1496 namespace_t ns = modifiers2access(mod);
1497 multiname_t mname = {QNAME, &ns, 0, name};
1498 if(mod->flags&FLAG_STATIC)
1499 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1501 f = abc_class_method(state->cls->abc, type2, &mname);
1502 slot = f->trait->slot_id;
1504 namespace_t mname_ns = {state->method->info->access, state->package};
1505 multiname_t mname = {QNAME, &mname_ns, 0, name};
1507 f = abc_method_new(global->file, type2, 1);
1508 if(!global->init) global->init = abc_initscript(global->file);
1509 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1510 //abc_code_t*c = global->init->method->body->code;
1512 //flash doesn't seem to allow us to access function slots
1513 //state->method->info->slot = slot;
1515 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1516 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1517 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1518 if(params->varargs) f->flags |= METHOD_NEED_REST;
1519 if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
1523 for(p=params->list;p;p=p->next) {
1524 if(params->varargs && !p->next) {
1525 break; //varargs: omit last parameter in function signature
1527 multiname_t*m = sig2mname(p->param->type);
1528 list_append(f->parameters, m);
1529 if(p->param->value) {
1530 check_constant_against_type(p->param->type, p->param->value);
1531 opt=1;list_append(f->optional_parameters, p->param->value);
1533 syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
1536 if(state->method->slots) {
1537 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1539 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1540 multiname_t*type = sig2mname(v->type);
1541 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1542 t->slot_id = v->index;
1547 check_code_for_break(body);
1549 /* Seems this works now.
1550 if(state->method->exceptions && state->method->uses_slots) {
1551 as3_warning("try/catch and activation not supported yet within the same method");
1555 f->body->code = body;
1556 f->body->exceptions = state->method->exceptions;
1557 } else { //interface
1559 syntaxerror("interface methods can't have a method body");
1569 void breakjumpsto(code_t*c, char*name, code_t*jump)
1572 if(c->opcode == OPCODE___BREAK__) {
1573 string_t*name2 = c->data[0];
1574 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1575 c->opcode = OPCODE_JUMP;
1582 void continuejumpsto(code_t*c, char*name, code_t*jump)
1585 if(c->opcode == OPCODE___CONTINUE__) {
1586 string_t*name2 = c->data[0];
1587 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1588 c->opcode = OPCODE_JUMP;
1596 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1601 return abc_coerce_a(c);
1605 // cast an "any" type to a specific type. subject to
1606 // runtime exceptions
1607 return abc_coerce2(c, &m);
1610 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1611 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1612 // allow conversion between number types
1613 if(TYPE_IS_UINT(to))
1614 return abc_convert_u(c);
1615 else if(TYPE_IS_INT(to))
1616 return abc_convert_i(c);
1617 else if(TYPE_IS_NUMBER(to))
1618 return abc_convert_d(c);
1619 return abc_coerce2(c, &m);
1622 if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
1625 if(TYPE_IS_BOOLEAN(to))
1626 return abc_convert_b(c);
1627 if(TYPE_IS_STRING(to))
1628 return abc_convert_s(c);
1629 if(TYPE_IS_OBJECT(to))
1630 return abc_coerce2(c, &m);
1631 if(TYPE_IS_OBJECT(from) && TYPE_IS_XMLLIST(to))
1632 return abc_coerce2(c, &m);
1633 if(TYPE_IS_OBJECT(from) && TYPE_IS_ARRAY(to))
1634 return abc_coerce2(c, &m);
1636 classinfo_t*supertype = from;
1638 if(supertype == to) {
1639 /* target type is one of from's superclasses.
1640 (not sure we need this coerce - as far as the verifier
1641 is concerned, object==object (i think) */
1642 return abc_coerce2(c, &m);
1645 while(supertype->interfaces[t]) {
1646 if(supertype->interfaces[t]==to) {
1647 // target type is one of from's interfaces
1648 return abc_coerce2(c, &m);
1652 supertype = supertype->superclass;
1654 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1656 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1658 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1661 as3_error("can't convert type %s%s%s to %s%s%s",
1662 from->package, from->package[0]?".":"", from->name,
1663 to->package, to->package[0]?".":"", to->name);
1667 code_t* coerce_to_type(code_t*c, classinfo_t*t)
1670 return abc_coerce_a(c);
1671 } else if(TYPE_IS_STRING(t)) {
1672 return abc_coerce_s(c);
1675 return abc_coerce2(c, &m);
1679 char is_pushundefined(code_t*c)
1681 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1684 static const char* get_package_from_name(const char*name)
1686 /* try explicit imports */
1687 dictentry_t* e = dict_get_slot(state->imports, name);
1689 if(!strcmp(e->key, name)) {
1690 slotinfo_t*c = (slotinfo_t*)e->data;
1691 if(c) return c->package;
1697 static namespace_list_t*get_current_imports()
1699 namespace_list_t*searchlist = 0;
1701 list_append(searchlist, namespace_new_package(state->package));
1703 import_list_t*l = state->wildcard_imports;
1705 namespace_t*ns = namespace_new_package(l->import->package);
1706 list_append(searchlist, ns);
1709 list_append(searchlist, namespace_new_package(""));
1710 list_append(searchlist, namespace_new_package(internal_filename_package));
1714 static slotinfo_t* find_class(const char*name)
1718 c = registry_find(state->package, name);
1721 /* try explicit imports */
1722 dictentry_t* e = dict_get_slot(state->imports, name);
1725 if(!strcmp(e->key, name)) {
1726 c = (slotinfo_t*)e->data;
1732 /* try package.* imports */
1733 import_list_t*l = state->wildcard_imports;
1735 //printf("does package %s contain a class %s?\n", l->import->package, name);
1736 c = registry_find(l->import->package, name);
1741 /* try global package */
1742 c = registry_find("", name);
1745 /* try local "filename" package */
1746 c = registry_find(internal_filename_package, name);
1751 typedcode_t push_class(slotinfo_t*a)
1756 if(a->access == ACCESS_PACKAGEINTERNAL &&
1757 strcmp(a->package, state->package) &&
1758 strcmp(a->package, internal_filename_package)
1760 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1761 infotypename(a), a->name, a->package, state->package);
1765 if(a->kind != INFOTYPE_CLASS) {
1767 x.c = abc_findpropstrict2(x.c, &m);
1768 x.c = abc_getproperty2(x.c, &m);
1769 if(a->kind == INFOTYPE_METHOD) {
1770 methodinfo_t*f = (methodinfo_t*)a;
1771 x.t = TYPE_FUNCTION(f);
1773 varinfo_t*v = (varinfo_t*)a;
1778 if(state->cls && state->method == state->cls->static_init) {
1779 /* we're in the static initializer.
1780 record the fact that we're using this class here */
1781 parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
1783 classinfo_t*c = (classinfo_t*)a;
1785 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1786 x.c = abc_getglobalscope(x.c);
1787 x.c = abc_getslot(x.c, c->slot);
1790 x.c = abc_getlex2(x.c, &m);
1792 x.t = TYPE_CLASS(c);
1798 char is_break_or_jump(code_t*c)
1802 if(c->opcode == OPCODE_JUMP ||
1803 c->opcode == OPCODE___BREAK__ ||
1804 c->opcode == OPCODE___CONTINUE__ ||
1805 c->opcode == OPCODE_THROW ||
1806 c->opcode == OPCODE_RETURNVOID ||
1807 c->opcode == OPCODE_RETURNVALUE) {
1813 #define IS_FINALLY_TARGET(op) \
1814 ((op) == OPCODE___CONTINUE__ || \
1815 (op) == OPCODE___BREAK__ || \
1816 (op) == OPCODE_RETURNVOID || \
1817 (op) == OPCODE_RETURNVALUE || \
1818 (op) == OPCODE___RETHROW__)
1820 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1822 #define NEED_EXTRA_STACK_ARG
1823 code_t*finally_label = abc_nop(0);
1824 NEW(lookupswitch_t, l);
1830 code_t*prev = i->prev;
1831 if(IS_FINALLY_TARGET(i->opcode)) {
1834 if(i->opcode == OPCODE___RETHROW__ ||
1835 i->opcode == OPCODE_RETURNVALUE) {
1836 if(i->opcode == OPCODE___RETHROW__)
1837 i->opcode = OPCODE_THROW;
1839 p = abc_coerce_a(p);
1840 p = abc_setlocal(p, tempvar);
1842 p = abc_pushbyte(p, count++);
1843 p = abc_jump(p, finally_label);
1844 code_t*target = p = abc_label(p);
1845 #ifdef NEED_EXTRA_STACK_ARG
1849 p = abc_getlocal(p, tempvar);
1852 p->next = i;i->prev = p;
1853 list_append(l->targets, target);
1859 c = abc_pushbyte(c, -1);
1860 c = code_append(c, finally_label);
1861 c = code_append(c, finally);
1863 #ifdef NEED_EXTRA_STACK_ARG
1866 c = abc_lookupswitch(c, l);
1867 c = l->def = abc_label(c);
1868 #ifdef NEED_EXTRA_STACK_ARG
1875 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1879 code_t*prev = i->prev;
1880 if(IS_FINALLY_TARGET(i->opcode)) {
1881 if(i->opcode == OPCODE___RETHROW__)
1882 i->opcode = OPCODE_THROW;
1883 code_t*end = code_dup(finally);
1884 code_t*start = code_start(end);
1885 if(prev) prev->next = start;
1892 return code_append(c, finally);
1895 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1901 int num_insertion_points=0;
1903 if(IS_FINALLY_TARGET(i->opcode))
1904 num_insertion_points++;
1911 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1916 int simple_version_cost = (1+num_insertion_points)*code_size;
1917 int lookup_version_cost = 4*num_insertion_points + 5;
1919 if(cantdup || simple_version_cost > lookup_version_cost) {
1920 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1921 return insert_finally_lookup(c, finally, tempvar);
1923 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1924 return insert_finally_simple(c, finally, tempvar);
1928 #define PASS1 }} if(as3_pass == 1) {{
1929 #define PASS1END }} if(as3_pass == 2) {{
1930 #define PASS2 }} if(as3_pass == 2) {{
1931 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1932 #define PASS12END }} if(as3_pass == 2) {{
1933 #define PASS_ALWAYS }} {{
1939 /* ------------ code blocks / statements ---------------- */
1941 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1943 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1944 PROGRAM_CODE_LIST: PROGRAM_CODE
1945 | PROGRAM_CODE_LIST PROGRAM_CODE
1947 PROGRAM_CODE: PACKAGE_DECLARATION
1948 | INTERFACE_DECLARATION
1950 | FUNCTION_DECLARATION
1953 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1956 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1957 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1958 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1960 INPACKAGE_CODE: INTERFACE_DECLARATION
1962 | FUNCTION_DECLARATION
1965 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1966 | '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
1969 MAYBECODE: CODE {$$=$1;}
1970 MAYBECODE: {$$=code_new();}
1972 CODE: CODE CODEPIECE {
1973 $$=code_append($1,$2);
1975 CODE: CODEPIECE {$$=$1;}
1977 // code which may appear outside of methods
1978 CODE_STATEMENT: DEFAULT_NAMESPACE
1979 CODE_STATEMENT: IMPORT
1981 CODE_STATEMENT: FOR_IN
1982 CODE_STATEMENT: WHILE
1983 CODE_STATEMENT: DO_WHILE
1984 CODE_STATEMENT: SWITCH
1986 CODE_STATEMENT: WITH
1988 CODE_STATEMENT: VOIDEXPRESSION
1989 CODE_STATEMENT: USE_NAMESPACE
1990 CODE_STATEMENT: NAMESPACE_DECLARATION
1991 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1992 CODE_STATEMENT: '{' '}' {$$=0;}
1994 // code which may appear in methods (includes the above)
1995 CODEPIECE: ';' {$$=0;}
1996 CODEPIECE: CODE_STATEMENT
1997 CODEPIECE: VARIABLE_DECLARATION
2002 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
2012 //CODEBLOCK : '{' CODE '}' {$$=$2;}
2013 //CODEBLOCK : '{' '}' {$$=0;}
2014 CODEBLOCK : CODEPIECE ';' {$$=$1;}
2015 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
2017 /* ------------ package init code ------------------- */
2019 PACKAGE_INITCODE: CODE_STATEMENT {
2022 global->init = abc_initscript(global->file);
2023 code_t**cc = &global->init->method->body->code;
2024 *cc = code_append(*cc, $1);
2028 /* ------------ embed code ------------- */
2030 EMBED_START: %prec above_function {
2036 /* ------------ conditional compilation ------------- */
2038 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
2041 char*key = concat3($1,"::",$3);
2042 if(!definitions || !dict_contains(definitions, key)) {
2048 /* ------------ variables --------------------------- */
2051 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
2055 char do_init_variable(char*name)
2057 if(!state->method->no_variable_scoping)
2059 if(!state->new_vars)
2065 MAYBEEXPRESSION : '=' E {$$=$2;}
2066 | {$$=mkdummynode();}
2068 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2069 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2071 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2072 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2074 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2077 if(variable_exists($1))
2078 syntaxerror("Variable %s already defined", $1);
2080 new_variable($1, 0, 1, 0);
2086 if(state->method->uses_slots) {
2087 v = find_slot(state, $1);
2089 // this variable is stored in a slot
2096 v = new_variable2($1, $2, 1, 0);
2099 $$ = slot?abc_getscopeobject(0, 1):0;
2101 typedcode_t val = node_read($3);
2102 if(!is_subtype_of(val.t, $2)) {
2103 syntaxerror("Can't convert %s to %s", val.t->name, $2->name);
2106 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2107 $$ = code_append($$, val.c);
2108 $$ = converttype($$, val.t, $2);
2111 $$ = defaultvalue($$, $2);
2114 if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
2115 $$ = code_append($$, val.c);
2116 $$ = abc_coerce_a($$);
2118 // don't do anything
2126 $$ = abc_setslot($$, v->index);
2128 $$ = abc_setlocal($$, v->index);
2129 v->init = do_init_variable($1);
2133 /* ------------ control flow ------------------------- */
2135 IF_CODEBLOCK: {PASS12 new_state();} CODEBLOCK {
2136 $$ = var_block($2, state->vars);
2139 MAYBEELSE: %prec below_else {$$ = code_new();}
2140 MAYBEELSE: "else" IF_CODEBLOCK {$$=$2;}
2141 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2143 IF : "if" '(' EXPRESSION ')' IF_CODEBLOCK MAYBEELSE {
2145 $$ = code_append($$, $3.c);
2146 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2148 $$ = code_append($$, $5);
2150 myjmp = $$ = abc_jump($$, 0);
2152 myif->branch = $$ = abc_nop($$);
2154 $$ = code_append($$, $6);
2155 myjmp->branch = $$ = abc_nop($$);
2159 FOR_INIT : {$$=code_new();}
2160 FOR_INIT : VARIABLE_DECLARATION
2161 FOR_INIT : VOIDEXPRESSION
2163 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2164 // (I don't see any easy way to revolve this conflict otherwise, as we
2165 // can't touch VAR_READ without upsetting the precedence about "return")
2166 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2167 PASS1 $$=$2;new_variable($2,0,1,0);
2168 PASS2 $$=$2;new_variable($2,$3,1,0);
2170 FOR_IN_INIT : T_IDENTIFIER {
2175 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2176 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2178 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' IF_CODEBLOCK {
2179 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2181 $$ = code_append($$, $2);
2182 code_t*loopstart = $$ = abc_label($$);
2183 $$ = code_append($$, $4.c);
2184 code_t*myif = $$ = abc_iffalse($$, 0);
2185 $$ = code_append($$, $8);
2186 code_t*cont = $$ = abc_nop($$);
2187 $$ = code_append($$, $6);
2188 $$ = abc_jump($$, loopstart);
2189 code_t*out = $$ = abc_nop($$);
2190 breakjumpsto($$, $1.name, out);
2191 continuejumpsto($$, $1.name, cont);
2194 $$ = var_block($$, state->vars);
2198 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' IF_CODEBLOCK {
2199 variable_t*var = find_variable(state, $2);
2201 syntaxerror("variable %s not known in this scope", $2);
2203 int it = alloc_local();
2204 int array = alloc_local();
2207 $$ = code_append($$, $4.c);
2208 $$ = abc_coerce_a($$);
2209 $$ = abc_setlocal($$, array);
2210 $$ = abc_pushbyte($$, 0);
2211 $$ = abc_setlocal($$, it);
2213 code_t*loopstart = $$ = abc_label($$);
2215 $$ = abc_hasnext2($$, array, it);
2216 code_t*myif = $$ = abc_iffalse($$, 0);
2217 $$ = abc_getlocal($$, array);
2218 $$ = abc_getlocal($$, it);
2220 $$ = abc_nextname($$);
2222 $$ = abc_nextvalue($$);
2223 $$ = converttype($$, 0, var->type);
2224 $$ = abc_setlocal($$, var->index);
2226 $$ = code_append($$, $6);
2227 $$ = abc_jump($$, loopstart);
2229 code_t*out = $$ = abc_nop($$);
2230 breakjumpsto($$, $1.name, out);
2231 continuejumpsto($$, $1.name, loopstart);
2235 $$ = abc_kill($$, it);
2236 $$ = abc_kill($$, array);
2241 WHILE : T_WHILE '(' EXPRESSION ')' IF_CODEBLOCK {
2245 code_t*myjmp = $$ = abc_jump($$, 0);
2246 code_t*loopstart = $$ = abc_label($$);
2247 $$ = code_append($$, $5);
2248 code_t*cont = $$ = abc_nop($$);
2249 myjmp->branch = cont;
2250 $$ = code_append($$, $3.c);
2251 $$ = abc_iftrue($$, loopstart);
2252 code_t*out = $$ = abc_nop($$);
2253 breakjumpsto($$, $1, out);
2254 continuejumpsto($$, $1, cont);
2257 DO_WHILE : T_DO IF_CODEBLOCK "while" '(' EXPRESSION ')' {
2259 code_t*loopstart = $$ = abc_label($$);
2260 $$ = code_append($$, $2);
2261 code_t*cont = $$ = abc_nop($$);
2262 $$ = code_append($$, $5.c);
2263 $$ = abc_iftrue($$, loopstart);
2264 code_t*out = $$ = abc_nop($$);
2265 breakjumpsto($$, $1, out);
2266 continuejumpsto($$, $1, cont);
2269 BREAK : "break" %prec prec_none {
2270 $$ = abc___break__(0, "");
2272 BREAK : "break" T_IDENTIFIER {
2273 $$ = abc___break__(0, $2);
2275 CONTINUE : "continue" %prec prec_none {
2276 $$ = abc___continue__(0, "");
2278 CONTINUE : "continue" T_IDENTIFIER {
2279 $$ = abc___continue__(0, $2);
2282 MAYBE_CASE_LIST : {$$=0;}
2283 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2284 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2285 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2286 CASE_LIST: CASE {$$=$1;}
2287 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2289 CASE: "case" E ':' MAYBECODE {
2290 $$ = abc_getlocal(0, state->switch_var);
2291 $$ = code_append($$, node_read($2).c);
2292 code_t*j = $$ = abc_ifne($$, 0);
2293 $$ = code_append($$, $4);
2294 if($$->opcode != OPCODE___BREAK__) {
2295 $$ = abc___fallthrough__($$, "");
2297 code_t*e = $$ = abc_nop($$);
2300 DEFAULT: "default" ':' MAYBECODE {
2303 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2304 $$ = node_read($4).c;
2305 $$ = abc_setlocal($$, state->switch_var);
2306 $$ = code_append($$, $7);
2308 code_t*out = $$ = abc_kill($$, state->switch_var);
2309 breakjumpsto($$, $1, out);
2311 code_t*c = $$,*lastblock=0;
2313 if(c->opcode == OPCODE_IFNE) {
2314 if(!c->next) syntaxerror("internal error in fallthrough handling");
2316 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2318 c->opcode = OPCODE_JUMP;
2319 c->branch = lastblock;
2321 /* fall through end of switch */
2322 c->opcode = OPCODE_NOP;
2328 $$ = var_block($$, state->vars);
2332 /* ------------ try / catch /finally ---------------- */
2334 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2335 state->exception_name=$3;
2336 PASS1 new_variable($3, 0, 0, 0);
2337 PASS2 new_variable($3, $4, 0, 0);
2340 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2341 multiname_t name = {QNAME, &name_ns, 0, $3};
2343 NEW(abc_exception_t, e)
2344 e->exc_type = sig2mname($4);
2345 e->var_name = multiname_clone(&name);
2349 int i = find_variable_safe(state, $3)->index;
2350 e->target = c = abc_nop(0);
2351 c = abc_setlocal(c, i);
2352 c = code_append(c, code_dup(state->method->scope_code));
2353 c = code_append(c, $8);
2356 c = var_block(c, state->vars);
2359 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2360 $4 = var_block($4, state->vars);
2364 NEW(abc_exception_t, e)
2365 e->exc_type = 0; //all exceptions
2366 e->var_name = 0; //no name
2369 e->to = code_append(e->to, $4);
2375 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2376 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2377 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2378 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2382 list_append($$.l,$2);
2383 $$.finally = $2->to;$2->to=0;
2386 CATCH_FINALLY_LIST: FINALLY {
2390 list_append($$.l,$1);
2391 $$.finally = $1->to;$1->to=0;
2395 TRY : "try" '{' {PASS12 new_state();
2396 state->method->has_exceptions=1;
2397 state->method->late_binding=1;//for invariant scope_code
2398 } MAYBECODE '}' CATCH_FINALLY_LIST {
2399 code_t*out = abc_nop(0);
2401 code_t*start = abc_nop(0);
2402 $$ = code_append(start, $4);
2403 if(!is_break_or_jump($4)) {
2404 $$ = abc_jump($$, out);
2406 code_t*end = $$ = abc_nop($$);
2410 tmp = alloc_local();
2412 abc_exception_list_t*l = $6.l;
2415 abc_exception_t*e = l->abc_exception;
2417 $$ = code_append($$, e->target);
2418 $$ = abc_jump($$, out);
2420 parserassert((ptroff_t)$6.finally);
2422 e->target = $$ = abc_nop($$);
2423 $$ = code_append($$, code_dup(state->method->scope_code));
2424 $$ = abc___rethrow__($$);
2432 $$ = code_append($$, out);
2434 $$ = insert_finally($$, $6.finally, tmp);
2436 list_concat(state->method->exceptions, $6.l);
2438 $$ = var_block($$, state->vars);
2442 /* ------------ throw ------------------------------- */
2444 THROW : "throw" EXPRESSION {
2448 THROW : "throw" %prec prec_none {
2449 if(!state->exception_name)
2450 syntaxerror("re-throw only possible within a catch block");
2451 variable_t*v = find_variable(state, state->exception_name);
2453 $$=abc_getlocal($$, v->index);
2457 /* ------------ with -------------------------------- */
2459 WITH_HEAD : "with" '(' EXPRESSION ')' {
2461 if(state->method->has_exceptions) {
2462 int v = alloc_local();
2463 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2464 state->method->scope_code = abc_pushwith(state->method->scope_code);
2469 WITH : WITH_HEAD CODEBLOCK {
2470 /* remove getlocal;pushwith from scope code again */
2471 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2474 if(state->method->has_exceptions) {
2476 $$ = abc_setlocal($$, $1.number);
2478 $$ = abc_pushwith($$);
2479 $$ = code_append($$, $2);
2480 $$ = abc_popscope($$);
2484 /* ------------ packages and imports ---------------- */
2486 X_IDENTIFIER: T_IDENTIFIER
2487 | "package" {PASS12 $$="package";}
2488 | "namespace" {PASS12 $$="namespace";}
2489 | "NaN" {PASS12 $$="NaN";}
2490 | T_NAMESPACE {PASS12 $$=$1;}
2492 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2493 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2495 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2496 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2497 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2498 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2501 static void state_has_imports()
2503 state->wildcard_imports = list_clone(state->wildcard_imports);
2504 state->imports = dict_clone(state->imports);
2505 state->has_own_imports = 1;
2507 static void import_toplevel(const char*package)
2509 char* s = strdup(package);
2511 dict_put(state->import_toplevel_packages, s, 0);
2512 char*x = strrchr(s, '.');
2521 IMPORT : "import" T_IDENTIFIER {
2523 slotinfo_t*s = registry_find(state->package, $2);
2524 if(!s && as3_pass==1) {as3_schedule_class(state->package, $2);}
2525 state_has_imports();
2526 dict_put(state->imports, state->package, $2);
2529 IMPORT : "import" PACKAGEANDCLASS {
2531 slotinfo_t*s = registry_find($2->package, $2->name);
2532 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2533 as3_schedule_class($2->package, $2->name);
2535 state_has_imports();
2536 dict_put(state->imports, $2->name, $2);
2537 import_toplevel($2->package);
2540 IMPORT : "import" PACKAGE '.' '*' {
2542 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2543 as3_schedule_package($2);
2548 state_has_imports();
2549 list_append(state->wildcard_imports, i);
2550 import_toplevel(i->package);
2554 /* ------------ classes and interfaces (header) -------------- */
2556 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2557 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2558 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2559 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2561 $$.flags=$1.flags|$2.flags;
2562 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2563 $$.ns=$1.ns?$1.ns:$2.ns;
2566 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2567 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2568 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2569 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2570 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2571 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2572 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2573 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2574 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2575 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2579 EXTENDS : {PASS12 $$=0;}
2580 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2582 EXTENDS_LIST : {PASS12 $$=list_new();}
2583 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2585 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2586 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2588 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2589 EXTENDS IMPLEMENTS_LIST
2590 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2592 '}' {PASS12 endclass();$$=0;}
2594 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2596 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2597 startclass(&$1,$3,0,$4);}
2598 MAYBE_INTERFACE_BODY
2599 '}' {PASS12 endclass();$$=0;}
2601 /* ------------ classes and interfaces (body) -------------- */
2604 MAYBE_CLASS_BODY : CLASS_BODY
2605 CLASS_BODY : CLASS_BODY_ITEM
2606 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2607 CLASS_BODY_ITEM : ';'
2608 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2609 CLASS_BODY_ITEM : SLOT_DECLARATION
2610 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2612 CLASS_BODY_ITEM : CODE_STATEMENT {
2613 code_t*c = state->cls->static_init->header;
2614 c = code_append(c, $1);
2615 state->cls->static_init->header = c;
2618 MAYBE_INTERFACE_BODY :
2619 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2620 INTERFACE_BODY : IDECLARATION
2621 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2623 IDECLARATION : "var" T_IDENTIFIER {
2624 syntaxerror("variable declarations not allowed in interfaces");
2626 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2628 $1.flags |= FLAG_PUBLIC;
2629 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2630 syntaxerror("invalid method modifiers: interface methods always need to be public");
2632 startfunction(&$1,$3,$4,&$6,$8);
2633 endfunction(&$1,$3,$4,&$6,$8, 0);
2634 list_deep_free($6.list);
2637 /* ------------ classes and interfaces (body, slots ) ------- */
2640 static int slotstate_varconst = 0;
2641 static modifiers_t*slotstate_flags = 0;
2642 static void setslotstate(modifiers_t* flags, int varconst)
2644 slotstate_varconst = varconst;
2645 slotstate_flags = flags;
2648 if(flags->flags&FLAG_STATIC) {
2649 state->method = state->cls->static_init;
2651 state->method = state->cls->init;
2654 // reset to "default" state (all in class code is static by default) */
2655 state->method = state->cls->static_init;
2658 parserassert(state->method);
2661 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2663 int flags = modifiers->flags;
2664 namespace_t ns = modifiers2access(modifiers);
2667 multiname_t mname = {QNAME, &ns, 0, name};
2669 trait_list_t**traits;
2673 if(!global->init) global->init = abc_initscript(global->file);
2674 ns.name = state->package;
2675 traits = &global->init->traits;
2676 code = &global->init->method->body->code;
2677 } else if(flags&FLAG_STATIC) {
2679 traits = &state->cls->abc->static_traits;
2680 code = &state->cls->static_init->header;
2682 // instance variable
2683 traits = &state->cls->abc->traits;
2684 code = &state->cls->init->header;
2686 if(ns.access == ACCESS_PROTECTED) {
2687 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2693 *m = *multiname_clone(&mname);
2695 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2699 VARCONST: "var" | "const"
2701 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2703 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2704 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2706 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2709 int flags = slotstate_flags->flags;
2710 namespace_t ns = modifiers2access(slotstate_flags);
2714 varinfo_t* info = 0;
2716 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2718 check_override(i, flags);
2720 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2722 slotinfo_t*i = registry_find(state->package, $1);
2724 syntaxerror("package %s already contains '%s'", state->package, $1);
2726 if(ns.name && ns.name[0]) {
2727 syntaxerror("namespaces not allowed on package-level variables");
2729 info = varinfo_register_global(ns.access, state->package, $1);
2733 info->flags = flags;
2735 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2739 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2743 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2747 t->type_name = multiname_clone(&m);
2749 info->slot = t->slot_id;
2751 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2752 FIXME: is there a way to use slots and still don't have conflicting overrides?
2754 info->slot = t->slot_id = 0;
2756 constant_t cval = $3->type->eval($3);
2757 if(cval.type!=CONSTANT_UNKNOWN) {
2758 /* compile time constant */
2759 t->value = malloc(sizeof(constant_t));
2760 memcpy(t->value, &cval, sizeof(constant_t));
2761 info->value = constant_clone(t->value);
2763 typedcode_t v = node_read($3);
2764 /* initalization code (if needed) */
2766 if(v.c && !is_pushundefined(v.c)) {
2767 c = abc_getlocal_0(c);
2768 c = code_append(c, v.c);
2769 c = converttype(c, v.t, $2);
2771 c = abc_initproperty2(c, &mname);
2773 c = abc_setslot(c, t->slot_id);
2776 *code = code_append(*code, c);
2779 if(slotstate_varconst==KW_CONST) {
2780 t->kind= TRAIT_CONST;
2781 info->flags |= FLAG_CONST;
2788 /* ------------ constants -------------------------------------- */
2790 MAYBECONSTANT: {$$=0;}
2791 MAYBECONSTANT: '=' E {
2792 $$ = malloc(sizeof(constant_t));
2793 *$$ = node_eval($2);
2794 if($$->type == CONSTANT_UNKNOWN) {
2795 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2799 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2800 CONSTANT : T_INT {$$ = constant_new_int($1);}
2802 $$ = constant_new_uint($1);
2804 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2805 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2806 CONSTANT : "true" {$$ = constant_new_true($1);}
2807 CONSTANT : "false" {$$ = constant_new_false($1);}
2808 CONSTANT : "null" {$$ = constant_new_null($1);}
2809 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2810 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2812 /*CONSTANT : T_NAMESPACE {
2814 $$ = constant_new_namespace(namespace_new_namespace($1.url));
2817 /* ---------------------------xml ------------------------------ */
2820 static int xml_level = 0;
2824 multiname_t m = {QNAME, &stdns, 0, "XML"};
2827 v.c = abc_getlex2(v.c, &m);
2828 v.c = code_append(v.c, node_read($1).c);
2829 v.c = abc_construct(v.c, 1);
2834 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2835 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2836 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2838 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2841 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2844 XMLTEXT : {$$=mkstringnode("");}
2845 XMLTEXT : XMLTEXT XMLEXPR1 {
2846 $$ = mkaddnode($1,$2);
2848 XMLTEXT : XMLTEXT T_STRING {
2849 char* str = string_cstr(&$2);
2850 $$ = mkaddnode($1,mkstringnode(str));
2853 XMLTEXT : XMLTEXT '>' {
2854 $$ = mkaddnode($1, mkstringnode(">"));
2856 XML2 : XMLNODE XMLTEXT {
2857 $$ = mkaddnode($1,$2);
2859 XML2 : XML2 XMLNODE XMLTEXT {
2860 $$ = mkaddnode($1, mkaddnode($2,$3));
2862 XML_ID_OR_EXPR: T_IDENTIFIER {
2863 $$ = mkstringnode($1);
2865 XML_ID_OR_EXPR: XMLEXPR2 {
2869 MAYBE_XMLATTRIBUTES: {
2870 $$ = mkstringnode("");
2872 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {
2873 $$ = mkaddnode(mkstringnode(" "),$1);
2876 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2877 //$$ = allocprintf("<%s%s/>", $2, $3, $5, $8);
2878 $$ = mkaddnode(mkaddnode(mkaddnode(mkstringnode("<"),$2),$3),mkstringnode("/>"));
2880 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2881 //$$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2882 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2883 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),mkstringnode("</")),$8),mkstringnode(">"));
2885 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2886 //$$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2887 $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
2888 mkstringnode("<"),$2),$3),mkstringnode(">")),$5),$6),mkstringnode("</")),$9),mkstringnode(">"));
2891 XMLATTRIBUTES: XMLATTRIBUTE {
2894 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {
2895 $$ = mkaddnode($1, mkaddnode(mkstringnode(" "),$2));
2897 XMLATTRIBUTE: XMLEXPR2 {
2900 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2901 char* str = string_cstr(&$3);
2902 $$ = mkaddnode($1, mkstringnode(concat2("=",str)));
2905 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2906 $$ = mkaddnode($1, mkaddnode(mkstringnode("=\""), mkaddnode($3, mkstringnode("\""))));
2908 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2909 $$ = mkaddnode(mkaddnode(mkstringnode(concat2($1,"=\"")), $3), mkstringnode("\""));
2911 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2912 char* str = string_cstr(&$3);
2913 $$=mkstringnode(allocprintf("%s=%s", $1,str));
2915 free($1);free((char*)$3.str);
2918 /* ------------ classes and interfaces (body, functions) ------- */
2920 // non-vararg version
2923 memset(&$$,0,sizeof($$));
2925 MAYBE_PARAM_LIST: PARAM_LIST {
2931 MAYBE_PARAM_LIST: "..." PARAM {
2933 memset(&$$,0,sizeof($$));
2935 list_append($$.list, $2);
2937 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2941 list_append($$.list, $4);
2945 PARAM_LIST: PARAM_LIST ',' PARAM {
2948 list_append($$.list, $3);
2952 memset(&$$,0,sizeof($$));
2953 list_append($$.list, $1);
2956 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2958 $$ = rfx_calloc(sizeof(param_t));
2964 PARAM: T_IDENTIFIER MAYBECONSTANT {
2966 $$ = rfx_calloc(sizeof(param_t));
2968 $$->type = TYPE_ANY;
2976 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2977 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2980 endfunction(&$1,$3,$4,&$6,0,0);
2982 if(!state->method->info) syntaxerror("internal error");
2984 code_t*c = method_header(state->method);
2985 c = wrap_function(c, 0, $11);
2987 endfunction(&$1,$3,$4,&$6,$8,c);
2989 list_deep_free($6.list);
2993 MAYBE_IDENTIFIER: T_IDENTIFIER
2994 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2995 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2996 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2999 endfunction(0,0,$2,&$4,0,0);
3001 methodinfo_t*f = state->method->info;
3002 if(!f || !f->kind) syntaxerror("internal error");
3004 code_t*c = method_header(state->method);
3005 c = wrap_function(c, 0, $9);
3007 int index = state->method->var_index;
3008 endfunction(0,0,$2,&$4,$6,c);
3010 $$.c = abc_getlocal(0, index);
3011 $$.t = TYPE_FUNCTION(f);
3013 PASS12 list_deep_free($4.list);
3017 /* ------------- package + class ids --------------- */
3019 CLASS: X_IDENTIFIER {
3020 PASS1 NEW(unresolvedinfo_t,c);
3021 memset(c, 0, sizeof(*c));
3022 c->kind = INFOTYPE_UNRESOLVED;
3024 c->package = get_package_from_name($1);
3026 c->nsset = get_current_imports();
3027 /* make the compiler look for this class in the current directory,
3029 as3_schedule_class_noerror(state->package, $1);
3031 $$ = (classinfo_t*)c;
3033 slotinfo_t*s = find_class($1);
3034 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
3035 $$ = (classinfo_t*)s;
3038 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
3039 PASS1 NEW(unresolvedinfo_t,c);
3040 memset(c, 0, sizeof(*c));
3041 c->kind = INFOTYPE_UNRESOLVED;
3044 $$ = (classinfo_t*)c;
3046 slotinfo_t*s = registry_find($1, $3);
3047 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
3049 $$ = (classinfo_t*)s;
3052 CLASS_SPEC: PACKAGEANDCLASS
3055 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
3056 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
3058 TYPE : CLASS_SPEC {PASS12 $$=$1;}
3059 | '*' {PASS12 $$=TYPE_ANY;}
3060 | "void" {PASS12 $$=TYPE_VOID;}
3062 | "String" {$$=registry_getstringclass();}
3063 | "int" {$$=registry_getintclass();}
3064 | "uint" {$$=registry_getuintclass();}
3065 | "Boolean" {$$=registry_getbooleanclass();}
3066 | "Number" {$$=registry_getnumberclass();}
3069 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
3070 MAYBETYPE: {PASS12 $$=0;}
3072 /* ----------function calls, delete, constructor calls ------ */
3074 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3075 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3077 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3078 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3079 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3081 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3085 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3086 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3087 $$.number= $1.number+1;
3088 $$.cc = code_append($1.cc, $2.c);
3092 NEW : "new" E XX MAYBE_PARAM_VALUES {
3093 typedcode_t v = node_read($2);
3095 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3097 code_t*paramcode = $4.cc;
3098 if($$.c->opcode == OPCODE_GETPROPERTY) {
3099 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3100 $$.c = code_cutlast($$.c);
3101 $$.c = code_append($$.c, paramcode);
3102 $$.c = abc_constructprop2($$.c, name, $4.number);
3103 multiname_destroy(name);
3104 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3106 classinfo_t*c = v.t->data;
3108 $$.c = abc_findpropstrict2(0, &m);
3109 $$.c = code_append($$.c, paramcode);
3110 $$.c = abc_constructprop2($$.c, &m, $4.number);
3111 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3112 int slot = (int)(ptroff_t)$$.c->data[0];
3113 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3114 multiname_t*name = t->name;
3115 $$.c = code_cutlast($$.c);
3116 $$.c = code_append($$.c, paramcode);
3117 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3119 $$.c = code_append($$.c, paramcode);
3120 $$.c = abc_construct($$.c, $4.number);
3124 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3127 $$.c = abc_coerce_a($$.c);
3132 /* TODO: use abc_call (for calling local variables),
3133 abc_callstatic (for calling own methods)
3136 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3138 typedcode_t v = node_read($1);
3140 if($$.c->opcode == OPCODE_COERCE_A) {
3141 $$.c = code_cutlast($$.c);
3143 code_t*paramcode = $3.cc;
3146 if($$.c->opcode == OPCODE_GETPROPERTY) {
3147 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3148 $$.c = code_cutlast($$.c);
3149 $$.c = code_append($$.c, paramcode);
3150 $$.c = abc_callproperty2($$.c, name, $3.number);
3151 multiname_destroy(name);
3152 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3153 int slot = (int)(ptroff_t)$$.c->data[0];
3154 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3155 if(t->kind!=TRAIT_METHOD) {
3156 //ok: flash allows to assign closures to members.
3158 multiname_t*name = t->name;
3159 $$.c = code_cutlast($$.c);
3160 $$.c = code_append($$.c, paramcode);
3161 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3162 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3163 } else if($$.c->opcode == OPCODE_GETSUPER) {
3164 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3165 $$.c = code_cutlast($$.c);
3166 $$.c = code_append($$.c, paramcode);
3167 $$.c = abc_callsuper2($$.c, name, $3.number);
3168 multiname_destroy(name);
3170 $$.c = abc_getglobalscope($$.c);
3171 $$.c = code_append($$.c, paramcode);
3172 $$.c = abc_call($$.c, $3.number);
3175 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3176 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3177 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3178 // calling a class is like a typecast
3179 $$.t = (classinfo_t*)v.t->data;
3182 $$.c = abc_coerce_a($$.c);
3186 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3187 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3188 if(!state->method) syntaxerror("super() not allowed outside of a function");
3189 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3192 $$.c = abc_getlocal_0($$.c);
3194 $$.c = code_append($$.c, $3.cc);
3196 this is dependent on the control path, check this somewhere else
3197 if(state->method->has_super)
3198 syntaxerror("constructor may call super() only once");
3200 state->method->has_super = 1;
3202 $$.c = abc_constructsuper($$.c, $3.number);
3203 $$.c = abc_pushundefined($$.c);
3207 DELETE: "delete" E {
3208 typedcode_t v = node_read($2);
3210 if($$.c->opcode == OPCODE_COERCE_A) {
3211 $$.c = code_cutlast($$.c);
3213 multiname_t*name = 0;
3214 if($$.c->opcode == OPCODE_GETPROPERTY) {
3215 $$.c->opcode = OPCODE_DELETEPROPERTY;
3216 } else if($$.c->opcode == OPCODE_GETSLOT) {
3217 int slot = (int)(ptroff_t)$$.c->data[0];
3218 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3219 $$.c = code_cutlast($$.c);
3220 $$.c = abc_deleteproperty2($$.c, name);
3222 $$.c = abc_getlocal_0($$.c);
3223 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3224 $$.c = abc_deleteproperty2($$.c, &m);
3226 $$.t = TYPE_BOOLEAN;
3229 RETURN: "return" %prec prec_none {
3230 $$ = abc_returnvoid(0);
3232 RETURN: "return" EXPRESSION {
3234 $$ = abc_returnvalue($$);
3237 // ----------------------- expression types -------------------------------------
3239 NONCOMMAEXPRESSION : E %prec below_lt {
3242 EXPRESSION : COMMA_EXPRESSION {
3245 COMMA_EXPRESSION : E %prec below_lt {
3246 $$ = mkmultinode(&node_comma, $1);
3248 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3249 $$ = multinode_extend($1, $3);
3251 VOIDEXPRESSION : E %prec below_minus {
3254 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3256 $$ = code_append($$, node_exec($3));
3259 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3260 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3262 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3263 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3264 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3265 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3266 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3268 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3270 $$.cc = code_append($$.cc, $1);
3271 $$.cc = code_append($$.cc, $3.c);
3274 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3276 $$.number = $1.number+2;
3277 $$.cc = code_append($$.cc, $3);
3278 $$.cc = code_append($$.cc, $5.c);
3281 // ----------------------- expression evaluation -------------------------------------
3283 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3284 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3285 E : NEW {$$ = mkcodenode($1);}
3286 E : DELETE {$$ = mkcodenode($1);}
3287 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3288 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3291 $$ = mkconstnode($1);
3302 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3304 v.c = abc_getlex2(v.c, &m);
3305 v.c = abc_pushstring(v.c, $1.pattern);
3306 v.c = abc_construct(v.c, 1);
3308 v.c = abc_getlex2(v.c, &m);
3309 v.c = abc_pushstring(v.c, $1.pattern);
3310 v.c = abc_pushstring(v.c, $1.options);
3311 v.c = abc_construct(v.c, 2);
3319 state->method->need_arguments = 1;
3322 v.c = abc_getlocal(0, state->method->need_arguments);
3328 E : '[' MAYBE_EXPRESSION_LIST ']' {
3331 v.c = code_append(v.c, $2.cc);
3332 v.c = abc_newarray(v.c, $2.number);
3333 v.t = registry_getarrayclass();
3338 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3341 v.c = code_append(v.c, $2.cc);
3342 v.c = abc_newobject(v.c, $2.number/2);
3343 v.t = registry_getobjectclass();
3347 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3348 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3349 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3350 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3351 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3352 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3353 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3354 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3355 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3356 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3357 E : '!' E {$$ = mknode1(&node_not, $2);}
3358 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3359 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3360 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3361 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3362 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3363 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3364 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3365 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3366 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3367 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3368 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3369 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3370 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3371 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3372 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3373 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3374 E : "typeof" E {$$ = mknode1(&node_typeof, $2);}
3375 E : "void" E {$$ = mknode1(&node_void, $2);}
3376 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3377 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3378 E : '-' E {$$ = mknode1(&node_neg, $2);}
3379 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3380 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3381 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3382 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3383 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3384 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3385 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3386 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3387 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3388 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3389 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3390 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3391 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3392 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3394 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3395 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3396 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3397 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3399 E : "super" '.' T_IDENTIFIER
3400 { if(!state->cls->info)
3401 syntaxerror("super keyword not allowed outside a class");
3402 classinfo_t*t = state->cls->info->superclass;
3403 if(!t) t = TYPE_OBJECT;
3404 memberinfo_t*f = findmember_nsset(t, $3, 1);
3405 MEMBER_MULTINAME(m, f, $3);
3408 v.c = abc_getlocal_0(v.c);
3409 v.c = abc_getsuper2(v.c, &m);
3410 v.t = slotinfo_gettype((slotinfo_t*)f);
3414 E : '@' T_IDENTIFIER {
3416 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3417 v.c = abc_getlex2(0, &m);
3422 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3425 typedcode_t v = node_read($1);
3426 typedcode_t w = node_read($5);
3428 int index = alloc_local();
3429 int result = alloc_local();
3430 int tmp = alloc_local();
3431 int xml = alloc_local();
3433 c = code_append(c, v.c);
3434 c = abc_checkfilter(c);
3435 c = abc_coerce_a(c); //hasnext2 converts to *
3436 c = abc_setlocal(c, xml);
3437 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3438 c = abc_getlex2(c, &m);
3439 c = abc_construct(c, 0);
3440 c = abc_setlocal(c, result);
3441 c = abc_pushbyte(c, 0);
3442 c = abc_setlocal(c, index);
3443 code_t*jmp = c = abc_jump(c, 0);
3444 code_t*loop = c = abc_label(c);
3445 c = abc_getlocal(c, xml);
3446 c = abc_getlocal(c, index);
3447 c = abc_nextvalue(c);
3449 c = abc_setlocal(c, tmp);
3450 c = abc_pushwith(c);
3451 c = code_append(c, w.c);
3452 c = abc_popscope(c);
3453 code_t*b = c = abc_iffalse(c, 0);
3454 c = abc_getlocal(c, result);
3455 c = abc_getlocal(c, index);
3456 c = abc_getlocal(c, tmp);
3457 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3458 c = abc_setproperty2(c, &m2);
3459 c = b->branch = jmp->branch = abc_nop(c);
3460 c = abc_kill(c, tmp);
3461 c = abc_hasnext2(c, xml, index);
3462 c = abc_iftrue(c, loop);
3463 c = abc_getlocal(c, result);
3464 c = abc_kill(c, xml);
3465 c = abc_kill(c, result);
3466 c = abc_kill(c, index);
3468 c = var_block(c, state->vars);
3476 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3477 ID_OR_NS : '*' {$$="*";}
3478 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3479 SUBNODE: X_IDENTIFIER
3483 MAYBE_NS: T_IDENTIFIER "::" {$$=$1;}
3484 | T_NAMESPACE "::" {$$=(char*)$1;}
3485 | '*' "::" {$$="*";}
3488 E : E '.' ID_OR_NS "::" SUBNODE {
3489 typedcode_t v = node_read($1);
3490 typedcode_t w = node_read(resolve_identifier($3));
3491 v.c = code_append(v.c, w.c);
3492 if(!TYPE_IS_NAMESPACE(w.t)) {
3493 as3_softwarning("%s might not be a namespace", $3);
3495 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3496 multiname_t m = {RTQNAME, 0, 0, $5};
3497 v.c = abc_getproperty2(v.c, &m);
3498 if(TYPE_IS_XML(v.t)) {
3501 v.c = abc_coerce_a(v.c);
3506 E : E ".." SUBNODE {
3507 typedcode_t v = node_read($1);
3508 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3509 v.c = abc_getdescendants2(v.c, &m);
3513 E : E '.' '[' E ']' {
3514 typedcode_t v = node_read($1);
3515 typedcode_t w = node_read($4);
3516 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3517 v.c = code_append(v.c, w.c);
3518 v.c = converttype(w.c, w.t, TYPE_STRING);
3519 v.c = abc_getproperty2(v.c, &m);
3524 E : E '.' '@' SUBNODE {
3525 typedcode_t v = node_read($1);
3526 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3527 v.c = abc_getproperty2(v.c, &m);
3531 E : E ".." '@' SUBNODE {
3532 typedcode_t v = node_read($1);
3533 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3534 v.c = abc_getdescendants2(v.c, &m);
3538 E : E '.' '@' '[' E ']' {
3539 typedcode_t v = node_read($1);
3540 typedcode_t w = node_read($5);
3541 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3542 v.c = code_append(v.c, w.c);
3543 v.c = converttype(w.c, w.t, TYPE_STRING);
3544 v.c = abc_getproperty2(v.c, &m);
3548 E : E ".." '@' '[' E ']' {
3549 typedcode_t v = node_read($1);
3550 typedcode_t w = node_read($5);
3551 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3552 v.c = code_append(v.c, w.c);
3553 v.c = converttype(w.c, w.t, TYPE_STRING);
3554 v.c = abc_getdescendants2(v.c, &m);
3559 MEMBER : E '.' SUBNODE {
3560 typedcode_t v1 = node_read($1);
3562 classinfo_t*t = v1.t;
3564 if(TYPE_IS_CLASS(t) && t->data) {
3568 if(TYPE_IS_XML(t)) {
3569 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3570 $$.c = abc_getproperty2($$.c, &m);
3571 $$.c = abc_coerce_a($$.c);
3572 $$.t = TYPE_XMLLIST;
3574 if(t->subtype==INFOTYPE_UNRESOLVED) {
3575 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3577 memberinfo_t*f = findmember_nsset(t, $3, 1);
3579 if(f && !is_static != !(f->flags&FLAG_STATIC))
3581 if(f && f->slot && !noslot) {
3582 $$.c = abc_getslot($$.c, f->slot);
3585 if(!TYPE_IS_XMLLIST(t)) {
3586 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3589 MEMBER_MULTINAME(m, f, $3);
3590 $$.c = abc_getproperty2($$.c, &m);
3592 /* determine type */
3593 $$.t = slotinfo_gettype((slotinfo_t*)f);
3595 $$.c = abc_coerce_a($$.c);
3597 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3598 string_t*package = v1.c->data[0];
3599 char*package2 = concat3(package->str, ".", $3);
3601 slotinfo_t*a = registry_find(package->str, $3);
3604 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3605 registry_ispackage(package2)) {
3607 $$.c->data[0] = string_new4(package2);
3610 syntaxerror("couldn't resolve %s", package2);
3613 /* when resolving a property on an unknown type, we do know the
3614 name of the property (and don't seem to need the package), but
3615 we need to make avm2 try out all access modes */
3616 as3_softwarning("Resolving %s on unknown type", $3);
3617 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3618 $$.c = abc_getproperty2($$.c, &m);
3619 $$.c = abc_coerce_a($$.c);
3625 node_t* resolve_identifier(char*name)
3635 /* look at variables */
3636 if((v = find_variable(state, name))) {
3637 // name is a local variable
3638 o.c = abc_getlocal(o.c, v->index);
3640 return mkcodenode(o);
3642 if((v = find_slot(state, name))) {
3643 o.c = abc_getscopeobject(o.c, 1);
3644 o.c = abc_getslot(o.c, v->index);
3646 return mkcodenode(o);
3649 int i_am_static = state->method->is_static;
3651 /* look at current class' members */
3652 if(!state->method->inner &&
3653 !state->xmlfilter &&
3655 (f = findmember_nsset(state->cls->info, name, 1)))
3657 // name is a member or attribute in this class
3658 int var_is_static = (f->flags&FLAG_STATIC);
3660 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3661 /* if the variable is a constant (and we know what is evaluates to), we
3662 can just use the value itself */
3663 varinfo_t*v = (varinfo_t*)f;
3665 return mkconstnode(v->value);
3669 if(var_is_static >= i_am_static) {
3670 if(f->kind == INFOTYPE_METHOD) {
3671 o.t = TYPE_FUNCTION(f);
3676 if(var_is_static && !i_am_static) {
3677 /* access to a static member from a non-static location.
3678 do this via findpropstrict:
3679 there doesn't seem to be any non-lookup way to access
3680 static properties of a class */
3681 state->method->late_binding = 1;
3683 namespace_t ns = {f->access, f->package};
3684 multiname_t m = {QNAME, &ns, 0, name};
3685 o.c = abc_findpropstrict2(o.c, &m);
3686 o.c = abc_getproperty2(o.c, &m);
3687 return mkcodenode(o);
3688 } else if(f->slot>0) {
3689 o.c = abc_getlocal_0(o.c);
3690 o.c = abc_getslot(o.c, f->slot);
3691 return mkcodenode(o);
3693 MEMBER_MULTINAME(m, f, name);
3694 o.c = abc_getlocal_0(o.c);
3695 o.c = abc_getproperty2(o.c, &m);
3696 return mkcodenode(o);
3701 /* look at actual classes, in the current package and imported */
3702 if(!state->xmlfilter && (a = find_class(name))) {
3703 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3704 o.c = abc_getlocal_0(0);
3705 o.t = TYPE_CLASS((classinfo_t*)a);
3709 return mkcodenode(o);
3712 /* look through package prefixes */
3713 if(!state->xmlfilter &&
3714 (dict_contains(state->import_toplevel_packages, name) ||
3715 registry_ispackage(name))) {
3716 o.c = abc___pushpackage__(o.c, name);
3718 return mkcodenode(o); //?
3721 /* unknown object, let the avm2 resolve it */
3723 if(!state->method->inner && !state->xmlfilter) {
3724 /* we really should make inner functions aware of the class context */
3725 as3_warning("Couldn't resolve '%s', doing late binding", name);
3727 state->method->late_binding = 1;
3729 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3732 o.c = abc_findpropstrict2(o.c, &m);
3733 o.c = abc_getproperty2(o.c, &m);
3734 return mkcodenode(o);
3739 VAR_READ : T_IDENTIFIER {
3741 /* Queue unresolved identifiers for checking against the parent
3742 function's variables.
3743 We consider everything which is not a local variable "unresolved".
3744 This encompasses class names, members of the surrounding class
3745 etc. which is *correct* because local variables of the parent function
3749 if(!find_variable(state, $1)) {
3750 unknown_variable($1);
3751 /* let the compiler know that it might want to check the current directory/package
3752 for this identifier- maybe there's a file $1.as defining $1. */
3753 as3_schedule_class_noerror(state->package, $1);
3759 $$ = resolve_identifier($1);
3762 // ----------------- namespaces -------------------------------------------------
3765 void add_active_url(const char*url)
3769 list_append(state->active_namespace_urls, n);
3773 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3775 NEW(namespace_decl_t,n);
3780 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3782 NEW(namespace_decl_t,n);
3787 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3789 NEW(namespace_decl_t,n);
3794 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3796 trie_put(active_namespaces, $2->name, (void*)$2->url);
3798 namespace_t access = modifiers2access(&$1);
3799 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3800 var->type = TYPE_NAMESPACE;
3802 ns.access = ACCESS_NAMESPACE;
3804 var->value = constant_new_namespace(&ns);
3807 MULTINAME(m, TYPE_NAMESPACE);
3808 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3809 t->value = var->value;
3810 t->type_name = multiname_clone(&m);
3816 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3818 as3_warning("default xml namespaces not supported yet");
3822 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3824 const char*url = $3->name;
3826 varinfo_t*s = (varinfo_t*)$3;
3827 if(s->kind == INFOTYPE_UNRESOLVED) {
3828 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3830 syntaxerror("Couldn't resolve namespace %s", $3->name);
3833 if(!s || s->kind != INFOTYPE_VAR)
3834 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3835 if(!s->value || !NS_TYPE(s->value->type))
3836 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3837 url = s->value->ns->name;
3839 trie_put(active_namespaces, $3->name, (void*)url);
3840 add_active_url(url);