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
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 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 <id> XML XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT XML_ID_OR_EXPR XMLEXPR1 XMLEXPR2
221 %type <classinfo> TYPE
222 //%type <token> VARIABLE
225 //%type <token> T_IDENTIFIER
226 %type <value> FUNCTIONCALL
227 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES
228 %type <value_list> MAYBE_DICT_EXPRPAIR_LIST DICT_EXPRPAIR_LIST WITH_HEAD
231 // precedence: from low to high
235 %left below_semicolon
238 %nonassoc below_assignment // for ?:, contrary to spec
239 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
246 %nonassoc "==" "!=" "===" "!=="
247 %nonassoc "is" "as" "in"
249 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
250 %left "<<" ">>" ">>>"
254 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
256 %nonassoc below_curly
260 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
262 %left T_IDENTIFIER "arguments"
263 %left above_identifier
267 // needed for "return" precedence:
268 %nonassoc T_STRING T_REGEXP
269 %nonassoc T_INT T_UINT T_FLOAT KW_NAN
270 %nonassoc "false" "true" "null" "undefined" "super" "function"
277 static int a3_error(char*s)
279 syntaxerror("%s", s);
280 return 0; //make gcc happy
283 static void parsererror(const char*file, int line, const char*f)
285 syntaxerror("internal error in %s, %s:%d", f, file, line);
288 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
291 static char* concat2(const char* t1, const char* t2)
295 char*text = malloc(l1+l2+1);
296 memcpy(text , t1, l1);
297 memcpy(text+l1, t2, l2);
301 static char* concat3(const char* t1, const char* t2, const char* t3)
306 char*text = malloc(l1+l2+l3+1);
307 memcpy(text , t1, l1);
308 memcpy(text+l1, t2, l2);
309 memcpy(text+l1+l2, t3, l3);
314 typedef struct _import {
317 DECLARE_LIST(import);
319 DECLARE(methodstate);
320 DECLARE_LIST(methodstate);
322 typedef struct _classstate {
328 methodstate_t*static_init;
330 //code_t*static_init;
331 parsedclass_t*dependencies;
333 char has_constructor;
336 struct _methodstate {
347 dict_t*unresolved_variables;
350 char uses_parent_function;
358 int var_index; // for inner methods
359 int slot_index; // for inner methods
360 char is_a_slot; // for inner methods
365 abc_exception_list_t*exceptions;
367 methodstate_list_t*innerfunctions;
370 typedef struct _state {
375 import_list_t*wildcard_imports;
376 dict_t*import_toplevel_packages;
379 namespace_list_t*active_namespace_urls;
381 char has_own_imports;
382 char new_vars; // e.g. transition between two functions
383 char xmlfilter; // are we inside a xmlobj..() filter?
386 methodstate_t*method;
393 dict_t*allvars; // also contains variables from sublevels
396 typedef struct _global {
399 parsedclass_list_t*classes;
400 abc_script_t*classinit;
402 abc_script_t*init; //package-level code
405 dict_t*file2token2info;
408 static global_t*global = 0;
409 static state_t* state = 0;
413 /* protected handling here is a big hack: we just assume the protectedns
414 is package:class. the correct approach would be to add the proper
415 namespace to all protected members in the registry, even though that
416 would slow down searching */
417 #define MEMBER_MULTINAME(m,f,n) \
421 m##_ns.access = ((slotinfo_t*)(f))->access; \
422 if(m##_ns.access == ACCESS_NAMESPACE) \
423 m##_ns.name = ((slotinfo_t*)(f))->package; \
424 else if(m##_ns.access == ACCESS_PROTECTED && (f)->parent) \
425 m##_ns.name = concat3((f)->parent->package,":",(f)->parent->name); \
430 m.namespace_set = 0; \
431 m.name = ((slotinfo_t*)(f))->name; \
433 m.type = MULTINAME; \
435 m.namespace_set = &nopackage_namespace_set; \
439 /* warning: list length of namespace set is undefined */
440 #define MULTINAME_LATE(m, access, package) \
441 namespace_t m##_ns = {access, package}; \
442 namespace_set_t m##_nsset; \
443 namespace_list_t m##_l;m##_l.next = 0; \
444 m##_nsset.namespaces = &m##_l; \
445 m##_nsset = m##_nsset; \
446 m##_l.namespace = &m##_ns; \
447 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
449 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
450 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
451 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
452 static namespace_t stdns = {ACCESS_PACKAGE, ""};
453 static namespace_list_t nl4 = {&stdns,0};
454 static namespace_list_t nl3 = {&ns3,&nl4};
455 static namespace_list_t nl2 = {&ns2,&nl3};
456 static namespace_list_t nl1 = {&ns1,&nl2};
457 static namespace_set_t nopackage_namespace_set = {&nl1};
459 static dict_t*definitions=0;
460 void as3_set_define(const char*c)
463 definitions = dict_new();
464 if(!dict_contains(definitions,c))
465 dict_put(definitions,c,0);
468 static void new_state()
471 state_t*oldstate = state;
473 memcpy(s, state, sizeof(state_t)); //shallow copy
475 s->imports = dict_new();
477 if(!s->import_toplevel_packages) {
478 s->import_toplevel_packages = dict_new();
482 state->has_own_imports = 0;
483 state->vars = dict_new();
484 state->old = oldstate;
487 trie_remember(active_namespaces);
490 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
493 static void state_destroy(state_t*state)
495 if(state->has_own_imports) {
496 list_free(state->wildcard_imports);
497 dict_destroy(state->imports);state->imports=0;
499 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
500 dict_destroy(state->imports);state->imports=0;
503 dict_destroy(state->vars);state->vars=0;
505 if(state->new_vars && state->allvars) {
506 parserassert(!state->old || state->old->allvars != state->allvars);
507 DICT_ITERATE_DATA(state->allvars, void*, data) {
510 dict_destroy(state->allvars);
513 list_free(state->active_namespace_urls)
514 state->active_namespace_urls = 0;
519 static void old_state()
521 trie_rollback(active_namespaces);
523 if(!state || !state->old)
524 syntaxerror("invalid nesting");
525 state_t*leaving = state;
529 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
530 free(leaving->method);
533 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
538 state_destroy(leaving);
541 static code_t* method_header(methodstate_t*m);
542 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
543 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0);
546 static char* internal_filename_package = 0;
547 void initialize_file(char*filename)
550 syntaxerror("invalid call to initialize_file during parsing of another file");
553 active_namespaces = trie_new();
556 state->package = internal_filename_package = strdup(filename);
557 state->allvars = dict_new();
559 global->token2info = dict_lookup(global->file2token2info,
560 current_filename // use long version
562 if(!global->token2info) {
563 global->token2info = dict_new2(&ptr_type);
564 dict_put(global->file2token2info, current_filename, global->token2info);
568 state->method = rfx_calloc(sizeof(methodstate_t));
569 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
570 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
572 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
574 syntaxerror("internal error: skewed tokencount");
575 function_initvars(state->method, 0, 0, 0, 1);
582 if(!state || state->level!=1) {
583 syntaxerror("unexpected end of file in pass %d", as3_pass);
587 dict_del(global->file2token2info, current_filename);
588 code_t*header = method_header(state->method);
589 //if(global->init->method->body->code || global->init->traits) {
591 code_t*c = wrap_function(header, 0, global->init->method->body->code);
592 global->init->method->body->code = abc_returnvoid(c);
593 free(state->method);state->method=0;
597 //free(state->package);state->package=0; // used in registry
598 state_destroy(state);state=0;
601 void initialize_parser()
603 global = rfx_calloc(sizeof(global_t));
604 global->file = abc_file_new();
605 global->file->flags &= ~ABCFILE_LAZY;
606 global->file2token2info = dict_new();
607 global->token2info = 0;
608 global->classinit = abc_initscript(global->file);
611 void* finish_parser()
613 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
614 global->token2info=0;
616 initcode_add_classlist(global->classinit, global->classes);
621 typedef struct _variable {
626 methodstate_t*is_inner_method;
629 static variable_t* find_variable(state_t*s, char*name)
634 v = dict_lookup(s->vars, name);
636 if(s->new_vars) break;
639 return dict_lookup(top->allvars, name);
641 static variable_t* find_slot(state_t*s, const char*name)
643 if(s->method && s->method->slots)
644 return dict_lookup(s->method->slots, name);
648 static variable_t* find_variable_safe(state_t*s, char*name)
650 variable_t* v = find_variable(s, name);
652 syntaxerror("undefined variable: %s", name);
656 static char variable_exists(char*name)
658 return dict_contains(state->vars, name);
661 static code_t*defaultvalue(code_t*c, classinfo_t*type)
663 if(TYPE_IS_INT(type)) {
664 c = abc_pushbyte(c, 0);
665 } else if(TYPE_IS_UINT(type)) {
666 c = abc_pushuint(c, 0);
667 } else if(TYPE_IS_FLOAT(type)) {
669 } else if(TYPE_IS_BOOLEAN(type)) {
670 c = abc_pushfalse(c);
671 } else if(TYPE_IS_STRING(type)) {
675 //c = abc_pushundefined(c);
676 syntaxerror("internal error: can't generate default value for * type");
680 c = abc_coerce2(c, &m);
685 static int alloc_local()
687 return state->method->variable_count++;
690 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
693 variable_t*v = find_slot(state, name);
701 v->index = alloc_local();
706 dict_put(state->vars, name, v);
707 dict_put(state->allvars, name, v);
712 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
714 return new_variable2(name, type, init, maybeslot)->index;
717 #define TEMPVARNAME "__as3_temp__"
720 variable_t*v = find_variable(state, TEMPVARNAME);
725 i = new_variable(TEMPVARNAME, 0, 0, 0);
730 static code_t* var_block(code_t*body)
736 DICT_ITERATE_DATA(state->vars, variable_t*, v) {
737 if(v->type && v->init) {
738 c = defaultvalue(c, v->type);
739 c = abc_setlocal(c, v->index);
740 k = abc_kill(k, v->index);
748 if(x->opcode== OPCODE___BREAK__ ||
749 x->opcode== OPCODE___CONTINUE__) {
750 /* link kill code before break/continue */
751 code_t*e = code_dup(k);
752 code_t*s = code_start(e);
764 c = code_append(c, body);
765 c = code_append(c, k);
769 static void unknown_variable(char*name)
771 if(!state->method->unresolved_variables)
772 state->method->unresolved_variables = dict_new();
773 if(!dict_contains(state->method->unresolved_variables, name))
774 dict_put(state->method->unresolved_variables, name, 0);
777 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
779 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
780 c = abc_getlocal_0(c);
781 c = abc_pushscope(c);
784 /* FIXME: this alloc_local() causes variable indexes to be
785 different in pass2 than in pass1 */
786 if(!m->activation_var) {
787 m->activation_var = alloc_local();
790 c = abc_newactivation(c);
792 c = abc_pushscope(c);
793 c = abc_setlocal(c, m->activation_var);
795 c = abc_getlocal(c, m->activation_var);
796 c = abc_pushscope(c);
802 static code_t* method_header(methodstate_t*m)
806 c = add_scope_code(c, m, 1);
808 methodstate_list_t*l = m->innerfunctions;
810 parserassert(l->methodstate->abc);
811 if(m->uses_slots && l->methodstate->is_a_slot) {
812 c = abc_getscopeobject(c, 1);
813 c = abc_newfunction(c, l->methodstate->abc);
815 c = abc_setlocal(c, l->methodstate->var_index);
816 c = abc_setslot(c, l->methodstate->slot_index);
818 c = abc_newfunction(c, l->methodstate->abc);
819 c = abc_setlocal(c, l->methodstate->var_index);
821 free(l->methodstate);l->methodstate=0;
825 c = code_append(c, m->header);
828 if(m->is_constructor && !m->has_super) {
829 // call default constructor
830 c = abc_getlocal_0(c);
831 c = abc_constructsuper(c, 0);
835 /* all parameters that are used by inner functions
836 need to be copied from local to slot */
837 parserassert(m->activation_var);
838 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
839 if(v->is_parameter) {
840 c = abc_getlocal(c, m->activation_var);
841 c = abc_getlocal(c, v->index);
842 c = abc_setslot(c, v->index);
846 list_free(m->innerfunctions);
847 m->innerfunctions = 0;
852 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
854 c = code_append(c, header);
855 c = code_append(c, var_block(body));
856 /* append return if necessary */
857 if(!c || (c->opcode != OPCODE_RETURNVOID &&
858 c->opcode != OPCODE_RETURNVALUE)) {
859 c = abc_returnvoid(c);
864 static void startpackage(char*name)
867 state->package = strdup(name);
869 static void endpackage()
871 //used e.g. in classinfo_register:
872 //free(state->package);state->package=0;
876 #define FLAG_PUBLIC 256
877 #define FLAG_PROTECTED 512
878 #define FLAG_PRIVATE 1024
879 #define FLAG_PACKAGEINTERNAL 2048
880 #define FLAG_NAMESPACE 4096
882 static namespace_t modifiers2access(modifiers_t*mod)
887 if(mod->flags&FLAG_NAMESPACE) {
888 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
889 syntaxerror("invalid combination of access levels and namespaces");
890 ns.access = ACCESS_NAMESPACE;
892 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
894 /* shouldn't happen- the tokenizer only reports something as a namespace
895 if it was already registered */
896 trie_dump(active_namespaces);
897 syntaxerror("unknown namespace: %s", mod->ns);
900 } else if(mod->flags&FLAG_PUBLIC) {
901 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
902 syntaxerror("invalid combination of access levels");
903 ns.access = ACCESS_PACKAGE;
904 } else if(mod->flags&FLAG_PRIVATE) {
905 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
906 syntaxerror("invalid combination of access levels");
907 ns.access = ACCESS_PRIVATE;
908 } else if(mod->flags&FLAG_PROTECTED) {
909 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
910 syntaxerror("invalid combination of access levels");
911 ns.access = ACCESS_PROTECTED;
913 ns.access = ACCESS_PACKAGEINTERNAL;
917 static slotinfo_t* find_class(const char*name);
919 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
921 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
924 static void innerfunctions2vars(methodstate_t*m)
926 methodstate_list_t*l = m->innerfunctions;
928 methodstate_t*m = l->methodstate;
930 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 0);
931 m->var_index = v->index;
933 m->slot_index = m->is_a_slot;
934 v->is_inner_method = m;
939 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
944 index = new_variable("this", 0, 0, 0);
945 else if(!m->is_global)
946 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
948 index = new_variable("globalscope", 0, 0, 0);
949 parserassert(!index);
954 for(p=params->list;p;p=p->next) {
955 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
958 if(as3_pass==2 && m->need_arguments) {
959 /* arguments can never be used by an innerfunction (the inner functions
960 have their own arguments var), so it's ok to not initialize this until
961 pass 2. (We don't know whether we need it before, anyway) */
962 variable_t*v = new_variable2("arguments", TYPE_ARRAY, 0, 0);
963 m->need_arguments = v->index;
967 innerfunctions2vars(m);
970 m->scope_code = add_scope_code(m->scope_code, m, 0);
972 /* exchange unresolved identifiers with the actual objects */
973 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
974 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
975 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
976 if(!type || type->kind != INFOTYPE_CLASS) {
977 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
987 char*as3_globalclass=0;
988 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
991 syntaxerror("inner classes now allowed");
996 classinfo_list_t*mlist=0;
998 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
999 syntaxerror("invalid modifier(s)");
1001 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
1002 syntaxerror("public and internal not supported at the same time.");
1004 if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
1005 syntaxerror("protected and static not supported at the same time.");
1007 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1008 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1009 // all classes extend object
1010 extends = registry_getobjectclass();
1013 /* create the class name, together with the proper attributes */
1017 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
1018 access = ACCESS_PRIVATE; package = internal_filename_package;
1019 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
1020 access = ACCESS_PACKAGEINTERNAL; package = state->package;
1021 } else if(state->package!=internal_filename_package) {
1022 access = ACCESS_PACKAGE; package = state->package;
1024 syntaxerror("public classes only allowed inside a package");
1028 state->cls = rfx_calloc(sizeof(classstate_t));
1029 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1030 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1031 state->cls->static_init->is_static=FLAG_STATIC;
1032 state->cls->static_init->variable_count=1;
1033 /* notice: we make no effort to initialize the top variable (local0) here,
1034 even though it has special meaning. We just rely on the fact
1035 that pass 1 won't do anything with variables */
1037 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1039 /* set current method to constructor- all code within the class-level (except
1040 static variable initializations) will be executed during construction time */
1041 state->method = state->cls->init;
1043 if(registry_find(package, classname)) {
1044 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1046 /* build info struct */
1047 int num_interfaces = (list_length(implements));
1048 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1049 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1050 state->cls->info->superclass = extends;
1053 classinfo_list_t*l = implements;
1054 for(l=implements;l;l=l->next) {
1055 state->cls->info->interfaces[pos++] = l->classinfo;
1060 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1062 state->method = state->cls->init;
1063 parserassert(state->cls && state->cls->info);
1065 function_initvars(state->cls->init, 0, 0, 0, 1);
1066 function_initvars(state->cls->static_init, 0, 0, 0, 0);
1068 if(extends && (extends->flags & FLAG_FINAL))
1069 syntaxerror("Can't extend final class '%s'", extends->name);
1072 while(state->cls->info->interfaces[pos]) {
1073 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1074 syntaxerror("'%s' is not an interface",
1075 state->cls->info->interfaces[pos]->name);
1079 /* generate the abc code for this class */
1080 MULTINAME(classname2,state->cls->info);
1081 multiname_t*extends2 = sig2mname(extends);
1083 /* don't add the class to the class index just yet- that will be done later
1085 state->cls->abc = abc_class_new(0, &classname2, extends2);
1086 state->cls->abc->file = global->file;
1088 multiname_destroy(extends2);
1089 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1090 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1091 if(state->cls->info->flags&FLAG_INTERFACE) {
1092 abc_class_interface(state->cls->abc);
1095 for(mlist=implements;mlist;mlist=mlist->next) {
1096 MULTINAME(m, mlist->classinfo);
1097 abc_class_add_interface(state->cls->abc, &m);
1100 state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
1101 list_append(global->classes, state->cls->dependencies);
1103 /* flash.display.MovieClip handling */
1104 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1105 if(state->package && state->package[0]) {
1106 as3_globalclass = concat3(state->package, ".", classname);
1108 as3_globalclass = strdup(classname);
1114 static void endclass()
1117 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1119 c = abc_getlocal_0(c);
1120 c = abc_constructsuper(c, 0);
1121 state->cls->init->header = code_append(state->cls->init->header, c);
1122 state->cls->has_constructor=1;
1124 if(state->cls->init) {
1125 if(state->cls->info->flags&FLAG_INTERFACE) {
1126 if(state->cls->init->header)
1127 syntaxerror("interface can not have class-level code");
1129 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1130 code_t*c = method_header(state->cls->init);
1131 m->body->code = wrap_function(c, 0, m->body->code);
1134 if(state->cls->static_init) {
1135 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1136 code_t*c = method_header(state->cls->static_init);
1137 m->body->code = wrap_function(c, 0, m->body->code);
1140 trait_list_t*trait = state->cls->abc->traits;
1141 /* switch all protected members to the protected ns of this class */
1143 trait_t*t = trait->trait;
1144 if(t->name->ns->access == ACCESS_PROTECTED) {
1145 if(!state->cls->abc->protectedNS) {
1146 char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
1147 state->cls->abc->protectedNS = namespace_new_protected(n);
1148 state->cls->abc->flags |= CLASS_PROTECTED_NS;
1150 t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
1152 trait = trait->next;
1159 void check_code_for_break(code_t*c)
1162 if(c->opcode == OPCODE___BREAK__) {
1163 char*name = string_cstr(c->data[0]);
1164 syntaxerror("Unresolved \"break %s\"", name);
1166 if(c->opcode == OPCODE___CONTINUE__) {
1167 char*name = string_cstr(c->data[0]);
1168 syntaxerror("Unresolved \"continue %s\"", name);
1170 if(c->opcode == OPCODE___RETHROW__) {
1171 syntaxerror("Unresolved \"rethrow\"");
1173 if(c->opcode == OPCODE___FALLTHROUGH__) {
1174 syntaxerror("Unresolved \"fallthrough\"");
1176 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1177 char*name = string_cstr(c->data[0]);
1178 syntaxerror("Can't reference a package (%s) as such", name);
1184 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1186 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1187 if(TYPE_IS_NUMBER(t)) {
1188 xassert(c->type == CONSTANT_FLOAT
1189 || c->type == CONSTANT_INT
1190 || c->type == CONSTANT_UINT);
1191 } else if(TYPE_IS_UINT(t)) {
1192 xassert(c->type == CONSTANT_UINT ||
1193 (c->type == CONSTANT_INT && c->i>=0));
1194 } else if(TYPE_IS_INT(t)) {
1195 xassert(c->type == CONSTANT_INT);
1196 } else if(TYPE_IS_BOOLEAN(t)) {
1197 xassert(c->type == CONSTANT_TRUE
1198 || c->type == CONSTANT_FALSE);
1202 static void check_override(memberinfo_t*m, int flags)
1206 if(m->parent == state->cls->info)
1207 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1209 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1210 if(m->access==ACCESS_PRIVATE)
1212 if(m->flags & FLAG_FINAL)
1213 syntaxerror("can't override final member %s", m->name);
1215 /* allow this. it's no issue.
1216 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1217 syntaxerror("can't override static member %s", m->name);*/
1219 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1220 syntaxerror("can't override non-static member %s with static declaration", m->name);
1222 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1223 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1224 if(m->kind == INFOTYPE_METHOD)
1225 syntaxerror("can't override without explicit 'override' declaration");
1227 syntaxerror("can't override '%s'", m->name);
1232 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1234 methodinfo_t*minfo = 0;
1235 namespace_t ns = modifiers2access(mod);
1238 minfo = methodinfo_register_global(ns.access, state->package, name);
1239 minfo->return_type = return_type;
1240 } else if(getset != KW_GET && getset != KW_SET) {
1242 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1244 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1246 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1247 minfo->return_type = return_type;
1248 // getslot on a member slot only returns "undefined", so no need
1249 // to actually store these
1250 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1252 //class getter/setter
1253 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1255 if(getset == KW_GET) {
1257 } else if(params->list && params->list->param && !params->list->next) {
1258 type = params->list->param->type;
1260 syntaxerror("setter function needs to take exactly one argument");
1261 // not sure wether to look into superclasses here, too
1262 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1264 if(minfo->kind!=INFOTYPE_VAR)
1265 syntaxerror("class already contains a method called '%s'", name);
1266 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1267 syntaxerror("class already contains a field called '%s'", name);
1268 if(minfo->subtype & gs)
1269 syntaxerror("getter/setter for '%s' already defined", name);
1270 /* make a setter or getter into a getset */
1271 minfo->subtype |= gs;
1274 FIXME: this check needs to be done in pass 2
1276 if((!minfo->return_type != !type) ||
1277 (minfo->return_type && type &&
1278 !strcmp(minfo->return_type->name, type->name))) {
1279 syntaxerror("different type in getter and setter: %s and %s",
1280 minfo->return_type?minfo->return_type->name:"*",
1281 type?type->name:"*");
1284 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1285 minfo->kind = INFOTYPE_VAR; //hack
1286 minfo->subtype = gs;
1287 minfo->return_type = type;
1290 /* can't assign a slot as getter and setter might have different slots */
1291 //minfo->slot = slot;
1293 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1294 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1295 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1300 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1302 //parserassert(state->method && state->method->info);
1304 methodstate_t*parent_method = state->method;
1307 return_type = 0; // not valid in pass 1
1311 state->new_vars = 1;
1312 state->allvars = dict_new();
1315 state->method = rfx_calloc(sizeof(methodstate_t));
1316 state->method->inner = 1;
1317 state->method->is_static = parent_method->is_static;
1318 state->method->variable_count = 0;
1319 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1321 NEW(methodinfo_t,minfo);
1322 minfo->kind = INFOTYPE_METHOD;
1323 minfo->access = ACCESS_PACKAGEINTERNAL;
1325 state->method->info = minfo;
1328 list_append(parent_method->innerfunctions, state->method);
1330 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1332 function_initvars(state->method, 1, params, 0, 1);
1336 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1337 state->method->variable_count = 0;
1338 parserassert(state->method);
1340 state->method->info->return_type = return_type;
1341 function_initvars(state->method, 1, params, 0, 1);
1345 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1346 params_t*params, classinfo_t*return_type)
1348 if(state->method && state->method->info) {
1349 syntaxerror("not able to start another method scope");
1352 state->new_vars = 1;
1353 state->allvars = dict_new();
1356 state->method = rfx_calloc(sizeof(methodstate_t));
1357 state->method->has_super = 0;
1358 state->method->is_static = mod->flags&FLAG_STATIC;
1361 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1363 state->method->is_global = 1;
1364 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1366 if(state->method->is_constructor)
1367 name = "__as3_constructor__";
1369 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1371 function_initvars(state->method, 1, params, mod->flags, 1);
1373 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1377 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1378 state->method->variable_count = 0;
1379 parserassert(state->method);
1382 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1383 check_override(m, mod->flags);
1387 state->cls->has_constructor |= state->method->is_constructor;
1390 function_initvars(state->method, 1, params, mod->flags, 1);
1394 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1395 params_t*params, classinfo_t*return_type, code_t*body)
1398 innerfunctions2vars(state->method);
1400 methodstate_list_t*ml = state->method->innerfunctions;
1402 dict_t*xvars = dict_new();
1405 methodstate_t*m = ml->methodstate;
1406 parserassert(m->inner);
1407 if(m->unresolved_variables) {
1408 dict_t*d = m->unresolved_variables;
1410 DICT_ITERATE_KEY(d, char*, id) {
1411 /* check parent method's variables */
1413 if((v=find_variable(state, id))) {
1414 m->uses_parent_function = 1;
1415 state->method->uses_slots = 1;
1416 dict_put(xvars, id, 0);
1419 dict_destroy(m->unresolved_variables);m->unresolved_variables = 0;
1424 if(state->method->uses_slots) {
1425 state->method->slots = dict_new();
1427 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1428 if(!name) syntaxerror("internal error");
1429 if(v->index && dict_contains(xvars, name)) {
1432 if(v->is_inner_method) {
1433 v->is_inner_method->is_a_slot = i;
1436 dict_put(state->method->slots, name, v);
1439 state->method->uses_slots = i;
1440 dict_destroy(state->vars);state->vars = 0;
1441 parserassert(state->new_vars);
1442 dict_destroy(state->allvars);state->allvars = 0;
1449 /*if(state->method->uses_parent_function){
1450 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1455 multiname_t*type2 = sig2mname(return_type);
1457 if(state->method->inner) {
1458 f = state->method->abc;
1459 abc_method_init(f, global->file, type2, 1);
1460 } else if(state->method->is_constructor) {
1461 f = abc_class_getconstructor(state->cls->abc, type2);
1462 } else if(!state->method->is_global) {
1463 namespace_t ns = modifiers2access(mod);
1464 multiname_t mname = {QNAME, &ns, 0, name};
1465 if(mod->flags&FLAG_STATIC)
1466 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1468 f = abc_class_method(state->cls->abc, type2, &mname);
1469 slot = f->trait->slot_id;
1471 namespace_t mname_ns = {state->method->info->access, state->package};
1472 multiname_t mname = {QNAME, &mname_ns, 0, name};
1474 f = abc_method_new(global->file, type2, 1);
1475 if(!global->init) global->init = abc_initscript(global->file);
1476 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1477 //abc_code_t*c = global->init->method->body->code;
1479 //flash doesn't seem to allow us to access function slots
1480 //state->method->info->slot = slot;
1482 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1483 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1484 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1485 if(params->varargs) f->flags |= METHOD_NEED_REST;
1486 if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
1490 for(p=params->list;p;p=p->next) {
1491 if(params->varargs && !p->next) {
1492 break; //varargs: omit last parameter in function signature
1494 multiname_t*m = sig2mname(p->param->type);
1495 list_append(f->parameters, m);
1496 if(p->param->value) {
1497 check_constant_against_type(p->param->type, p->param->value);
1498 opt=1;list_append(f->optional_parameters, p->param->value);
1500 syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
1503 if(state->method->slots) {
1504 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1506 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1507 multiname_t*type = sig2mname(v->type);
1508 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1509 t->slot_id = v->index;
1514 check_code_for_break(body);
1516 /* Seems this works now.
1517 if(state->method->exceptions && state->method->uses_slots) {
1518 as3_warning("try/catch and activation not supported yet within the same method");
1522 f->body->code = body;
1523 f->body->exceptions = state->method->exceptions;
1524 } else { //interface
1526 syntaxerror("interface methods can't have a method body");
1536 void breakjumpsto(code_t*c, char*name, code_t*jump)
1539 if(c->opcode == OPCODE___BREAK__) {
1540 string_t*name2 = c->data[0];
1541 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1542 c->opcode = OPCODE_JUMP;
1549 void continuejumpsto(code_t*c, char*name, code_t*jump)
1552 if(c->opcode == OPCODE___CONTINUE__) {
1553 string_t*name2 = c->data[0];
1554 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1555 c->opcode = OPCODE_JUMP;
1563 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1568 return abc_coerce_a(c);
1572 // cast an "any" type to a specific type. subject to
1573 // runtime exceptions
1574 return abc_coerce2(c, &m);
1577 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1578 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1579 // allow conversion between number types
1580 if(TYPE_IS_UINT(to))
1581 return abc_convert_u(c);
1582 else if(TYPE_IS_INT(to))
1583 return abc_convert_i(c);
1584 else if(TYPE_IS_NUMBER(to))
1585 return abc_convert_d(c);
1586 return abc_coerce2(c, &m);
1589 if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
1592 if(TYPE_IS_BOOLEAN(to))
1593 return abc_convert_b(c);
1594 if(TYPE_IS_STRING(to))
1595 return abc_convert_s(c);
1596 if(TYPE_IS_OBJECT(to))
1597 return abc_coerce2(c, &m);
1598 if(TYPE_IS_OBJECT(from) && TYPE_IS_XMLLIST(to))
1599 return abc_coerce2(c, &m);
1600 if(TYPE_IS_OBJECT(from) && TYPE_IS_ARRAY(to))
1601 return abc_coerce2(c, &m);
1603 classinfo_t*supertype = from;
1605 if(supertype == to) {
1606 /* target type is one of from's superclasses.
1607 (not sure we need this coerce - as far as the verifier
1608 is concerned, object==object (i think) */
1609 return abc_coerce2(c, &m);
1612 while(supertype->interfaces[t]) {
1613 if(supertype->interfaces[t]==to) {
1614 // target type is one of from's interfaces
1615 return abc_coerce2(c, &m);
1619 supertype = supertype->superclass;
1621 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1623 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1625 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1628 as3_error("can't convert type %s%s%s to %s%s%s",
1629 from->package, from->package[0]?".":"", from->name,
1630 to->package, to->package[0]?".":"", to->name);
1634 code_t* coerce_to_type(code_t*c, classinfo_t*t)
1637 return abc_coerce_a(c);
1638 } else if(TYPE_IS_STRING(t)) {
1639 return abc_coerce_s(c);
1642 return abc_coerce2(c, &m);
1646 char is_pushundefined(code_t*c)
1648 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1651 static const char* get_package_from_name(const char*name)
1653 /* try explicit imports */
1654 dictentry_t* e = dict_get_slot(state->imports, name);
1656 if(!strcmp(e->key, name)) {
1657 slotinfo_t*c = (slotinfo_t*)e->data;
1658 if(c) return c->package;
1664 static namespace_list_t*get_current_imports()
1666 namespace_list_t*searchlist = 0;
1668 list_append(searchlist, namespace_new_package(state->package));
1670 import_list_t*l = state->wildcard_imports;
1672 namespace_t*ns = namespace_new_package(l->import->package);
1673 list_append(searchlist, ns);
1676 list_append(searchlist, namespace_new_package(""));
1677 list_append(searchlist, namespace_new_package(internal_filename_package));
1681 static slotinfo_t* find_class(const char*name)
1685 c = registry_find(state->package, name);
1688 /* try explicit imports */
1689 dictentry_t* e = dict_get_slot(state->imports, name);
1692 if(!strcmp(e->key, name)) {
1693 c = (slotinfo_t*)e->data;
1699 /* try package.* imports */
1700 import_list_t*l = state->wildcard_imports;
1702 //printf("does package %s contain a class %s?\n", l->import->package, name);
1703 c = registry_find(l->import->package, name);
1708 /* try global package */
1709 c = registry_find("", name);
1712 /* try local "filename" package */
1713 c = registry_find(internal_filename_package, name);
1718 typedcode_t push_class(slotinfo_t*a)
1723 if(a->access == ACCESS_PACKAGEINTERNAL &&
1724 strcmp(a->package, state->package) &&
1725 strcmp(a->package, internal_filename_package)
1727 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1728 infotypename(a), a->name, a->package, state->package);
1732 if(a->kind != INFOTYPE_CLASS) {
1734 x.c = abc_findpropstrict2(x.c, &m);
1735 x.c = abc_getproperty2(x.c, &m);
1736 if(a->kind == INFOTYPE_METHOD) {
1737 methodinfo_t*f = (methodinfo_t*)a;
1738 x.t = TYPE_FUNCTION(f);
1740 varinfo_t*v = (varinfo_t*)a;
1745 if(state->cls && state->method == state->cls->static_init) {
1746 /* we're in the static initializer.
1747 record the fact that we're using this class here */
1748 parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
1750 classinfo_t*c = (classinfo_t*)a;
1752 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1753 x.c = abc_getglobalscope(x.c);
1754 x.c = abc_getslot(x.c, c->slot);
1757 x.c = abc_getlex2(x.c, &m);
1759 x.t = TYPE_CLASS(c);
1765 char is_break_or_jump(code_t*c)
1769 if(c->opcode == OPCODE_JUMP ||
1770 c->opcode == OPCODE___BREAK__ ||
1771 c->opcode == OPCODE___CONTINUE__ ||
1772 c->opcode == OPCODE_THROW ||
1773 c->opcode == OPCODE_RETURNVOID ||
1774 c->opcode == OPCODE_RETURNVALUE) {
1780 #define IS_FINALLY_TARGET(op) \
1781 ((op) == OPCODE___CONTINUE__ || \
1782 (op) == OPCODE___BREAK__ || \
1783 (op) == OPCODE_RETURNVOID || \
1784 (op) == OPCODE_RETURNVALUE || \
1785 (op) == OPCODE___RETHROW__)
1787 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1789 #define NEED_EXTRA_STACK_ARG
1790 code_t*finally_label = abc_nop(0);
1791 NEW(lookupswitch_t, l);
1797 code_t*prev = i->prev;
1798 if(IS_FINALLY_TARGET(i->opcode)) {
1801 if(i->opcode == OPCODE___RETHROW__ ||
1802 i->opcode == OPCODE_RETURNVALUE) {
1803 if(i->opcode == OPCODE___RETHROW__)
1804 i->opcode = OPCODE_THROW;
1806 p = abc_coerce_a(p);
1807 p = abc_setlocal(p, tempvar);
1809 p = abc_pushbyte(p, count++);
1810 p = abc_jump(p, finally_label);
1811 code_t*target = p = abc_label(p);
1812 #ifdef NEED_EXTRA_STACK_ARG
1816 p = abc_getlocal(p, tempvar);
1819 p->next = i;i->prev = p;
1820 list_append(l->targets, target);
1826 c = abc_pushbyte(c, -1);
1827 c = code_append(c, finally_label);
1828 c = code_append(c, finally);
1830 #ifdef NEED_EXTRA_STACK_ARG
1833 c = abc_lookupswitch(c, l);
1834 c = l->def = abc_label(c);
1835 #ifdef NEED_EXTRA_STACK_ARG
1842 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1846 code_t*prev = i->prev;
1847 if(IS_FINALLY_TARGET(i->opcode)) {
1848 if(i->opcode == OPCODE___RETHROW__)
1849 i->opcode = OPCODE_THROW;
1850 code_t*end = code_dup(finally);
1851 code_t*start = code_start(end);
1852 if(prev) prev->next = start;
1859 return code_append(c, finally);
1862 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1868 int num_insertion_points=0;
1870 if(IS_FINALLY_TARGET(i->opcode))
1871 num_insertion_points++;
1878 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1883 int simple_version_cost = (1+num_insertion_points)*code_size;
1884 int lookup_version_cost = 4*num_insertion_points + 5;
1886 if(cantdup || simple_version_cost > lookup_version_cost) {
1887 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1888 return insert_finally_lookup(c, finally, tempvar);
1890 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1891 return insert_finally_simple(c, finally, tempvar);
1895 #define PASS1 }} if(as3_pass == 1) {{
1896 #define PASS1END }} if(as3_pass == 2) {{
1897 #define PASS2 }} if(as3_pass == 2) {{
1898 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1899 #define PASS12END }} if(as3_pass == 2) {{
1900 #define PASS_ALWAYS }} {{
1906 /* ------------ code blocks / statements ---------------- */
1908 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1910 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1911 PROGRAM_CODE_LIST: PROGRAM_CODE
1912 | PROGRAM_CODE_LIST PROGRAM_CODE
1914 PROGRAM_CODE: PACKAGE_DECLARATION
1915 | INTERFACE_DECLARATION
1917 | FUNCTION_DECLARATION
1920 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1923 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1924 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1925 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1927 INPACKAGE_CODE: INTERFACE_DECLARATION
1929 | FUNCTION_DECLARATION
1932 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1935 MAYBECODE: CODE {$$=$1;}
1936 MAYBECODE: {$$=code_new();}
1938 CODE: CODE CODEPIECE {
1939 $$=code_append($1,$2);
1941 CODE: CODEPIECE {$$=$1;}
1943 // code which may appear outside of methods
1944 CODE_STATEMENT: DEFAULT_NAMESPACE
1945 CODE_STATEMENT: IMPORT
1947 CODE_STATEMENT: FOR_IN
1948 CODE_STATEMENT: WHILE
1949 CODE_STATEMENT: DO_WHILE
1950 CODE_STATEMENT: SWITCH
1952 CODE_STATEMENT: WITH
1954 CODE_STATEMENT: VOIDEXPRESSION
1955 CODE_STATEMENT: USE_NAMESPACE
1956 CODE_STATEMENT: NAMESPACE_DECLARATION
1957 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1958 CODE_STATEMENT: '{' '}' {$$=0;}
1960 // code which may appear in methods (includes the above)
1961 CODEPIECE: ';' {$$=0;}
1962 CODEPIECE: CODE_STATEMENT
1963 CODEPIECE: VARIABLE_DECLARATION
1968 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
1978 //CODEBLOCK : '{' CODE '}' {$$=$2;}
1979 //CODEBLOCK : '{' '}' {$$=0;}
1980 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1981 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1983 /* ------------ package init code ------------------- */
1985 PACKAGE_INITCODE: CODE_STATEMENT {
1988 global->init = abc_initscript(global->file);
1989 code_t**cc = &global->init->method->body->code;
1990 *cc = code_append(*cc, $1);
1994 /* ------------ conditional compilation ------------- */
1996 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
1999 char*key = concat3($1,"::",$3);
2000 if(!definitions || !dict_contains(definitions, key)) {
2006 /* ------------ variables --------------------------- */
2009 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
2015 MAYBEEXPRESSION : '=' E {$$=$2;}
2016 | {$$=mkdummynode();}
2018 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2019 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2021 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2022 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2024 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2027 if(variable_exists($1))
2028 syntaxerror("Variable %s already defined", $1);
2030 new_variable($1, 0, 1, 0);
2035 if(state->method->uses_slots) {
2036 variable_t* v = find_slot(state, $1);
2038 // this variable is stored in a slot
2046 index = new_variable($1, $2, 1, 0);
2049 $$ = slot?abc_getscopeobject(0, 1):0;
2051 typedcode_t v = node_read($3);
2052 if(!is_subtype_of(v.t, $2)) {
2053 syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
2056 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2057 $$ = code_append($$, v.c);
2058 $$ = converttype($$, v.t, $2);
2061 $$ = defaultvalue($$, $2);
2064 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2065 $$ = code_append($$, v.c);
2066 $$ = abc_coerce_a($$);
2068 // don't do anything
2076 $$ = abc_setslot($$, index);
2078 $$ = abc_setlocal($$, index);
2082 /* ------------ control flow ------------------------- */
2084 MAYBEELSE: %prec below_else {$$ = code_new();}
2085 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2086 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2088 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2091 $$ = code_append($$, $4.c);
2092 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2094 $$ = code_append($$, $6);
2096 myjmp = $$ = abc_jump($$, 0);
2098 myif->branch = $$ = abc_nop($$);
2100 $$ = code_append($$, $7);
2101 myjmp->branch = $$ = abc_nop($$);
2107 FOR_INIT : {$$=code_new();}
2108 FOR_INIT : VARIABLE_DECLARATION
2109 FOR_INIT : VOIDEXPRESSION
2111 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2112 // (I don't see any easy way to revolve this conflict otherwise, as we
2113 // can't touch VAR_READ without upsetting the precedence about "return")
2114 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2115 PASS1 $$=$2;new_variable($2,0,1,0);
2116 PASS2 $$=$2;new_variable($2,$3,1,0);
2118 FOR_IN_INIT : T_IDENTIFIER {
2123 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2124 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2126 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2127 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2129 $$ = code_append($$, $2);
2130 code_t*loopstart = $$ = abc_label($$);
2131 $$ = code_append($$, $4.c);
2132 code_t*myif = $$ = abc_iffalse($$, 0);
2133 $$ = code_append($$, $8);
2134 code_t*cont = $$ = abc_nop($$);
2135 $$ = code_append($$, $6);
2136 $$ = abc_jump($$, loopstart);
2137 code_t*out = $$ = abc_nop($$);
2138 breakjumpsto($$, $1.name, out);
2139 continuejumpsto($$, $1.name, cont);
2146 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2147 variable_t*var = find_variable(state, $2);
2149 syntaxerror("variable %s not known in this scope", $2);
2152 char*tmp1name = concat2($2, "__tmp1__");
2153 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2154 char*tmp2name = concat2($2, "__array__");
2155 int array = new_variable(tmp1name, 0, 0, 0);
2158 $$ = code_append($$, $4.c);
2159 $$ = abc_coerce_a($$);
2160 $$ = abc_setlocal($$, array);
2161 $$ = abc_pushbyte($$, 0);
2162 $$ = abc_setlocal($$, it);
2164 code_t*loopstart = $$ = abc_label($$);
2166 $$ = abc_hasnext2($$, array, it);
2167 code_t*myif = $$ = abc_iffalse($$, 0);
2168 $$ = abc_getlocal($$, array);
2169 $$ = abc_getlocal($$, it);
2171 $$ = abc_nextname($$);
2173 $$ = abc_nextvalue($$);
2174 $$ = converttype($$, 0, var->type);
2175 $$ = abc_setlocal($$, var->index);
2177 $$ = code_append($$, $6);
2178 $$ = abc_jump($$, loopstart);
2180 code_t*out = $$ = abc_nop($$);
2181 breakjumpsto($$, $1.name, out);
2182 continuejumpsto($$, $1.name, loopstart);
2194 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2198 code_t*myjmp = $$ = abc_jump($$, 0);
2199 code_t*loopstart = $$ = abc_label($$);
2200 $$ = code_append($$, $6);
2201 code_t*cont = $$ = abc_nop($$);
2202 myjmp->branch = cont;
2203 $$ = code_append($$, $4.c);
2204 $$ = abc_iftrue($$, loopstart);
2205 code_t*out = $$ = abc_nop($$);
2206 breakjumpsto($$, $1, out);
2207 continuejumpsto($$, $1, cont);
2213 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2215 code_t*loopstart = $$ = abc_label($$);
2216 $$ = code_append($$, $3);
2217 code_t*cont = $$ = abc_nop($$);
2218 $$ = code_append($$, $6.c);
2219 $$ = abc_iftrue($$, loopstart);
2220 code_t*out = $$ = abc_nop($$);
2221 breakjumpsto($$, $1, out);
2222 continuejumpsto($$, $1, cont);
2228 BREAK : "break" %prec prec_none {
2229 $$ = abc___break__(0, "");
2231 BREAK : "break" T_IDENTIFIER {
2232 $$ = abc___break__(0, $2);
2234 CONTINUE : "continue" %prec prec_none {
2235 $$ = abc___continue__(0, "");
2237 CONTINUE : "continue" T_IDENTIFIER {
2238 $$ = abc___continue__(0, $2);
2241 MAYBE_CASE_LIST : {$$=0;}
2242 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2243 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2244 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2245 CASE_LIST: CASE {$$=$1;}
2246 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2248 CASE: "case" E ':' MAYBECODE {
2249 $$ = abc_getlocal(0, state->switch_var);
2250 $$ = code_append($$, node_read($2).c);
2251 code_t*j = $$ = abc_ifne($$, 0);
2252 $$ = code_append($$, $4);
2253 if($$->opcode != OPCODE___BREAK__) {
2254 $$ = abc___fallthrough__($$, "");
2256 code_t*e = $$ = abc_nop($$);
2259 DEFAULT: "default" ':' MAYBECODE {
2262 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2263 $$ = node_read($4).c;
2264 $$ = abc_setlocal($$, state->switch_var);
2265 $$ = code_append($$, $7);
2267 code_t*out = $$ = abc_kill($$, state->switch_var);
2268 breakjumpsto($$, $1, out);
2270 code_t*c = $$,*lastblock=0;
2272 if(c->opcode == OPCODE_IFNE) {
2273 if(!c->next) syntaxerror("internal error in fallthrough handling");
2275 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2277 c->opcode = OPCODE_JUMP;
2278 c->branch = lastblock;
2280 /* fall through end of switch */
2281 c->opcode = OPCODE_NOP;
2291 /* ------------ try / catch /finally ---------------- */
2293 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2294 state->exception_name=$3;
2295 PASS1 new_variable($3, 0, 0, 0);
2296 PASS2 new_variable($3, $4, 0, 0);
2299 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2300 multiname_t name = {QNAME, &name_ns, 0, $3};
2302 NEW(abc_exception_t, e)
2303 e->exc_type = sig2mname($4);
2304 e->var_name = multiname_clone(&name);
2308 int i = find_variable_safe(state, $3)->index;
2309 e->target = c = abc_nop(0);
2310 c = abc_setlocal(c, i);
2311 c = code_append(c, code_dup(state->method->scope_code));
2312 c = code_append(c, $8);
2318 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2323 NEW(abc_exception_t, e)
2324 e->exc_type = 0; //all exceptions
2325 e->var_name = 0; //no name
2328 e->to = code_append(e->to, $4);
2334 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2335 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2336 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2337 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2341 list_append($$.l,$2);
2342 $$.finally = $2->to;$2->to=0;
2345 CATCH_FINALLY_LIST: FINALLY {
2349 list_append($$.l,$1);
2350 $$.finally = $1->to;$1->to=0;
2354 TRY : "try" '{' {PASS12 new_state();
2355 state->method->has_exceptions=1;
2356 state->method->late_binding=1;//for invariant scope_code
2357 } MAYBECODE '}' CATCH_FINALLY_LIST {
2358 code_t*out = abc_nop(0);
2360 code_t*start = abc_nop(0);
2361 $$ = code_append(start, $4);
2362 if(!is_break_or_jump($4)) {
2363 $$ = abc_jump($$, out);
2365 code_t*end = $$ = abc_nop($$);
2369 tmp = new_variable("__finally__", 0, 0, 0);
2371 abc_exception_list_t*l = $6.l;
2374 abc_exception_t*e = l->abc_exception;
2376 $$ = code_append($$, e->target);
2377 $$ = abc_jump($$, out);
2379 parserassert((ptroff_t)$6.finally);
2381 e->target = $$ = abc_nop($$);
2382 $$ = code_append($$, code_dup(state->method->scope_code));
2383 $$ = abc___rethrow__($$);
2391 $$ = code_append($$, out);
2393 $$ = insert_finally($$, $6.finally, tmp);
2395 list_concat(state->method->exceptions, $6.l);
2401 /* ------------ throw ------------------------------- */
2403 THROW : "throw" EXPRESSION {
2407 THROW : "throw" %prec prec_none {
2408 if(!state->exception_name)
2409 syntaxerror("re-throw only possible within a catch block");
2410 variable_t*v = find_variable(state, state->exception_name);
2412 $$=abc_getlocal($$, v->index);
2416 /* ------------ with -------------------------------- */
2418 WITH_HEAD : "with" '(' EXPRESSION ')' {
2420 if(state->method->has_exceptions) {
2421 int v = alloc_local();
2422 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2423 state->method->scope_code = abc_pushwith(state->method->scope_code);
2428 WITH : WITH_HEAD CODEBLOCK {
2429 /* remove getlocal;pushwith from scope code again */
2430 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2433 if(state->method->has_exceptions) {
2435 $$ = abc_setlocal($$, $1.number);
2437 $$ = abc_pushwith($$);
2438 $$ = code_append($$, $2);
2439 $$ = abc_popscope($$);
2443 /* ------------ packages and imports ---------------- */
2445 X_IDENTIFIER: T_IDENTIFIER
2446 | "package" {PASS12 $$="package";}
2447 | "namespace" {PASS12 $$="namespace";}
2448 | T_NAMESPACE {PASS12 $$=$1;}
2450 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2451 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2453 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2454 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2455 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2456 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2459 static void state_has_imports()
2461 state->wildcard_imports = list_clone(state->wildcard_imports);
2462 state->imports = dict_clone(state->imports);
2463 state->has_own_imports = 1;
2465 static void import_toplevel(const char*package)
2467 char* s = strdup(package);
2469 dict_put(state->import_toplevel_packages, s, 0);
2470 char*x = strrchr(s, '.');
2478 IMPORT : "import" PACKAGEANDCLASS {
2480 slotinfo_t*s = registry_find($2->package, $2->name);
2481 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2482 as3_schedule_class($2->package, $2->name);
2486 syntaxerror("Couldn't import class\n");
2487 state_has_imports();
2488 dict_put(state->imports, c->name, c);
2489 import_toplevel(c->package);
2492 IMPORT : "import" PACKAGE '.' '*' {
2494 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2495 as3_schedule_package($2);
2500 state_has_imports();
2501 list_append(state->wildcard_imports, i);
2502 import_toplevel(i->package);
2506 /* ------------ classes and interfaces (header) -------------- */
2508 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2509 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2510 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2511 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2513 $$.flags=$1.flags|$2.flags;
2514 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2515 $$.ns=$1.ns?$1.ns:$2.ns;
2518 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2519 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2520 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2521 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2522 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2523 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2524 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2525 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2526 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2527 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2531 EXTENDS : {PASS12 $$=0;}
2532 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2534 EXTENDS_LIST : {PASS12 $$=list_new();}
2535 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2537 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2538 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2540 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2541 EXTENDS IMPLEMENTS_LIST
2542 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2544 '}' {PASS12 endclass();$$=0;}
2546 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2548 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2549 startclass(&$1,$3,0,$4);}
2550 MAYBE_INTERFACE_BODY
2551 '}' {PASS12 endclass();$$=0;}
2553 /* ------------ classes and interfaces (body) -------------- */
2556 MAYBE_CLASS_BODY : CLASS_BODY
2557 CLASS_BODY : CLASS_BODY_ITEM
2558 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2559 CLASS_BODY_ITEM : ';'
2560 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2561 CLASS_BODY_ITEM : SLOT_DECLARATION
2562 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2564 CLASS_BODY_ITEM : CODE_STATEMENT {
2565 code_t*c = state->cls->static_init->header;
2566 c = code_append(c, $1);
2567 state->cls->static_init->header = c;
2570 MAYBE_INTERFACE_BODY :
2571 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2572 INTERFACE_BODY : IDECLARATION
2573 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2575 IDECLARATION : "var" T_IDENTIFIER {
2576 syntaxerror("variable declarations not allowed in interfaces");
2578 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2580 $1.flags |= FLAG_PUBLIC;
2581 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2582 syntaxerror("invalid method modifiers: interface methods always need to be public");
2584 startfunction(&$1,$3,$4,&$6,$8);
2585 endfunction(&$1,$3,$4,&$6,$8, 0);
2586 list_deep_free($6.list);
2589 /* ------------ classes and interfaces (body, slots ) ------- */
2592 static int slotstate_varconst = 0;
2593 static modifiers_t*slotstate_flags = 0;
2594 static void setslotstate(modifiers_t* flags, int varconst)
2596 slotstate_varconst = varconst;
2597 slotstate_flags = flags;
2600 if(flags->flags&FLAG_STATIC) {
2601 state->method = state->cls->static_init;
2603 state->method = state->cls->init;
2606 // reset to "default" state (all in class code is static by default) */
2607 state->method = state->cls->static_init;
2610 parserassert(state->method);
2613 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2615 int flags = modifiers->flags;
2616 namespace_t ns = modifiers2access(modifiers);
2619 multiname_t mname = {QNAME, &ns, 0, name};
2621 trait_list_t**traits;
2625 if(!global->init) global->init = abc_initscript(global->file);
2626 ns.name = state->package;
2627 traits = &global->init->traits;
2628 code = &global->init->method->body->code;
2629 } else if(flags&FLAG_STATIC) {
2631 traits = &state->cls->abc->static_traits;
2632 code = &state->cls->static_init->header;
2634 // instance variable
2635 traits = &state->cls->abc->traits;
2636 code = &state->cls->init->header;
2638 if(ns.access == ACCESS_PROTECTED) {
2639 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2645 *m = *multiname_clone(&mname);
2647 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2651 VARCONST: "var" | "const"
2653 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2655 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2656 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2658 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2661 int flags = slotstate_flags->flags;
2662 namespace_t ns = modifiers2access(slotstate_flags);
2666 varinfo_t* info = 0;
2668 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2670 check_override(i, flags);
2672 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2674 slotinfo_t*i = registry_find(state->package, $1);
2676 syntaxerror("package %s already contains '%s'", state->package, $1);
2678 if(ns.name && ns.name[0]) {
2679 syntaxerror("namespaces not allowed on package-level variables");
2681 info = varinfo_register_global(ns.access, state->package, $1);
2685 info->flags = flags;
2687 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2691 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2695 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2699 t->type_name = multiname_clone(&m);
2701 info->slot = t->slot_id;
2703 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2704 FIXME: is there a way to use slots and still don't have conflicting overrides?
2706 info->slot = t->slot_id = 0;
2708 constant_t cval = $3->type->eval($3);
2709 if(cval.type!=CONSTANT_UNKNOWN) {
2710 /* compile time constant */
2711 t->value = malloc(sizeof(constant_t));
2712 memcpy(t->value, &cval, sizeof(constant_t));
2713 info->value = constant_clone(t->value);
2715 typedcode_t v = node_read($3);
2716 /* initalization code (if needed) */
2718 if(v.c && !is_pushundefined(v.c)) {
2719 c = abc_getlocal_0(c);
2720 c = code_append(c, v.c);
2721 c = converttype(c, v.t, $2);
2723 c = abc_initproperty2(c, &mname);
2725 c = abc_setslot(c, t->slot_id);
2728 *code = code_append(*code, c);
2731 if(slotstate_varconst==KW_CONST) {
2732 t->kind= TRAIT_CONST;
2733 info->flags |= FLAG_CONST;
2740 /* ------------ constants -------------------------------------- */
2742 MAYBECONSTANT: {$$=0;}
2743 MAYBECONSTANT: '=' E {
2744 $$ = malloc(sizeof(constant_t));
2745 *$$ = node_eval($2);
2746 if($$->type == CONSTANT_UNKNOWN) {
2747 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2751 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2752 CONSTANT : T_INT {$$ = constant_new_int($1);}
2754 $$ = constant_new_uint($1);
2756 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2757 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2758 CONSTANT : "true" {$$ = constant_new_true($1);}
2759 CONSTANT : "false" {$$ = constant_new_false($1);}
2760 CONSTANT : "null" {$$ = constant_new_null($1);}
2761 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2762 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2765 CONSTANT : T_IDENTIFIER {
2766 if(!strcmp($1, "NaN")) {
2767 $$ = constant_new_float(__builtin_nan(""));
2769 as3_warning("Couldn't evaluate constant value of %s", $1);
2770 $$ = constant_new_null($1);
2774 /* ---------------------------xml ------------------------------ */
2777 static int xml_level = 0;
2782 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2783 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2784 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2786 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2788 as3_warning("xml string substitution not yet supported");
2790 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2792 as3_warning("xml string substitution not yet supported");
2795 XMLTEXT : XMLTEXT XMLEXPR1 {
2796 $$ = concat2($1, "{...}");
2798 XMLTEXT : XMLTEXT T_STRING {$$=concat2($1, string_cstr(&$2));}
2799 XMLTEXT : XMLTEXT '>' {$$=concat2($1, ">");}
2801 XML2 : XMLNODE XMLTEXT {$$=concat2($1,$2);}
2802 XML2 : XML2 XMLNODE XMLTEXT {$$=concat3($1,$2,$3);free($1);free($2);free($3);}
2804 XML_ID_OR_EXPR: T_IDENTIFIER {$$=$1;}
2805 XML_ID_OR_EXPR: XMLEXPR2 {$$=$1;}
2807 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2808 $$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2809 free($2);free($3);free($5);free($8);
2811 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2812 $$ = allocprintf("<%s%s/>", $2, $3);
2814 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2815 $$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2816 free($2);free($3);free($5);free($6);free($9);
2819 MAYBE_XMLATTRIBUTES: {$$=strdup("");}
2820 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {$$=concat2(" ",$1);}
2821 XMLATTRIBUTES: XMLATTRIBUTE {$$=$1;}
2822 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {$$=concat3($1," ",$2);free($1);free($2);}
2824 XMLATTRIBUTE: XMLEXPR2 {
2825 $$ = strdup("{...}");
2827 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2828 char* str = string_cstr(&$3);
2829 $$ = concat2("{...}=",str);
2831 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2832 $$ = strdup("{...}={...}");
2834 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2835 $$ = concat2($1,"={...}");
2837 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2838 char* str = string_cstr(&$3);
2839 $$=allocprintf("%s=%s", $1,str);
2841 free($1);free((char*)$3.str);
2844 /* ------------ classes and interfaces (body, functions) ------- */
2846 // non-vararg version
2849 memset(&$$,0,sizeof($$));
2851 MAYBE_PARAM_LIST: PARAM_LIST {
2857 MAYBE_PARAM_LIST: "..." PARAM {
2859 memset(&$$,0,sizeof($$));
2861 list_append($$.list, $2);
2863 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2867 list_append($$.list, $4);
2871 PARAM_LIST: PARAM_LIST ',' PARAM {
2874 list_append($$.list, $3);
2878 memset(&$$,0,sizeof($$));
2879 list_append($$.list, $1);
2882 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2884 $$ = rfx_calloc(sizeof(param_t));
2890 PARAM: T_IDENTIFIER MAYBECONSTANT {
2892 $$ = rfx_calloc(sizeof(param_t));
2894 $$->type = TYPE_ANY;
2902 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2903 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2906 endfunction(&$1,$3,$4,&$6,0,0);
2908 if(!state->method->info) syntaxerror("internal error");
2910 code_t*c = method_header(state->method);
2911 c = wrap_function(c, 0, $11);
2913 endfunction(&$1,$3,$4,&$6,$8,c);
2915 list_deep_free($6.list);
2919 MAYBE_IDENTIFIER: T_IDENTIFIER
2920 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2921 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2922 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2925 endfunction(0,0,$2,&$4,0,0);
2927 methodinfo_t*f = state->method->info;
2928 if(!f || !f->kind) syntaxerror("internal error");
2930 code_t*c = method_header(state->method);
2931 c = wrap_function(c, 0, $9);
2933 int index = state->method->var_index;
2934 endfunction(0,0,$2,&$4,$6,c);
2936 $$.c = abc_getlocal(0, index);
2937 $$.t = TYPE_FUNCTION(f);
2939 PASS12 list_deep_free($4.list);
2943 /* ------------- package + class ids --------------- */
2945 CLASS: X_IDENTIFIER {
2946 PASS1 NEW(unresolvedinfo_t,c);
2947 memset(c, 0, sizeof(*c));
2948 c->kind = INFOTYPE_UNRESOLVED;
2950 c->package = get_package_from_name($1);
2952 c->nsset = get_current_imports();
2953 /* make the compiler look for this class in the current directory,
2955 as3_schedule_class_noerror(state->package, $1);
2957 $$ = (classinfo_t*)c;
2959 slotinfo_t*s = find_class($1);
2960 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2961 $$ = (classinfo_t*)s;
2964 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2965 PASS1 NEW(unresolvedinfo_t,c);
2966 memset(c, 0, sizeof(*c));
2967 c->kind = INFOTYPE_UNRESOLVED;
2970 $$ = (classinfo_t*)c;
2972 slotinfo_t*s = registry_find($1, $3);
2973 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2975 $$ = (classinfo_t*)s;
2978 CLASS_SPEC: PACKAGEANDCLASS
2981 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2982 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2984 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2985 | '*' {PASS12 $$=TYPE_ANY;}
2986 | "void" {PASS12 $$=TYPE_VOID;}
2988 | "String" {$$=registry_getstringclass();}
2989 | "int" {$$=registry_getintclass();}
2990 | "uint" {$$=registry_getuintclass();}
2991 | "Boolean" {$$=registry_getbooleanclass();}
2992 | "Number" {$$=registry_getnumberclass();}
2995 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2996 MAYBETYPE: {PASS12 $$=0;}
2998 /* ----------function calls, delete, constructor calls ------ */
3000 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3001 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3003 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3004 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3005 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3007 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3011 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3012 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3013 $$.number= $1.number+1;
3014 $$.cc = code_append($1.cc, $2.c);
3018 NEW : "new" E XX MAYBE_PARAM_VALUES {
3019 typedcode_t v = node_read($2);
3021 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3023 code_t*paramcode = $4.cc;
3024 if($$.c->opcode == OPCODE_GETPROPERTY) {
3025 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3026 $$.c = code_cutlast($$.c);
3027 $$.c = code_append($$.c, paramcode);
3028 $$.c = abc_constructprop2($$.c, name, $4.number);
3029 multiname_destroy(name);
3030 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3032 classinfo_t*c = v.t->data;
3034 $$.c = abc_findpropstrict2(0, &m);
3035 $$.c = code_append($$.c, paramcode);
3036 $$.c = abc_constructprop2($$.c, &m, $4.number);
3037 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3038 int slot = (int)(ptroff_t)$$.c->data[0];
3039 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3040 multiname_t*name = t->name;
3041 $$.c = code_cutlast($$.c);
3042 $$.c = code_append($$.c, paramcode);
3043 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3045 $$.c = code_append($$.c, paramcode);
3046 $$.c = abc_construct($$.c, $4.number);
3050 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3053 $$.c = abc_coerce_a($$.c);
3058 /* TODO: use abc_call (for calling local variables),
3059 abc_callstatic (for calling own methods)
3062 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3064 typedcode_t v = node_read($1);
3066 if($$.c->opcode == OPCODE_COERCE_A) {
3067 $$.c = code_cutlast($$.c);
3069 code_t*paramcode = $3.cc;
3072 if($$.c->opcode == OPCODE_GETPROPERTY) {
3073 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3074 $$.c = code_cutlast($$.c);
3075 $$.c = code_append($$.c, paramcode);
3076 $$.c = abc_callproperty2($$.c, name, $3.number);
3077 multiname_destroy(name);
3078 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3079 int slot = (int)(ptroff_t)$$.c->data[0];
3080 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3081 if(t->kind!=TRAIT_METHOD) {
3082 //ok: flash allows to assign closures to members.
3084 multiname_t*name = t->name;
3085 $$.c = code_cutlast($$.c);
3086 $$.c = code_append($$.c, paramcode);
3087 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3088 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3089 } else if($$.c->opcode == OPCODE_GETSUPER) {
3090 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3091 $$.c = code_cutlast($$.c);
3092 $$.c = code_append($$.c, paramcode);
3093 $$.c = abc_callsuper2($$.c, name, $3.number);
3094 multiname_destroy(name);
3096 $$.c = abc_getglobalscope($$.c);
3097 $$.c = code_append($$.c, paramcode);
3098 $$.c = abc_call($$.c, $3.number);
3101 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3102 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3103 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3104 // calling a class is like a typecast
3105 $$.t = (classinfo_t*)v.t->data;
3108 $$.c = abc_coerce_a($$.c);
3112 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3113 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3114 if(!state->method) syntaxerror("super() not allowed outside of a function");
3115 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3118 $$.c = abc_getlocal_0($$.c);
3120 $$.c = code_append($$.c, $3.cc);
3122 this is dependent on the control path, check this somewhere else
3123 if(state->method->has_super)
3124 syntaxerror("constructor may call super() only once");
3126 state->method->has_super = 1;
3128 $$.c = abc_constructsuper($$.c, $3.number);
3129 $$.c = abc_pushundefined($$.c);
3133 DELETE: "delete" E {
3134 typedcode_t v = node_read($2);
3136 if($$.c->opcode == OPCODE_COERCE_A) {
3137 $$.c = code_cutlast($$.c);
3139 multiname_t*name = 0;
3140 if($$.c->opcode == OPCODE_GETPROPERTY) {
3141 $$.c->opcode = OPCODE_DELETEPROPERTY;
3142 } else if($$.c->opcode == OPCODE_GETSLOT) {
3143 int slot = (int)(ptroff_t)$$.c->data[0];
3144 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3145 $$.c = code_cutlast($$.c);
3146 $$.c = abc_deleteproperty2($$.c, name);
3148 $$.c = abc_getlocal_0($$.c);
3149 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3150 $$.c = abc_deleteproperty2($$.c, &m);
3152 $$.t = TYPE_BOOLEAN;
3155 RETURN: "return" %prec prec_none {
3156 $$ = abc_returnvoid(0);
3158 RETURN: "return" EXPRESSION {
3160 $$ = abc_returnvalue($$);
3163 // ----------------------- expression types -------------------------------------
3165 NONCOMMAEXPRESSION : E %prec below_lt {
3168 EXPRESSION : COMMA_EXPRESSION {
3171 COMMA_EXPRESSION : E %prec below_lt {
3172 $$ = mkmultinode(&node_comma, $1);
3174 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3175 $$ = multinode_extend($1, $3);
3177 VOIDEXPRESSION : E %prec below_minus {
3180 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3182 $$ = code_append($$, node_exec($3));
3185 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3186 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3188 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3189 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3190 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3191 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3192 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3194 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3196 $$.cc = code_append($$.cc, $1);
3197 $$.cc = code_append($$.cc, $3.c);
3200 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3202 $$.number = $1.number+2;
3203 $$.cc = code_append($$.cc, $3);
3204 $$.cc = code_append($$.cc, $5.c);
3207 // ----------------------- expression evaluation -------------------------------------
3209 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3210 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3211 E : NEW {$$ = mkcodenode($1);}
3212 E : DELETE {$$ = mkcodenode($1);}
3213 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3214 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3217 $$ = mkconstnode($1);
3223 multiname_t m = {QNAME, &stdns, 0, "XML"};
3224 v.c = abc_getlex2(v.c, &m);
3225 v.c = abc_pushstring(v.c, $1);
3226 v.c = abc_construct(v.c, 1);
3235 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3237 v.c = abc_getlex2(v.c, &m);
3238 v.c = abc_pushstring(v.c, $1.pattern);
3239 v.c = abc_construct(v.c, 1);
3241 v.c = abc_getlex2(v.c, &m);
3242 v.c = abc_pushstring(v.c, $1.pattern);
3243 v.c = abc_pushstring(v.c, $1.options);
3244 v.c = abc_construct(v.c, 2);
3252 state->method->need_arguments = 1;
3255 v.c = abc_getlocal(0, state->method->need_arguments);
3261 E : '[' MAYBE_EXPRESSION_LIST ']' {
3264 v.c = code_append(v.c, $2.cc);
3265 v.c = abc_newarray(v.c, $2.number);
3266 v.t = registry_getarrayclass();
3271 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3274 v.c = code_append(v.c, $2.cc);
3275 v.c = abc_newobject(v.c, $2.number/2);
3276 v.t = registry_getobjectclass();
3280 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3281 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3282 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3283 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3284 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3285 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3286 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3287 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3288 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3289 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3290 E : '!' E {$$ = mknode1(&node_not, $2);}
3291 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3292 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3293 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3294 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3295 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3296 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3297 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3298 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3299 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3300 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3301 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3302 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3303 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3304 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3305 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3306 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3307 E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
3308 E : "void" E {$$ = mknode1(&node_void, $2);}
3309 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3310 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3311 E : '-' E {$$ = mknode1(&node_neg, $2);}
3312 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3313 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3314 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3315 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3316 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3317 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3318 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3319 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3320 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3321 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3322 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3323 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3324 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3325 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3327 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3328 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3329 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3330 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3332 E : "super" '.' T_IDENTIFIER
3333 { if(!state->cls->info)
3334 syntaxerror("super keyword not allowed outside a class");
3335 classinfo_t*t = state->cls->info->superclass;
3336 if(!t) t = TYPE_OBJECT;
3337 memberinfo_t*f = findmember_nsset(t, $3, 1);
3338 MEMBER_MULTINAME(m, f, $3);
3341 v.c = abc_getlocal_0(v.c);
3342 v.c = abc_getsuper2(v.c, &m);
3343 v.t = slotinfo_gettype((slotinfo_t*)f);
3347 E : '@' T_IDENTIFIER {
3349 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3350 v.c = abc_getlex2(0, &m);
3355 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3358 typedcode_t v = node_read($1);
3359 typedcode_t w = node_read($5);
3361 int index = alloc_local();
3362 int result = alloc_local();
3363 int tmp = alloc_local();
3364 int xml = alloc_local();
3366 c = code_append(c, v.c);
3367 c = abc_checkfilter(c);
3368 c = abc_coerce_a(c); //hasnext2 converts to *
3369 c = abc_setlocal(c, xml);
3370 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3371 c = abc_getlex2(c, &m);
3372 c = abc_construct(c, 0);
3373 c = abc_setlocal(c, result);
3374 c = abc_pushbyte(c, 0);
3375 c = abc_setlocal(c, index);
3376 code_t*jmp = c = abc_jump(c, 0);
3377 code_t*loop = c = abc_label(c);
3378 c = abc_getlocal(c, xml);
3379 c = abc_getlocal(c, index);
3380 c = abc_nextvalue(c);
3382 c = abc_setlocal(c, tmp);
3383 c = abc_pushwith(c);
3384 c = code_append(c, w.c);
3385 c = abc_popscope(c);
3386 code_t*b = c = abc_iffalse(c, 0);
3387 c = abc_getlocal(c, result);
3388 c = abc_getlocal(c, index);
3389 c = abc_getlocal(c, tmp);
3390 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3391 c = abc_setproperty2(c, &m2);
3392 c = b->branch = jmp->branch = abc_nop(c);
3393 c = abc_kill(c, tmp);
3394 c = abc_hasnext2(c, xml, index);
3395 c = abc_iftrue(c, loop);
3396 c = abc_getlocal(c, result);
3397 c = abc_kill(c, xml);
3398 c = abc_kill(c, result);
3399 c = abc_kill(c, index);
3409 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3410 ID_OR_NS : '*' {$$="*";}
3411 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3412 SUBNODE: X_IDENTIFIER
3416 MAYBE_NS: T_IDENTIFIER "::" {$$=$1;}
3417 | T_NAMESPACE "::" {$$=(char*)$1;}
3418 | '*' "::" {$$="*";}
3421 E : E '.' ID_OR_NS "::" SUBNODE {
3422 typedcode_t v = node_read($1);
3423 typedcode_t w = node_read(resolve_identifier($3));
3424 v.c = code_append(v.c, w.c);
3425 if(!TYPE_IS_NAMESPACE(w.t)) {
3426 as3_softwarning("%s might not be a namespace", $3);
3428 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3429 multiname_t m = {RTQNAME, 0, 0, $5};
3430 v.c = abc_getproperty2(v.c, &m);
3431 if(TYPE_IS_XML(v.t)) {
3434 v.c = abc_coerce_a(v.c);
3439 E : E ".." SUBNODE {
3440 typedcode_t v = node_read($1);
3441 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3442 v.c = abc_getdescendants2(v.c, &m);
3446 E : E '.' '[' E ']' {
3447 typedcode_t v = node_read($1);
3448 typedcode_t w = node_read($4);
3449 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3450 v.c = code_append(v.c, w.c);
3451 v.c = converttype(w.c, w.t, TYPE_STRING);
3452 v.c = abc_getproperty2(v.c, &m);
3457 E : E '.' '@' SUBNODE {
3458 typedcode_t v = node_read($1);
3459 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3460 v.c = abc_getproperty2(v.c, &m);
3464 E : E ".." '@' SUBNODE {
3465 typedcode_t v = node_read($1);
3466 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3467 v.c = abc_getdescendants2(v.c, &m);
3471 E : E '.' '@' '[' E ']' {
3472 typedcode_t v = node_read($1);
3473 typedcode_t w = node_read($5);
3474 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3475 v.c = code_append(v.c, w.c);
3476 v.c = converttype(w.c, w.t, TYPE_STRING);
3477 v.c = abc_getproperty2(v.c, &m);
3481 E : E ".." '@' '[' E ']' {
3482 typedcode_t v = node_read($1);
3483 typedcode_t w = node_read($5);
3484 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3485 v.c = code_append(v.c, w.c);
3486 v.c = converttype(w.c, w.t, TYPE_STRING);
3487 v.c = abc_getdescendants2(v.c, &m);
3492 MEMBER : E '.' SUBNODE {
3493 typedcode_t v1 = node_read($1);
3495 classinfo_t*t = v1.t;
3497 if(TYPE_IS_CLASS(t) && t->data) {
3501 if(TYPE_IS_XML(t)) {
3502 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3503 $$.c = abc_getproperty2($$.c, &m);
3504 $$.c = abc_coerce_a($$.c);
3505 $$.t = TYPE_XMLLIST;
3507 if(t->subtype==INFOTYPE_UNRESOLVED) {
3508 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3510 memberinfo_t*f = findmember_nsset(t, $3, 1);
3512 if(f && !is_static != !(f->flags&FLAG_STATIC))
3514 if(f && f->slot && !noslot) {
3515 $$.c = abc_getslot($$.c, f->slot);
3518 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3520 MEMBER_MULTINAME(m, f, $3);
3521 $$.c = abc_getproperty2($$.c, &m);
3523 /* determine type */
3524 $$.t = slotinfo_gettype((slotinfo_t*)f);
3526 $$.c = abc_coerce_a($$.c);
3528 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3529 string_t*package = v1.c->data[0];
3530 char*package2 = concat3(package->str, ".", $3);
3532 slotinfo_t*a = registry_find(package->str, $3);
3535 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3536 registry_ispackage(package2)) {
3538 $$.c->data[0] = string_new4(package2);
3541 syntaxerror("couldn't resolve %s", package2);
3544 /* when resolving a property on an unknown type, we do know the
3545 name of the property (and don't seem to need the package), but
3546 we need to make avm2 try out all access modes */
3547 as3_softwarning("Resolving %s on unknown type", $3);
3548 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3549 $$.c = abc_getproperty2($$.c, &m);
3550 $$.c = abc_coerce_a($$.c);
3556 node_t* resolve_identifier(char*name)
3566 /* look at variables */
3567 if((v = find_variable(state, name))) {
3568 // name is a local variable
3569 o.c = abc_getlocal(o.c, v->index);
3571 return mkcodenode(o);
3573 if((v = find_slot(state, name))) {
3574 o.c = abc_getscopeobject(o.c, 1);
3575 o.c = abc_getslot(o.c, v->index);
3577 return mkcodenode(o);
3580 int i_am_static = state->method->is_static;
3582 /* look at current class' members */
3583 if(!state->method->inner &&
3584 !state->xmlfilter &&
3586 (f = findmember_nsset(state->cls->info, name, 1)))
3588 // name is a member or attribute in this class
3589 int var_is_static = (f->flags&FLAG_STATIC);
3591 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3592 /* if the variable is a constant (and we know what is evaluates to), we
3593 can just use the value itself */
3594 varinfo_t*v = (varinfo_t*)f;
3596 return mkconstnode(v->value);
3600 if(var_is_static >= i_am_static) {
3601 if(f->kind == INFOTYPE_METHOD) {
3602 o.t = TYPE_FUNCTION(f);
3607 if(var_is_static && !i_am_static) {
3608 /* access to a static member from a non-static location.
3609 do this via findpropstrict:
3610 there doesn't seem to be any non-lookup way to access
3611 static properties of a class */
3612 state->method->late_binding = 1;
3614 namespace_t ns = {f->access, f->package};
3615 multiname_t m = {QNAME, &ns, 0, name};
3616 o.c = abc_findpropstrict2(o.c, &m);
3617 o.c = abc_getproperty2(o.c, &m);
3618 return mkcodenode(o);
3619 } else if(f->slot>0) {
3620 o.c = abc_getlocal_0(o.c);
3621 o.c = abc_getslot(o.c, f->slot);
3622 return mkcodenode(o);
3624 MEMBER_MULTINAME(m, f, name);
3625 o.c = abc_getlocal_0(o.c);
3626 o.c = abc_getproperty2(o.c, &m);
3627 return mkcodenode(o);
3632 /* look at actual classes, in the current package and imported */
3633 if(!state->xmlfilter && (a = find_class(name))) {
3634 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3635 o.c = abc_getlocal_0(0);
3636 o.t = TYPE_CLASS((classinfo_t*)a);
3640 return mkcodenode(o);
3643 /* look through package prefixes */
3644 if(!state->xmlfilter &&
3645 (dict_contains(state->import_toplevel_packages, name) ||
3646 registry_ispackage(name))) {
3647 o.c = abc___pushpackage__(o.c, name);
3649 return mkcodenode(o); //?
3652 /* unknown object, let the avm2 resolve it */
3654 if(!state->method->inner && !state->xmlfilter) {
3655 /* we really should make inner functions aware of the class context */
3656 as3_warning("Couldn't resolve '%s', doing late binding", name);
3658 state->method->late_binding = 1;
3660 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3663 o.c = abc_findpropstrict2(o.c, &m);
3664 o.c = abc_getproperty2(o.c, &m);
3665 return mkcodenode(o);
3670 VAR_READ : T_IDENTIFIER {
3672 /* Queue unresolved identifiers for checking against the parent
3673 function's variables.
3674 We consider everything which is not a local variable "unresolved".
3675 This encompasses class names, members of the surrounding class
3676 etc. which is *correct* because local variables of the parent function
3680 if(!find_variable(state, $1)) {
3681 if(state->method->inner) {
3682 unknown_variable($1);
3684 /* let the compiler know that it might want to check the current directory/package
3685 for this identifier- maybe there's a file $1.as defining $1. */
3686 as3_schedule_class_noerror(state->package, $1);
3692 $$ = resolve_identifier($1);
3695 // ----------------- namespaces -------------------------------------------------
3698 void add_active_url(const char*url)
3702 list_append(state->active_namespace_urls, n);
3706 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3708 NEW(namespace_decl_t,n);
3713 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3715 NEW(namespace_decl_t,n);
3720 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3722 NEW(namespace_decl_t,n);
3727 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3729 trie_put(active_namespaces, $2->name, (void*)$2->url);
3731 namespace_t access = modifiers2access(&$1);
3732 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3733 var->type = TYPE_NAMESPACE;
3735 ns.access = ACCESS_NAMESPACE;
3737 var->value = constant_new_namespace(&ns);
3740 MULTINAME(m, TYPE_NAMESPACE);
3741 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3742 t->value = var->value;
3743 t->type_name = multiname_clone(&m);
3749 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3751 as3_warning("default xml namespaces not supported yet");
3754 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3756 const char*url = $3->name;
3758 varinfo_t*s = (varinfo_t*)$3;
3759 if(s->kind == INFOTYPE_UNRESOLVED) {
3760 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3762 syntaxerror("Couldn't resolve namespace %s", $3->name);
3765 if(!s || s->kind != INFOTYPE_VAR)
3766 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3767 if(!s->value || !NS_TYPE(s->value->type))
3768 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3769 url = s->value->ns->name;
3771 trie_put(active_namespaces, $3->name, (void*)url);
3772 add_active_url(url);