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);
576 global->init = abc_initscript(global->file);
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 code_t*c = wrap_function(header, 0, global->init->method->body->code);
590 global->init->method->body->code = abc_returnvoid(c);
591 free(state->method);state->method=0;
594 //free(state->package);state->package=0; // used in registry
595 state_destroy(state);state=0;
598 void initialize_parser()
600 global = rfx_calloc(sizeof(global_t));
601 global->file = abc_file_new();
602 global->file->flags &= ~ABCFILE_LAZY;
603 global->file2token2info = dict_new();
604 global->token2info = 0;
605 global->classinit = abc_initscript(global->file);
608 void* finish_parser()
610 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
611 global->token2info=0;
613 initcode_add_classlist(global->classinit, global->classes);
618 typedef struct _variable {
623 methodstate_t*is_inner_method;
626 static variable_t* find_variable(state_t*s, char*name)
631 v = dict_lookup(s->vars, name);
633 if(s->new_vars) break;
636 return dict_lookup(top->allvars, name);
638 static variable_t* find_slot(state_t*s, const char*name)
640 if(s->method && s->method->slots)
641 return dict_lookup(s->method->slots, name);
645 static variable_t* find_variable_safe(state_t*s, char*name)
647 variable_t* v = find_variable(s, name);
649 syntaxerror("undefined variable: %s", name);
653 static char variable_exists(char*name)
655 return dict_contains(state->vars, name);
658 static code_t*defaultvalue(code_t*c, classinfo_t*type)
660 if(TYPE_IS_INT(type)) {
661 c = abc_pushbyte(c, 0);
662 } else if(TYPE_IS_UINT(type)) {
663 c = abc_pushuint(c, 0);
664 } else if(TYPE_IS_FLOAT(type)) {
666 } else if(TYPE_IS_BOOLEAN(type)) {
667 c = abc_pushfalse(c);
668 } else if(TYPE_IS_STRING(type)) {
672 //c = abc_pushundefined(c);
673 syntaxerror("internal error: can't generate default value for * type");
677 c = abc_coerce2(c, &m);
682 static int alloc_local()
684 return state->method->variable_count++;
687 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
690 variable_t*v = find_slot(state, name);
698 v->index = alloc_local();
703 dict_put(state->vars, name, v);
704 dict_put(state->allvars, name, v);
709 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
711 return new_variable2(name, type, init, maybeslot)->index;
714 #define TEMPVARNAME "__as3_temp__"
717 variable_t*v = find_variable(state, TEMPVARNAME);
722 i = new_variable(TEMPVARNAME, 0, 0, 0);
727 static code_t* var_block(code_t*body)
733 DICT_ITERATE_DATA(state->vars, variable_t*, v) {
734 if(v->type && v->init) {
735 c = defaultvalue(c, v->type);
736 c = abc_setlocal(c, v->index);
737 k = abc_kill(k, v->index);
745 if(x->opcode== OPCODE___BREAK__ ||
746 x->opcode== OPCODE___CONTINUE__) {
747 /* link kill code before break/continue */
748 code_t*e = code_dup(k);
749 code_t*s = code_start(e);
761 c = code_append(c, body);
762 c = code_append(c, k);
766 static void unknown_variable(char*name)
768 if(!state->method->unresolved_variables)
769 state->method->unresolved_variables = dict_new();
770 if(!dict_contains(state->method->unresolved_variables, name))
771 dict_put(state->method->unresolved_variables, name, 0);
774 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
776 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
777 c = abc_getlocal_0(c);
778 c = abc_pushscope(c);
781 /* FIXME: this alloc_local() causes variable indexes to be
782 different in pass2 than in pass1 */
783 if(!m->activation_var) {
784 m->activation_var = alloc_local();
787 c = abc_newactivation(c);
789 c = abc_pushscope(c);
790 c = abc_setlocal(c, m->activation_var);
792 c = abc_getlocal(c, m->activation_var);
793 c = abc_pushscope(c);
799 static code_t* method_header(methodstate_t*m)
803 c = add_scope_code(c, m, 1);
805 methodstate_list_t*l = m->innerfunctions;
807 parserassert(l->methodstate->abc);
808 if(m->uses_slots && l->methodstate->is_a_slot) {
809 c = abc_getscopeobject(c, 1);
810 c = abc_newfunction(c, l->methodstate->abc);
812 c = abc_setlocal(c, l->methodstate->var_index);
813 c = abc_setslot(c, l->methodstate->slot_index);
815 c = abc_newfunction(c, l->methodstate->abc);
816 c = abc_setlocal(c, l->methodstate->var_index);
818 free(l->methodstate);l->methodstate=0;
822 c = code_append(c, m->header);
825 if(m->is_constructor && !m->has_super) {
826 // call default constructor
827 c = abc_getlocal_0(c);
828 c = abc_constructsuper(c, 0);
832 /* all parameters that are used by inner functions
833 need to be copied from local to slot */
834 parserassert(m->activation_var);
835 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
836 if(v->is_parameter) {
837 c = abc_getlocal(c, m->activation_var);
838 c = abc_getlocal(c, v->index);
839 c = abc_setslot(c, v->index);
843 list_free(m->innerfunctions);
844 m->innerfunctions = 0;
849 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
851 c = code_append(c, header);
852 c = code_append(c, var_block(body));
853 /* append return if necessary */
854 if(!c || (c->opcode != OPCODE_RETURNVOID &&
855 c->opcode != OPCODE_RETURNVALUE)) {
856 c = abc_returnvoid(c);
861 static void startpackage(char*name)
864 state->package = strdup(name);
866 static void endpackage()
868 //used e.g. in classinfo_register:
869 //free(state->package);state->package=0;
873 #define FLAG_PUBLIC 256
874 #define FLAG_PROTECTED 512
875 #define FLAG_PRIVATE 1024
876 #define FLAG_PACKAGEINTERNAL 2048
877 #define FLAG_NAMESPACE 4096
879 static namespace_t modifiers2access(modifiers_t*mod)
884 if(mod->flags&FLAG_NAMESPACE) {
885 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
886 syntaxerror("invalid combination of access levels and namespaces");
887 ns.access = ACCESS_NAMESPACE;
889 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
891 /* shouldn't happen- the tokenizer only reports something as a namespace
892 if it was already registered */
893 trie_dump(active_namespaces);
894 syntaxerror("unknown namespace: %s", mod->ns);
897 } else if(mod->flags&FLAG_PUBLIC) {
898 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
899 syntaxerror("invalid combination of access levels");
900 ns.access = ACCESS_PACKAGE;
901 } else if(mod->flags&FLAG_PRIVATE) {
902 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
903 syntaxerror("invalid combination of access levels");
904 ns.access = ACCESS_PRIVATE;
905 } else if(mod->flags&FLAG_PROTECTED) {
906 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
907 syntaxerror("invalid combination of access levels");
908 ns.access = ACCESS_PROTECTED;
910 ns.access = ACCESS_PACKAGEINTERNAL;
914 static slotinfo_t* find_class(const char*name);
916 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
918 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
921 static void innerfunctions2vars(methodstate_t*m)
923 methodstate_list_t*l = m->innerfunctions;
925 methodstate_t*m = l->methodstate;
927 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 0);
928 m->var_index = v->index;
930 m->slot_index = m->is_a_slot;
931 v->is_inner_method = m;
936 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
941 index = new_variable("this", 0, 0, 0);
942 else if(!m->is_global)
943 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
945 index = new_variable("globalscope", 0, 0, 0);
946 parserassert(!index);
951 for(p=params->list;p;p=p->next) {
952 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
955 if(as3_pass==2 && m->need_arguments) {
956 /* arguments can never be used by an innerfunction (the inner functions
957 have their own arguments var), so it's ok to not initialize this until
958 pass 2. (We don't know whether we need it before, anyway) */
959 variable_t*v = new_variable2("arguments", TYPE_ARRAY, 0, 0);
960 m->need_arguments = v->index;
964 innerfunctions2vars(m);
967 m->scope_code = add_scope_code(m->scope_code, m, 0);
969 /* exchange unresolved identifiers with the actual objects */
970 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
971 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
972 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
973 if(!type || type->kind != INFOTYPE_CLASS) {
974 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
984 char*as3_globalclass=0;
985 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
988 syntaxerror("inner classes now allowed");
993 classinfo_list_t*mlist=0;
995 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
996 syntaxerror("invalid modifier(s)");
998 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
999 syntaxerror("public and internal not supported at the same time.");
1001 if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
1002 syntaxerror("protected and static not supported at the same time.");
1004 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1005 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1006 // all classes extend object
1007 extends = registry_getobjectclass();
1010 /* create the class name, together with the proper attributes */
1014 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
1015 access = ACCESS_PRIVATE; package = internal_filename_package;
1016 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
1017 access = ACCESS_PACKAGEINTERNAL; package = state->package;
1018 } else if(state->package!=internal_filename_package) {
1019 access = ACCESS_PACKAGE; package = state->package;
1021 syntaxerror("public classes only allowed inside a package");
1025 state->cls = rfx_calloc(sizeof(classstate_t));
1026 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1027 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1028 state->cls->static_init->is_static=FLAG_STATIC;
1029 state->cls->static_init->variable_count=1;
1030 /* notice: we make no effort to initialize the top variable (local0) here,
1031 even though it has special meaning. We just rely on the fact
1032 that pass 1 won't do anything with variables */
1034 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1036 /* set current method to constructor- all code within the class-level (except
1037 static variable initializations) will be executed during construction time */
1038 state->method = state->cls->init;
1040 if(registry_find(package, classname)) {
1041 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1043 /* build info struct */
1044 int num_interfaces = (list_length(implements));
1045 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1046 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1047 state->cls->info->superclass = extends;
1050 classinfo_list_t*l = implements;
1051 for(l=implements;l;l=l->next) {
1052 state->cls->info->interfaces[pos++] = l->classinfo;
1057 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1059 state->method = state->cls->init;
1060 parserassert(state->cls && state->cls->info);
1062 function_initvars(state->cls->init, 0, 0, 0, 1);
1063 function_initvars(state->cls->static_init, 0, 0, 0, 0);
1065 if(extends && (extends->flags & FLAG_FINAL))
1066 syntaxerror("Can't extend final class '%s'", extends->name);
1069 while(state->cls->info->interfaces[pos]) {
1070 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1071 syntaxerror("'%s' is not an interface",
1072 state->cls->info->interfaces[pos]->name);
1076 /* generate the abc code for this class */
1077 MULTINAME(classname2,state->cls->info);
1078 multiname_t*extends2 = sig2mname(extends);
1080 /* don't add the class to the class index just yet- that will be done later
1082 state->cls->abc = abc_class_new(0, &classname2, extends2);
1083 state->cls->abc->file = global->file;
1085 multiname_destroy(extends2);
1086 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1087 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1088 if(state->cls->info->flags&FLAG_INTERFACE) {
1089 abc_class_interface(state->cls->abc);
1092 for(mlist=implements;mlist;mlist=mlist->next) {
1093 MULTINAME(m, mlist->classinfo);
1094 abc_class_add_interface(state->cls->abc, &m);
1097 state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
1098 list_append(global->classes, state->cls->dependencies);
1100 /* flash.display.MovieClip handling */
1101 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1102 if(state->package && state->package[0]) {
1103 as3_globalclass = concat3(state->package, ".", classname);
1105 as3_globalclass = strdup(classname);
1111 static void endclass()
1114 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1116 c = abc_getlocal_0(c);
1117 c = abc_constructsuper(c, 0);
1118 state->cls->init->header = code_append(state->cls->init->header, c);
1119 state->cls->has_constructor=1;
1121 if(state->cls->init) {
1122 if(state->cls->info->flags&FLAG_INTERFACE) {
1123 if(state->cls->init->header)
1124 syntaxerror("interface can not have class-level code");
1126 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1127 code_t*c = method_header(state->cls->init);
1128 m->body->code = wrap_function(c, 0, m->body->code);
1131 if(state->cls->static_init) {
1132 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1133 code_t*c = method_header(state->cls->static_init);
1134 m->body->code = wrap_function(c, 0, m->body->code);
1137 trait_list_t*trait = state->cls->abc->traits;
1138 /* switch all protected members to the protected ns of this class */
1140 trait_t*t = trait->trait;
1141 if(t->name->ns->access == ACCESS_PROTECTED) {
1142 if(!state->cls->abc->protectedNS) {
1143 char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
1144 state->cls->abc->protectedNS = namespace_new_protected(n);
1145 state->cls->abc->flags |= CLASS_PROTECTED_NS;
1147 t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
1149 trait = trait->next;
1156 void check_code_for_break(code_t*c)
1159 if(c->opcode == OPCODE___BREAK__) {
1160 char*name = string_cstr(c->data[0]);
1161 syntaxerror("Unresolved \"break %s\"", name);
1163 if(c->opcode == OPCODE___CONTINUE__) {
1164 char*name = string_cstr(c->data[0]);
1165 syntaxerror("Unresolved \"continue %s\"", name);
1167 if(c->opcode == OPCODE___RETHROW__) {
1168 syntaxerror("Unresolved \"rethrow\"");
1170 if(c->opcode == OPCODE___FALLTHROUGH__) {
1171 syntaxerror("Unresolved \"fallthrough\"");
1173 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1174 char*name = string_cstr(c->data[0]);
1175 syntaxerror("Can't reference a package (%s) as such", name);
1181 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1183 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1184 if(TYPE_IS_NUMBER(t)) {
1185 xassert(c->type == CONSTANT_FLOAT
1186 || c->type == CONSTANT_INT
1187 || c->type == CONSTANT_UINT);
1188 } else if(TYPE_IS_UINT(t)) {
1189 xassert(c->type == CONSTANT_UINT ||
1190 (c->type == CONSTANT_INT && c->i>=0));
1191 } else if(TYPE_IS_INT(t)) {
1192 xassert(c->type == CONSTANT_INT);
1193 } else if(TYPE_IS_BOOLEAN(t)) {
1194 xassert(c->type == CONSTANT_TRUE
1195 || c->type == CONSTANT_FALSE);
1199 static void check_override(memberinfo_t*m, int flags)
1203 if(m->parent == state->cls->info)
1204 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1206 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1207 if(m->access==ACCESS_PRIVATE)
1209 if(m->flags & FLAG_FINAL)
1210 syntaxerror("can't override final member %s", m->name);
1212 /* allow this. it's no issue.
1213 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1214 syntaxerror("can't override static member %s", m->name);*/
1216 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1217 syntaxerror("can't override non-static member %s with static declaration", m->name);
1219 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1220 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1221 if(m->kind == INFOTYPE_METHOD)
1222 syntaxerror("can't override without explicit 'override' declaration");
1224 syntaxerror("can't override '%s'", m->name);
1229 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1231 methodinfo_t*minfo = 0;
1232 namespace_t ns = modifiers2access(mod);
1235 minfo = methodinfo_register_global(ns.access, state->package, name);
1236 minfo->return_type = return_type;
1237 } else if(getset != KW_GET && getset != KW_SET) {
1239 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1241 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1243 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1244 minfo->return_type = return_type;
1245 // getslot on a member slot only returns "undefined", so no need
1246 // to actually store these
1247 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1249 //class getter/setter
1250 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1252 if(getset == KW_GET) {
1254 } else if(params->list && params->list->param && !params->list->next) {
1255 type = params->list->param->type;
1257 syntaxerror("setter function needs to take exactly one argument");
1258 // not sure wether to look into superclasses here, too
1259 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1261 if(minfo->kind!=INFOTYPE_VAR)
1262 syntaxerror("class already contains a method called '%s'", name);
1263 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1264 syntaxerror("class already contains a field called '%s'", name);
1265 if(minfo->subtype & gs)
1266 syntaxerror("getter/setter for '%s' already defined", name);
1267 /* make a setter or getter into a getset */
1268 minfo->subtype |= gs;
1271 FIXME: this check needs to be done in pass 2
1273 if((!minfo->return_type != !type) ||
1274 (minfo->return_type && type &&
1275 !strcmp(minfo->return_type->name, type->name))) {
1276 syntaxerror("different type in getter and setter: %s and %s",
1277 minfo->return_type?minfo->return_type->name:"*",
1278 type?type->name:"*");
1281 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1282 minfo->kind = INFOTYPE_VAR; //hack
1283 minfo->subtype = gs;
1284 minfo->return_type = type;
1287 /* can't assign a slot as getter and setter might have different slots */
1288 //minfo->slot = slot;
1290 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1291 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1292 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1297 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1299 //parserassert(state->method && state->method->info);
1301 methodstate_t*parent_method = state->method;
1304 return_type = 0; // not valid in pass 1
1308 state->new_vars = 1;
1309 state->allvars = dict_new();
1312 state->method = rfx_calloc(sizeof(methodstate_t));
1313 state->method->inner = 1;
1314 state->method->is_static = parent_method->is_static;
1315 state->method->variable_count = 0;
1316 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1318 NEW(methodinfo_t,minfo);
1319 minfo->kind = INFOTYPE_METHOD;
1320 minfo->access = ACCESS_PACKAGEINTERNAL;
1322 state->method->info = minfo;
1325 list_append(parent_method->innerfunctions, state->method);
1327 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1329 function_initvars(state->method, 1, params, 0, 1);
1333 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1334 state->method->variable_count = 0;
1335 parserassert(state->method);
1337 state->method->info->return_type = return_type;
1338 function_initvars(state->method, 1, params, 0, 1);
1342 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1343 params_t*params, classinfo_t*return_type)
1345 if(state->method && state->method->info) {
1346 syntaxerror("not able to start another method scope");
1349 state->new_vars = 1;
1350 state->allvars = dict_new();
1353 state->method = rfx_calloc(sizeof(methodstate_t));
1354 state->method->has_super = 0;
1355 state->method->is_static = mod->flags&FLAG_STATIC;
1358 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1360 state->method->is_global = 1;
1361 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1363 if(state->method->is_constructor)
1364 name = "__as3_constructor__";
1366 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1368 function_initvars(state->method, 1, params, mod->flags, 1);
1370 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1374 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1375 state->method->variable_count = 0;
1376 parserassert(state->method);
1379 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1380 check_override(m, mod->flags);
1384 state->cls->has_constructor |= state->method->is_constructor;
1387 function_initvars(state->method, 1, params, mod->flags, 1);
1391 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1392 params_t*params, classinfo_t*return_type, code_t*body)
1395 innerfunctions2vars(state->method);
1397 methodstate_list_t*ml = state->method->innerfunctions;
1399 dict_t*xvars = dict_new();
1402 methodstate_t*m = ml->methodstate;
1403 parserassert(m->inner);
1404 if(m->unresolved_variables) {
1405 dict_t*d = m->unresolved_variables;
1407 DICT_ITERATE_KEY(d, char*, id) {
1408 /* check parent method's variables */
1410 if((v=find_variable(state, id))) {
1411 m->uses_parent_function = 1;
1412 state->method->uses_slots = 1;
1413 dict_put(xvars, id, 0);
1416 dict_destroy(m->unresolved_variables);m->unresolved_variables = 0;
1421 if(state->method->uses_slots) {
1422 state->method->slots = dict_new();
1424 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1425 if(!name) syntaxerror("internal error");
1426 if(v->index && dict_contains(xvars, name)) {
1429 if(v->is_inner_method) {
1430 v->is_inner_method->is_a_slot = i;
1433 dict_put(state->method->slots, name, v);
1436 state->method->uses_slots = i;
1437 dict_destroy(state->vars);state->vars = 0;
1438 parserassert(state->new_vars);
1439 dict_destroy(state->allvars);state->allvars = 0;
1446 /*if(state->method->uses_parent_function){
1447 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1452 multiname_t*type2 = sig2mname(return_type);
1454 if(state->method->inner) {
1455 f = state->method->abc;
1456 abc_method_init(f, global->file, type2, 1);
1457 } else if(state->method->is_constructor) {
1458 f = abc_class_getconstructor(state->cls->abc, type2);
1459 } else if(!state->method->is_global) {
1460 namespace_t ns = modifiers2access(mod);
1461 multiname_t mname = {QNAME, &ns, 0, name};
1462 if(mod->flags&FLAG_STATIC)
1463 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1465 f = abc_class_method(state->cls->abc, type2, &mname);
1466 slot = f->trait->slot_id;
1468 namespace_t mname_ns = {state->method->info->access, state->package};
1469 multiname_t mname = {QNAME, &mname_ns, 0, name};
1471 f = abc_method_new(global->file, type2, 1);
1472 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1473 //abc_code_t*c = global->init->method->body->code;
1475 //flash doesn't seem to allow us to access function slots
1476 //state->method->info->slot = slot;
1478 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1479 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1480 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1481 if(params->varargs) f->flags |= METHOD_NEED_REST;
1482 if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
1486 for(p=params->list;p;p=p->next) {
1487 if(params->varargs && !p->next) {
1488 break; //varargs: omit last parameter in function signature
1490 multiname_t*m = sig2mname(p->param->type);
1491 list_append(f->parameters, m);
1492 if(p->param->value) {
1493 check_constant_against_type(p->param->type, p->param->value);
1494 opt=1;list_append(f->optional_parameters, p->param->value);
1496 syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
1499 if(state->method->slots) {
1500 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1502 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1503 multiname_t*type = sig2mname(v->type);
1504 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1505 t->slot_id = v->index;
1510 check_code_for_break(body);
1512 /* Seems this works now.
1513 if(state->method->exceptions && state->method->uses_slots) {
1514 as3_warning("try/catch and activation not supported yet within the same method");
1518 f->body->code = body;
1519 f->body->exceptions = state->method->exceptions;
1520 } else { //interface
1522 syntaxerror("interface methods can't have a method body");
1532 void breakjumpsto(code_t*c, char*name, code_t*jump)
1535 if(c->opcode == OPCODE___BREAK__) {
1536 string_t*name2 = c->data[0];
1537 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1538 c->opcode = OPCODE_JUMP;
1545 void continuejumpsto(code_t*c, char*name, code_t*jump)
1548 if(c->opcode == OPCODE___CONTINUE__) {
1549 string_t*name2 = c->data[0];
1550 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1551 c->opcode = OPCODE_JUMP;
1559 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1564 return abc_coerce_a(c);
1568 // cast an "any" type to a specific type. subject to
1569 // runtime exceptions
1570 return abc_coerce2(c, &m);
1573 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1574 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1575 // allow conversion between number types
1576 if(TYPE_IS_UINT(to))
1577 return abc_convert_u(c);
1578 else if(TYPE_IS_INT(to))
1579 return abc_convert_i(c);
1580 else if(TYPE_IS_NUMBER(to))
1581 return abc_convert_d(c);
1582 return abc_coerce2(c, &m);
1585 if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
1588 if(TYPE_IS_BOOLEAN(to))
1589 return abc_convert_b(c);
1590 if(TYPE_IS_STRING(to))
1591 return abc_convert_s(c);
1592 if(TYPE_IS_OBJECT(to))
1593 return abc_coerce2(c, &m);
1594 if(TYPE_IS_OBJECT(from) && TYPE_IS_XMLLIST(to))
1595 return abc_coerce2(c, &m);
1596 if(TYPE_IS_OBJECT(from) && TYPE_IS_ARRAY(to))
1597 return abc_coerce2(c, &m);
1599 classinfo_t*supertype = from;
1601 if(supertype == to) {
1602 /* target type is one of from's superclasses.
1603 (not sure we need this coerce - as far as the verifier
1604 is concerned, object==object (i think) */
1605 return abc_coerce2(c, &m);
1608 while(supertype->interfaces[t]) {
1609 if(supertype->interfaces[t]==to) {
1610 // target type is one of from's interfaces
1611 return abc_coerce2(c, &m);
1615 supertype = supertype->superclass;
1617 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1619 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1621 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1624 as3_error("can't convert type %s%s%s to %s%s%s",
1625 from->package, from->package[0]?".":"", from->name,
1626 to->package, to->package[0]?".":"", to->name);
1630 code_t* coerce_to_type(code_t*c, classinfo_t*t)
1633 return abc_coerce_a(c);
1634 } else if(TYPE_IS_STRING(t)) {
1635 return abc_coerce_s(c);
1638 return abc_coerce2(c, &m);
1642 char is_pushundefined(code_t*c)
1644 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1647 static const char* get_package_from_name(const char*name)
1649 /* try explicit imports */
1650 dictentry_t* e = dict_get_slot(state->imports, name);
1652 if(!strcmp(e->key, name)) {
1653 slotinfo_t*c = (slotinfo_t*)e->data;
1654 if(c) return c->package;
1660 static namespace_list_t*get_current_imports()
1662 namespace_list_t*searchlist = 0;
1664 list_append(searchlist, namespace_new_package(state->package));
1666 import_list_t*l = state->wildcard_imports;
1668 namespace_t*ns = namespace_new_package(l->import->package);
1669 list_append(searchlist, ns);
1672 list_append(searchlist, namespace_new_package(""));
1673 list_append(searchlist, namespace_new_package(internal_filename_package));
1677 static slotinfo_t* find_class(const char*name)
1681 c = registry_find(state->package, name);
1684 /* try explicit imports */
1685 dictentry_t* e = dict_get_slot(state->imports, name);
1688 if(!strcmp(e->key, name)) {
1689 c = (slotinfo_t*)e->data;
1695 /* try package.* imports */
1696 import_list_t*l = state->wildcard_imports;
1698 //printf("does package %s contain a class %s?\n", l->import->package, name);
1699 c = registry_find(l->import->package, name);
1704 /* try global package */
1705 c = registry_find("", name);
1708 /* try local "filename" package */
1709 c = registry_find(internal_filename_package, name);
1714 typedcode_t push_class(slotinfo_t*a)
1719 if(a->access == ACCESS_PACKAGEINTERNAL &&
1720 strcmp(a->package, state->package) &&
1721 strcmp(a->package, internal_filename_package)
1723 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1724 infotypename(a), a->name, a->package, state->package);
1728 if(a->kind != INFOTYPE_CLASS) {
1730 x.c = abc_findpropstrict2(x.c, &m);
1731 x.c = abc_getproperty2(x.c, &m);
1732 if(a->kind == INFOTYPE_METHOD) {
1733 methodinfo_t*f = (methodinfo_t*)a;
1734 x.t = TYPE_FUNCTION(f);
1736 varinfo_t*v = (varinfo_t*)a;
1741 if(state->cls && state->method == state->cls->static_init) {
1742 /* we're in the static initializer.
1743 record the fact that we're using this class here */
1744 parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
1746 classinfo_t*c = (classinfo_t*)a;
1748 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1749 x.c = abc_getglobalscope(x.c);
1750 x.c = abc_getslot(x.c, c->slot);
1753 x.c = abc_getlex2(x.c, &m);
1755 x.t = TYPE_CLASS(c);
1761 char is_break_or_jump(code_t*c)
1765 if(c->opcode == OPCODE_JUMP ||
1766 c->opcode == OPCODE___BREAK__ ||
1767 c->opcode == OPCODE___CONTINUE__ ||
1768 c->opcode == OPCODE_THROW ||
1769 c->opcode == OPCODE_RETURNVOID ||
1770 c->opcode == OPCODE_RETURNVALUE) {
1776 #define IS_FINALLY_TARGET(op) \
1777 ((op) == OPCODE___CONTINUE__ || \
1778 (op) == OPCODE___BREAK__ || \
1779 (op) == OPCODE_RETURNVOID || \
1780 (op) == OPCODE_RETURNVALUE || \
1781 (op) == OPCODE___RETHROW__)
1783 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1785 #define NEED_EXTRA_STACK_ARG
1786 code_t*finally_label = abc_nop(0);
1787 NEW(lookupswitch_t, l);
1793 code_t*prev = i->prev;
1794 if(IS_FINALLY_TARGET(i->opcode)) {
1797 if(i->opcode == OPCODE___RETHROW__ ||
1798 i->opcode == OPCODE_RETURNVALUE) {
1799 if(i->opcode == OPCODE___RETHROW__)
1800 i->opcode = OPCODE_THROW;
1802 p = abc_coerce_a(p);
1803 p = abc_setlocal(p, tempvar);
1805 p = abc_pushbyte(p, count++);
1806 p = abc_jump(p, finally_label);
1807 code_t*target = p = abc_label(p);
1808 #ifdef NEED_EXTRA_STACK_ARG
1812 p = abc_getlocal(p, tempvar);
1815 p->next = i;i->prev = p;
1816 list_append(l->targets, target);
1822 c = abc_pushbyte(c, -1);
1823 c = code_append(c, finally_label);
1824 c = code_append(c, finally);
1826 #ifdef NEED_EXTRA_STACK_ARG
1829 c = abc_lookupswitch(c, l);
1830 c = l->def = abc_label(c);
1831 #ifdef NEED_EXTRA_STACK_ARG
1838 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1842 code_t*prev = i->prev;
1843 if(IS_FINALLY_TARGET(i->opcode)) {
1844 if(i->opcode == OPCODE___RETHROW__)
1845 i->opcode = OPCODE_THROW;
1846 code_t*end = code_dup(finally);
1847 code_t*start = code_start(end);
1848 if(prev) prev->next = start;
1855 return code_append(c, finally);
1858 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1864 int num_insertion_points=0;
1866 if(IS_FINALLY_TARGET(i->opcode))
1867 num_insertion_points++;
1874 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1879 int simple_version_cost = (1+num_insertion_points)*code_size;
1880 int lookup_version_cost = 4*num_insertion_points + 5;
1882 if(cantdup || simple_version_cost > lookup_version_cost) {
1883 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1884 return insert_finally_lookup(c, finally, tempvar);
1886 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1887 return insert_finally_simple(c, finally, tempvar);
1891 #define PASS1 }} if(as3_pass == 1) {{
1892 #define PASS1END }} if(as3_pass == 2) {{
1893 #define PASS2 }} if(as3_pass == 2) {{
1894 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1895 #define PASS12END }} if(as3_pass == 2) {{
1896 #define PASS_ALWAYS }} {{
1902 /* ------------ code blocks / statements ---------------- */
1904 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1906 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1907 PROGRAM_CODE_LIST: PROGRAM_CODE
1908 | PROGRAM_CODE_LIST PROGRAM_CODE
1910 PROGRAM_CODE: PACKAGE_DECLARATION
1911 | INTERFACE_DECLARATION
1913 | FUNCTION_DECLARATION
1916 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1919 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1920 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1921 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1923 INPACKAGE_CODE: INTERFACE_DECLARATION
1925 | FUNCTION_DECLARATION
1928 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1931 MAYBECODE: CODE {$$=$1;}
1932 MAYBECODE: {$$=code_new();}
1934 CODE: CODE CODEPIECE {
1935 $$=code_append($1,$2);
1937 CODE: CODEPIECE {$$=$1;}
1939 // code which may appear outside of methods
1940 CODE_STATEMENT: DEFAULT_NAMESPACE
1941 CODE_STATEMENT: IMPORT
1943 CODE_STATEMENT: FOR_IN
1944 CODE_STATEMENT: WHILE
1945 CODE_STATEMENT: DO_WHILE
1946 CODE_STATEMENT: SWITCH
1948 CODE_STATEMENT: WITH
1950 CODE_STATEMENT: VOIDEXPRESSION
1951 CODE_STATEMENT: USE_NAMESPACE
1952 CODE_STATEMENT: NAMESPACE_DECLARATION
1953 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1954 CODE_STATEMENT: '{' '}' {$$=0;}
1956 // code which may appear in methods (includes the above)
1957 CODEPIECE: ';' {$$=0;}
1958 CODEPIECE: CODE_STATEMENT
1959 CODEPIECE: VARIABLE_DECLARATION
1964 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
1974 //CODEBLOCK : '{' CODE '}' {$$=$2;}
1975 //CODEBLOCK : '{' '}' {$$=0;}
1976 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1977 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1979 /* ------------ package init code ------------------- */
1981 PACKAGE_INITCODE: CODE_STATEMENT {
1982 code_t**cc = &global->init->method->body->code;
1983 *cc = code_append(*cc, $1);
1986 /* ------------ conditional compilation ------------- */
1988 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
1991 char*key = concat3($1,"::",$3);
1992 if(!definitions || !dict_contains(definitions, key)) {
1998 /* ------------ variables --------------------------- */
2001 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
2007 MAYBEEXPRESSION : '=' E {$$=$2;}
2008 | {$$=mkdummynode();}
2010 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2011 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2013 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2014 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2016 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2019 if(variable_exists($1))
2020 syntaxerror("Variable %s already defined", $1);
2022 new_variable($1, 0, 1, 0);
2027 if(state->method->uses_slots) {
2028 variable_t* v = find_slot(state, $1);
2030 // this variable is stored in a slot
2038 index = new_variable($1, $2, 1, 0);
2041 $$ = slot?abc_getscopeobject(0, 1):0;
2043 typedcode_t v = node_read($3);
2044 if(!is_subtype_of(v.t, $2)) {
2045 syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
2048 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2049 $$ = code_append($$, v.c);
2050 $$ = converttype($$, v.t, $2);
2053 $$ = defaultvalue($$, $2);
2056 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2057 $$ = code_append($$, v.c);
2058 $$ = abc_coerce_a($$);
2060 // don't do anything
2068 $$ = abc_setslot($$, index);
2070 $$ = abc_setlocal($$, index);
2074 /* ------------ control flow ------------------------- */
2076 MAYBEELSE: %prec below_else {$$ = code_new();}
2077 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2078 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2080 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2083 $$ = code_append($$, $4.c);
2084 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2086 $$ = code_append($$, $6);
2088 myjmp = $$ = abc_jump($$, 0);
2090 myif->branch = $$ = abc_nop($$);
2092 $$ = code_append($$, $7);
2093 myjmp->branch = $$ = abc_nop($$);
2099 FOR_INIT : {$$=code_new();}
2100 FOR_INIT : VARIABLE_DECLARATION
2101 FOR_INIT : VOIDEXPRESSION
2103 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2104 // (I don't see any easy way to revolve this conflict otherwise, as we
2105 // can't touch VAR_READ without upsetting the precedence about "return")
2106 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2107 PASS1 $$=$2;new_variable($2,0,1,0);
2108 PASS2 $$=$2;new_variable($2,$3,1,0);
2110 FOR_IN_INIT : T_IDENTIFIER {
2115 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2116 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2118 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2119 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2121 $$ = code_append($$, $2);
2122 code_t*loopstart = $$ = abc_label($$);
2123 $$ = code_append($$, $4.c);
2124 code_t*myif = $$ = abc_iffalse($$, 0);
2125 $$ = code_append($$, $8);
2126 code_t*cont = $$ = abc_nop($$);
2127 $$ = code_append($$, $6);
2128 $$ = abc_jump($$, loopstart);
2129 code_t*out = $$ = abc_nop($$);
2130 breakjumpsto($$, $1.name, out);
2131 continuejumpsto($$, $1.name, cont);
2138 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2139 variable_t*var = find_variable(state, $2);
2141 syntaxerror("variable %s not known in this scope", $2);
2144 char*tmp1name = concat2($2, "__tmp1__");
2145 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2146 char*tmp2name = concat2($2, "__array__");
2147 int array = new_variable(tmp1name, 0, 0, 0);
2150 $$ = code_append($$, $4.c);
2151 $$ = abc_coerce_a($$);
2152 $$ = abc_setlocal($$, array);
2153 $$ = abc_pushbyte($$, 0);
2154 $$ = abc_setlocal($$, it);
2156 code_t*loopstart = $$ = abc_label($$);
2158 $$ = abc_hasnext2($$, array, it);
2159 code_t*myif = $$ = abc_iffalse($$, 0);
2160 $$ = abc_getlocal($$, array);
2161 $$ = abc_getlocal($$, it);
2163 $$ = abc_nextname($$);
2165 $$ = abc_nextvalue($$);
2166 $$ = converttype($$, 0, var->type);
2167 $$ = abc_setlocal($$, var->index);
2169 $$ = code_append($$, $6);
2170 $$ = abc_jump($$, loopstart);
2172 code_t*out = $$ = abc_nop($$);
2173 breakjumpsto($$, $1.name, out);
2174 continuejumpsto($$, $1.name, loopstart);
2186 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2190 code_t*myjmp = $$ = abc_jump($$, 0);
2191 code_t*loopstart = $$ = abc_label($$);
2192 $$ = code_append($$, $6);
2193 code_t*cont = $$ = abc_nop($$);
2194 myjmp->branch = cont;
2195 $$ = code_append($$, $4.c);
2196 $$ = abc_iftrue($$, loopstart);
2197 code_t*out = $$ = abc_nop($$);
2198 breakjumpsto($$, $1, out);
2199 continuejumpsto($$, $1, cont);
2205 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2207 code_t*loopstart = $$ = abc_label($$);
2208 $$ = code_append($$, $3);
2209 code_t*cont = $$ = abc_nop($$);
2210 $$ = code_append($$, $6.c);
2211 $$ = abc_iftrue($$, loopstart);
2212 code_t*out = $$ = abc_nop($$);
2213 breakjumpsto($$, $1, out);
2214 continuejumpsto($$, $1, cont);
2220 BREAK : "break" %prec prec_none {
2221 $$ = abc___break__(0, "");
2223 BREAK : "break" T_IDENTIFIER {
2224 $$ = abc___break__(0, $2);
2226 CONTINUE : "continue" %prec prec_none {
2227 $$ = abc___continue__(0, "");
2229 CONTINUE : "continue" T_IDENTIFIER {
2230 $$ = abc___continue__(0, $2);
2233 MAYBE_CASE_LIST : {$$=0;}
2234 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2235 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2236 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2237 CASE_LIST: CASE {$$=$1;}
2238 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2240 CASE: "case" E ':' MAYBECODE {
2241 $$ = abc_getlocal(0, state->switch_var);
2242 $$ = code_append($$, node_read($2).c);
2243 code_t*j = $$ = abc_ifne($$, 0);
2244 $$ = code_append($$, $4);
2245 if($$->opcode != OPCODE___BREAK__) {
2246 $$ = abc___fallthrough__($$, "");
2248 code_t*e = $$ = abc_nop($$);
2251 DEFAULT: "default" ':' MAYBECODE {
2254 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2255 $$ = node_read($4).c;
2256 $$ = abc_setlocal($$, state->switch_var);
2257 $$ = code_append($$, $7);
2259 code_t*out = $$ = abc_kill($$, state->switch_var);
2260 breakjumpsto($$, $1, out);
2262 code_t*c = $$,*lastblock=0;
2264 if(c->opcode == OPCODE_IFNE) {
2265 if(!c->next) syntaxerror("internal error in fallthrough handling");
2267 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2269 c->opcode = OPCODE_JUMP;
2270 c->branch = lastblock;
2272 /* fall through end of switch */
2273 c->opcode = OPCODE_NOP;
2283 /* ------------ try / catch /finally ---------------- */
2285 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2286 state->exception_name=$3;
2287 PASS1 new_variable($3, 0, 0, 0);
2288 PASS2 new_variable($3, $4, 0, 0);
2291 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2292 multiname_t name = {QNAME, &name_ns, 0, $3};
2294 NEW(abc_exception_t, e)
2295 e->exc_type = sig2mname($4);
2296 e->var_name = multiname_clone(&name);
2300 int i = find_variable_safe(state, $3)->index;
2301 e->target = c = abc_nop(0);
2302 c = abc_setlocal(c, i);
2303 c = code_append(c, code_dup(state->method->scope_code));
2304 c = code_append(c, $8);
2310 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2315 NEW(abc_exception_t, e)
2316 e->exc_type = 0; //all exceptions
2317 e->var_name = 0; //no name
2320 e->to = code_append(e->to, $4);
2326 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2327 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2328 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2329 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2333 list_append($$.l,$2);
2334 $$.finally = $2->to;$2->to=0;
2337 CATCH_FINALLY_LIST: FINALLY {
2341 list_append($$.l,$1);
2342 $$.finally = $1->to;$1->to=0;
2346 TRY : "try" '{' {PASS12 new_state();
2347 state->method->has_exceptions=1;
2348 state->method->late_binding=1;//for invariant scope_code
2349 } MAYBECODE '}' CATCH_FINALLY_LIST {
2350 code_t*out = abc_nop(0);
2352 code_t*start = abc_nop(0);
2353 $$ = code_append(start, $4);
2354 if(!is_break_or_jump($4)) {
2355 $$ = abc_jump($$, out);
2357 code_t*end = $$ = abc_nop($$);
2361 tmp = new_variable("__finally__", 0, 0, 0);
2363 abc_exception_list_t*l = $6.l;
2366 abc_exception_t*e = l->abc_exception;
2368 $$ = code_append($$, e->target);
2369 $$ = abc_jump($$, out);
2371 parserassert((ptroff_t)$6.finally);
2373 e->target = $$ = abc_nop($$);
2374 $$ = code_append($$, code_dup(state->method->scope_code));
2375 $$ = abc___rethrow__($$);
2383 $$ = code_append($$, out);
2385 $$ = insert_finally($$, $6.finally, tmp);
2387 list_concat(state->method->exceptions, $6.l);
2393 /* ------------ throw ------------------------------- */
2395 THROW : "throw" EXPRESSION {
2399 THROW : "throw" %prec prec_none {
2400 if(!state->exception_name)
2401 syntaxerror("re-throw only possible within a catch block");
2402 variable_t*v = find_variable(state, state->exception_name);
2404 $$=abc_getlocal($$, v->index);
2408 /* ------------ with -------------------------------- */
2410 WITH_HEAD : "with" '(' EXPRESSION ')' {
2412 if(state->method->has_exceptions) {
2413 int v = alloc_local();
2414 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2415 state->method->scope_code = abc_pushwith(state->method->scope_code);
2420 WITH : WITH_HEAD CODEBLOCK {
2421 /* remove getlocal;pushwith from scope code again */
2422 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2425 if(state->method->has_exceptions) {
2427 $$ = abc_setlocal($$, $1.number);
2429 $$ = abc_pushwith($$);
2430 $$ = code_append($$, $2);
2431 $$ = abc_popscope($$);
2435 /* ------------ packages and imports ---------------- */
2437 X_IDENTIFIER: T_IDENTIFIER
2438 | "package" {PASS12 $$="package";}
2439 | "namespace" {PASS12 $$="namespace";}
2440 | T_NAMESPACE {PASS12 $$=$1;}
2442 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2443 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2445 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2446 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2447 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2448 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2451 static void state_has_imports()
2453 state->wildcard_imports = list_clone(state->wildcard_imports);
2454 state->imports = dict_clone(state->imports);
2455 state->has_own_imports = 1;
2457 static void import_toplevel(const char*package)
2459 char* s = strdup(package);
2461 dict_put(state->import_toplevel_packages, s, 0);
2462 char*x = strrchr(s, '.');
2470 IMPORT : "import" PACKAGEANDCLASS {
2472 slotinfo_t*s = registry_find($2->package, $2->name);
2473 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2474 as3_schedule_class($2->package, $2->name);
2478 syntaxerror("Couldn't import class\n");
2479 state_has_imports();
2480 dict_put(state->imports, c->name, c);
2481 import_toplevel(c->package);
2484 IMPORT : "import" PACKAGE '.' '*' {
2486 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2487 as3_schedule_package($2);
2492 state_has_imports();
2493 list_append(state->wildcard_imports, i);
2494 import_toplevel(i->package);
2498 /* ------------ classes and interfaces (header) -------------- */
2500 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2501 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2502 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2503 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2505 $$.flags=$1.flags|$2.flags;
2506 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2507 $$.ns=$1.ns?$1.ns:$2.ns;
2510 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2511 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2512 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2513 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2514 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2515 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2516 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2517 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2518 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2519 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2523 EXTENDS : {PASS12 $$=0;}
2524 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2526 EXTENDS_LIST : {PASS12 $$=list_new();}
2527 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2529 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2530 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2532 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2533 EXTENDS IMPLEMENTS_LIST
2534 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2536 '}' {PASS12 endclass();$$=0;}
2538 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2540 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2541 startclass(&$1,$3,0,$4);}
2542 MAYBE_INTERFACE_BODY
2543 '}' {PASS12 endclass();$$=0;}
2545 /* ------------ classes and interfaces (body) -------------- */
2548 MAYBE_CLASS_BODY : CLASS_BODY
2549 CLASS_BODY : CLASS_BODY_ITEM
2550 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2551 CLASS_BODY_ITEM : ';'
2552 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2553 CLASS_BODY_ITEM : SLOT_DECLARATION
2554 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2556 CLASS_BODY_ITEM : CODE_STATEMENT {
2557 code_t*c = state->cls->static_init->header;
2558 c = code_append(c, $1);
2559 state->cls->static_init->header = c;
2562 MAYBE_INTERFACE_BODY :
2563 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2564 INTERFACE_BODY : IDECLARATION
2565 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2567 IDECLARATION : "var" T_IDENTIFIER {
2568 syntaxerror("variable declarations not allowed in interfaces");
2570 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2572 $1.flags |= FLAG_PUBLIC;
2573 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2574 syntaxerror("invalid method modifiers: interface methods always need to be public");
2576 startfunction(&$1,$3,$4,&$6,$8);
2577 endfunction(&$1,$3,$4,&$6,$8, 0);
2578 list_deep_free($6.list);
2581 /* ------------ classes and interfaces (body, slots ) ------- */
2584 static int slotstate_varconst = 0;
2585 static modifiers_t*slotstate_flags = 0;
2586 static void setslotstate(modifiers_t* flags, int varconst)
2588 slotstate_varconst = varconst;
2589 slotstate_flags = flags;
2592 if(flags->flags&FLAG_STATIC) {
2593 state->method = state->cls->static_init;
2595 state->method = state->cls->init;
2598 // reset to "default" state (all in class code is static by default) */
2599 state->method = state->cls->static_init;
2602 parserassert(state->method);
2605 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2607 int flags = modifiers->flags;
2608 namespace_t ns = modifiers2access(modifiers);
2611 multiname_t mname = {QNAME, &ns, 0, name};
2613 trait_list_t**traits;
2617 ns.name = state->package;
2618 traits = &global->init->traits;
2619 code = &global->init->method->body->code;
2620 } else if(flags&FLAG_STATIC) {
2622 traits = &state->cls->abc->static_traits;
2623 code = &state->cls->static_init->header;
2625 // instance variable
2626 traits = &state->cls->abc->traits;
2627 code = &state->cls->init->header;
2629 if(ns.access == ACCESS_PROTECTED) {
2630 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2636 *m = *multiname_clone(&mname);
2638 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2642 VARCONST: "var" | "const"
2644 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2646 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2647 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2649 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2652 int flags = slotstate_flags->flags;
2653 namespace_t ns = modifiers2access(slotstate_flags);
2657 varinfo_t* info = 0;
2659 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2661 check_override(i, flags);
2663 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2665 slotinfo_t*i = registry_find(state->package, $1);
2667 syntaxerror("package %s already contains '%s'", state->package, $1);
2669 if(ns.name && ns.name[0]) {
2670 syntaxerror("namespaces not allowed on package-level variables");
2672 info = varinfo_register_global(ns.access, state->package, $1);
2676 info->flags = flags;
2678 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2682 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2686 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2690 t->type_name = multiname_clone(&m);
2692 info->slot = t->slot_id;
2694 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2695 FIXME: is there a way to use slots and still don't have conflicting overrides?
2697 info->slot = t->slot_id = 0;
2699 constant_t cval = $3->type->eval($3);
2700 if(cval.type!=CONSTANT_UNKNOWN) {
2701 /* compile time constant */
2702 t->value = malloc(sizeof(constant_t));
2703 memcpy(t->value, &cval, sizeof(constant_t));
2704 info->value = constant_clone(t->value);
2706 typedcode_t v = node_read($3);
2707 /* initalization code (if needed) */
2709 if(v.c && !is_pushundefined(v.c)) {
2710 c = abc_getlocal_0(c);
2711 c = code_append(c, v.c);
2712 c = converttype(c, v.t, $2);
2714 c = abc_initproperty2(c, &mname);
2716 c = abc_setslot(c, t->slot_id);
2719 *code = code_append(*code, c);
2722 if(slotstate_varconst==KW_CONST) {
2723 t->kind= TRAIT_CONST;
2724 info->flags |= FLAG_CONST;
2731 /* ------------ constants -------------------------------------- */
2733 MAYBECONSTANT: {$$=0;}
2734 MAYBECONSTANT: '=' E {
2735 $$ = malloc(sizeof(constant_t));
2736 *$$ = node_eval($2);
2737 if($$->type == CONSTANT_UNKNOWN) {
2738 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2742 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2743 CONSTANT : T_INT {$$ = constant_new_int($1);}
2745 $$ = constant_new_uint($1);
2747 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2748 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2749 CONSTANT : "true" {$$ = constant_new_true($1);}
2750 CONSTANT : "false" {$$ = constant_new_false($1);}
2751 CONSTANT : "null" {$$ = constant_new_null($1);}
2752 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2753 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2756 CONSTANT : T_IDENTIFIER {
2757 if(!strcmp($1, "NaN")) {
2758 $$ = constant_new_float(__builtin_nan(""));
2760 as3_warning("Couldn't evaluate constant value of %s", $1);
2761 $$ = constant_new_null($1);
2765 /* ---------------------------xml ------------------------------ */
2768 static int xml_level = 0;
2773 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2774 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2775 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2777 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2779 as3_warning("xml string substitution not yet supported");
2781 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2783 as3_warning("xml string substitution not yet supported");
2786 XMLTEXT : XMLTEXT XMLEXPR1 {
2787 $$ = concat2($1, "{...}");
2789 XMLTEXT : XMLTEXT T_STRING {$$=concat2($1, string_cstr(&$2));}
2790 XMLTEXT : XMLTEXT '>' {$$=concat2($1, ">");}
2792 XML2 : XMLNODE XMLTEXT {$$=concat2($1,$2);}
2793 XML2 : XML2 XMLNODE XMLTEXT {$$=concat3($1,$2,$3);free($1);free($2);free($3);}
2795 XML_ID_OR_EXPR: T_IDENTIFIER {$$=$1;}
2796 XML_ID_OR_EXPR: XMLEXPR2 {$$=$1;}
2798 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2799 $$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2800 free($2);free($3);free($5);free($8);
2802 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2803 $$ = allocprintf("<%s%s/>", $2, $3);
2805 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2806 $$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2807 free($2);free($3);free($5);free($6);free($9);
2810 MAYBE_XMLATTRIBUTES: {$$=strdup("");}
2811 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {$$=concat2(" ",$1);}
2812 XMLATTRIBUTES: XMLATTRIBUTE {$$=$1;}
2813 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {$$=concat3($1," ",$2);free($1);free($2);}
2815 XMLATTRIBUTE: XMLEXPR2 {
2816 $$ = strdup("{...}");
2818 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2819 char* str = string_cstr(&$3);
2820 $$ = concat2("{...}=",str);
2822 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2823 $$ = strdup("{...}={...}");
2825 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2826 $$ = concat2($1,"={...}");
2828 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2829 char* str = string_cstr(&$3);
2830 $$=allocprintf("%s=%s", $1,str);
2832 free($1);free((char*)$3.str);
2835 /* ------------ classes and interfaces (body, functions) ------- */
2837 // non-vararg version
2840 memset(&$$,0,sizeof($$));
2842 MAYBE_PARAM_LIST: PARAM_LIST {
2848 MAYBE_PARAM_LIST: "..." PARAM {
2850 memset(&$$,0,sizeof($$));
2852 list_append($$.list, $2);
2854 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2858 list_append($$.list, $4);
2862 PARAM_LIST: PARAM_LIST ',' PARAM {
2865 list_append($$.list, $3);
2869 memset(&$$,0,sizeof($$));
2870 list_append($$.list, $1);
2873 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2875 $$ = rfx_calloc(sizeof(param_t));
2881 PARAM: T_IDENTIFIER MAYBECONSTANT {
2883 $$ = rfx_calloc(sizeof(param_t));
2885 $$->type = TYPE_ANY;
2893 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2894 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2897 endfunction(&$1,$3,$4,&$6,0,0);
2899 if(!state->method->info) syntaxerror("internal error");
2901 code_t*c = method_header(state->method);
2902 c = wrap_function(c, 0, $11);
2904 endfunction(&$1,$3,$4,&$6,$8,c);
2906 list_deep_free($6.list);
2910 MAYBE_IDENTIFIER: T_IDENTIFIER
2911 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2912 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2913 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2916 endfunction(0,0,$2,&$4,0,0);
2918 methodinfo_t*f = state->method->info;
2919 if(!f || !f->kind) syntaxerror("internal error");
2921 code_t*c = method_header(state->method);
2922 c = wrap_function(c, 0, $9);
2924 int index = state->method->var_index;
2925 endfunction(0,0,$2,&$4,$6,c);
2927 $$.c = abc_getlocal(0, index);
2928 $$.t = TYPE_FUNCTION(f);
2930 PASS12 list_deep_free($4.list);
2934 /* ------------- package + class ids --------------- */
2936 CLASS: X_IDENTIFIER {
2937 PASS1 NEW(unresolvedinfo_t,c);
2938 memset(c, 0, sizeof(*c));
2939 c->kind = INFOTYPE_UNRESOLVED;
2941 c->package = get_package_from_name($1);
2943 c->nsset = get_current_imports();
2944 /* make the compiler look for this class in the current directory,
2946 as3_schedule_class_noerror(state->package, $1);
2948 $$ = (classinfo_t*)c;
2950 slotinfo_t*s = find_class($1);
2951 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2952 $$ = (classinfo_t*)s;
2955 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2956 PASS1 NEW(unresolvedinfo_t,c);
2957 memset(c, 0, sizeof(*c));
2958 c->kind = INFOTYPE_UNRESOLVED;
2961 $$ = (classinfo_t*)c;
2963 slotinfo_t*s = registry_find($1, $3);
2964 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2966 $$ = (classinfo_t*)s;
2969 CLASS_SPEC: PACKAGEANDCLASS
2972 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2973 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2975 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2976 | '*' {PASS12 $$=TYPE_ANY;}
2977 | "void" {PASS12 $$=TYPE_VOID;}
2979 | "String" {$$=registry_getstringclass();}
2980 | "int" {$$=registry_getintclass();}
2981 | "uint" {$$=registry_getuintclass();}
2982 | "Boolean" {$$=registry_getbooleanclass();}
2983 | "Number" {$$=registry_getnumberclass();}
2986 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2987 MAYBETYPE: {PASS12 $$=0;}
2989 /* ----------function calls, delete, constructor calls ------ */
2991 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
2992 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2994 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
2995 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2996 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2998 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3002 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3003 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3004 $$.number= $1.number+1;
3005 $$.cc = code_append($1.cc, $2.c);
3009 NEW : "new" E XX MAYBE_PARAM_VALUES {
3010 typedcode_t v = node_read($2);
3012 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3014 code_t*paramcode = $4.cc;
3015 if($$.c->opcode == OPCODE_GETPROPERTY) {
3016 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3017 $$.c = code_cutlast($$.c);
3018 $$.c = code_append($$.c, paramcode);
3019 $$.c = abc_constructprop2($$.c, name, $4.number);
3020 multiname_destroy(name);
3021 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3023 classinfo_t*c = v.t->data;
3025 $$.c = abc_findpropstrict2(0, &m);
3026 $$.c = code_append($$.c, paramcode);
3027 $$.c = abc_constructprop2($$.c, &m, $4.number);
3028 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3029 int slot = (int)(ptroff_t)$$.c->data[0];
3030 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3031 multiname_t*name = t->name;
3032 $$.c = code_cutlast($$.c);
3033 $$.c = code_append($$.c, paramcode);
3034 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3036 $$.c = code_append($$.c, paramcode);
3037 $$.c = abc_construct($$.c, $4.number);
3041 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3044 $$.c = abc_coerce_a($$.c);
3049 /* TODO: use abc_call (for calling local variables),
3050 abc_callstatic (for calling own methods)
3053 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3055 typedcode_t v = node_read($1);
3057 if($$.c->opcode == OPCODE_COERCE_A) {
3058 $$.c = code_cutlast($$.c);
3060 code_t*paramcode = $3.cc;
3063 if($$.c->opcode == OPCODE_GETPROPERTY) {
3064 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3065 $$.c = code_cutlast($$.c);
3066 $$.c = code_append($$.c, paramcode);
3067 $$.c = abc_callproperty2($$.c, name, $3.number);
3068 multiname_destroy(name);
3069 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3070 int slot = (int)(ptroff_t)$$.c->data[0];
3071 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3072 if(t->kind!=TRAIT_METHOD) {
3073 //ok: flash allows to assign closures to members.
3075 multiname_t*name = t->name;
3076 $$.c = code_cutlast($$.c);
3077 $$.c = code_append($$.c, paramcode);
3078 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3079 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3080 } else if($$.c->opcode == OPCODE_GETSUPER) {
3081 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3082 $$.c = code_cutlast($$.c);
3083 $$.c = code_append($$.c, paramcode);
3084 $$.c = abc_callsuper2($$.c, name, $3.number);
3085 multiname_destroy(name);
3087 $$.c = abc_getglobalscope($$.c);
3088 $$.c = code_append($$.c, paramcode);
3089 $$.c = abc_call($$.c, $3.number);
3092 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3093 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3094 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3095 // calling a class is like a typecast
3096 $$.t = (classinfo_t*)v.t->data;
3099 $$.c = abc_coerce_a($$.c);
3103 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3104 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3105 if(!state->method) syntaxerror("super() not allowed outside of a function");
3106 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3109 $$.c = abc_getlocal_0($$.c);
3111 $$.c = code_append($$.c, $3.cc);
3113 this is dependent on the control path, check this somewhere else
3114 if(state->method->has_super)
3115 syntaxerror("constructor may call super() only once");
3117 state->method->has_super = 1;
3119 $$.c = abc_constructsuper($$.c, $3.number);
3120 $$.c = abc_pushundefined($$.c);
3124 DELETE: "delete" E {
3125 typedcode_t v = node_read($2);
3127 if($$.c->opcode == OPCODE_COERCE_A) {
3128 $$.c = code_cutlast($$.c);
3130 multiname_t*name = 0;
3131 if($$.c->opcode == OPCODE_GETPROPERTY) {
3132 $$.c->opcode = OPCODE_DELETEPROPERTY;
3133 } else if($$.c->opcode == OPCODE_GETSLOT) {
3134 int slot = (int)(ptroff_t)$$.c->data[0];
3135 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3136 $$.c = code_cutlast($$.c);
3137 $$.c = abc_deleteproperty2($$.c, name);
3139 $$.c = abc_getlocal_0($$.c);
3140 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3141 $$.c = abc_deleteproperty2($$.c, &m);
3143 $$.t = TYPE_BOOLEAN;
3146 RETURN: "return" %prec prec_none {
3147 $$ = abc_returnvoid(0);
3149 RETURN: "return" EXPRESSION {
3151 $$ = abc_returnvalue($$);
3154 // ----------------------- expression types -------------------------------------
3156 NONCOMMAEXPRESSION : E %prec below_lt {
3159 EXPRESSION : COMMA_EXPRESSION {
3162 COMMA_EXPRESSION : E %prec below_lt {
3163 $$ = mkmultinode(&node_comma, $1);
3165 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3166 $$ = multinode_extend($1, $3);
3168 VOIDEXPRESSION : E %prec below_minus {
3171 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3173 $$ = code_append($$, node_exec($3));
3176 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3177 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3179 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3180 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3181 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3182 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3183 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3185 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3187 $$.cc = code_append($$.cc, $1);
3188 $$.cc = code_append($$.cc, $3.c);
3191 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3193 $$.number = $1.number+2;
3194 $$.cc = code_append($$.cc, $3);
3195 $$.cc = code_append($$.cc, $5.c);
3198 // ----------------------- expression evaluation -------------------------------------
3200 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3201 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3202 E : NEW {$$ = mkcodenode($1);}
3203 E : DELETE {$$ = mkcodenode($1);}
3204 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3205 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3208 $$ = mkconstnode($1);
3214 multiname_t m = {QNAME, &stdns, 0, "XML"};
3215 v.c = abc_getlex2(v.c, &m);
3216 v.c = abc_pushstring(v.c, $1);
3217 v.c = abc_construct(v.c, 1);
3226 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3228 v.c = abc_getlex2(v.c, &m);
3229 v.c = abc_pushstring(v.c, $1.pattern);
3230 v.c = abc_construct(v.c, 1);
3232 v.c = abc_getlex2(v.c, &m);
3233 v.c = abc_pushstring(v.c, $1.pattern);
3234 v.c = abc_pushstring(v.c, $1.options);
3235 v.c = abc_construct(v.c, 2);
3243 state->method->need_arguments = 1;
3246 v.c = abc_getlocal(0, state->method->need_arguments);
3252 E : '[' MAYBE_EXPRESSION_LIST ']' {
3255 v.c = code_append(v.c, $2.cc);
3256 v.c = abc_newarray(v.c, $2.number);
3257 v.t = registry_getarrayclass();
3262 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3265 v.c = code_append(v.c, $2.cc);
3266 v.c = abc_newobject(v.c, $2.number/2);
3267 v.t = registry_getobjectclass();
3271 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3272 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3273 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3274 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3275 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3276 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3277 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3278 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3279 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3280 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3281 E : '!' E {$$ = mknode1(&node_not, $2);}
3282 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3283 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3284 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3285 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3286 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3287 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3288 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3289 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3290 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3291 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3292 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3293 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3294 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3295 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3296 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3297 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3298 E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
3299 E : "void" E {$$ = mknode1(&node_void, $2);}
3300 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3301 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3302 E : '-' E {$$ = mknode1(&node_neg, $2);}
3303 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3304 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3305 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3306 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3307 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3308 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3309 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3310 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3311 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3312 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3313 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3314 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3315 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3316 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3318 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3319 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3320 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3321 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3323 E : "super" '.' T_IDENTIFIER
3324 { if(!state->cls->info)
3325 syntaxerror("super keyword not allowed outside a class");
3326 classinfo_t*t = state->cls->info->superclass;
3327 if(!t) t = TYPE_OBJECT;
3328 memberinfo_t*f = findmember_nsset(t, $3, 1);
3329 MEMBER_MULTINAME(m, f, $3);
3332 v.c = abc_getlocal_0(v.c);
3333 v.c = abc_getsuper2(v.c, &m);
3334 v.t = slotinfo_gettype((slotinfo_t*)f);
3338 E : '@' T_IDENTIFIER {
3340 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3341 v.c = abc_getlex2(0, &m);
3346 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3349 typedcode_t v = node_read($1);
3350 typedcode_t w = node_read($5);
3352 int index = alloc_local();
3353 int result = alloc_local();
3354 int tmp = alloc_local();
3355 int xml = alloc_local();
3357 c = code_append(c, v.c);
3358 c = abc_checkfilter(c);
3359 c = abc_coerce_a(c); //hasnext2 converts to *
3360 c = abc_setlocal(c, xml);
3361 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3362 c = abc_getlex2(c, &m);
3363 c = abc_construct(c, 0);
3364 c = abc_setlocal(c, result);
3365 c = abc_pushbyte(c, 0);
3366 c = abc_setlocal(c, index);
3367 code_t*jmp = c = abc_jump(c, 0);
3368 code_t*loop = c = abc_label(c);
3369 c = abc_getlocal(c, xml);
3370 c = abc_getlocal(c, index);
3371 c = abc_nextvalue(c);
3373 c = abc_setlocal(c, tmp);
3374 c = abc_pushwith(c);
3375 c = code_append(c, w.c);
3376 c = abc_popscope(c);
3377 code_t*b = c = abc_iffalse(c, 0);
3378 c = abc_getlocal(c, result);
3379 c = abc_getlocal(c, index);
3380 c = abc_getlocal(c, tmp);
3381 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3382 c = abc_setproperty2(c, &m2);
3383 c = b->branch = jmp->branch = abc_nop(c);
3384 c = abc_kill(c, tmp);
3385 c = abc_hasnext2(c, xml, index);
3386 c = abc_iftrue(c, loop);
3387 c = abc_getlocal(c, result);
3388 c = abc_kill(c, xml);
3389 c = abc_kill(c, result);
3390 c = abc_kill(c, index);
3400 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3401 ID_OR_NS : '*' {$$="*";}
3402 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3403 SUBNODE: X_IDENTIFIER
3407 MAYBE_NS: T_IDENTIFIER "::" {$$=$1;}
3408 | T_NAMESPACE "::" {$$=(char*)$1;}
3409 | '*' "::" {$$="*";}
3412 E : E '.' ID_OR_NS "::" SUBNODE {
3413 typedcode_t v = node_read($1);
3414 typedcode_t w = node_read(resolve_identifier($3));
3415 v.c = code_append(v.c, w.c);
3416 if(!TYPE_IS_NAMESPACE(w.t)) {
3417 as3_softwarning("%s might not be a namespace", $3);
3419 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3420 multiname_t m = {RTQNAME, 0, 0, $5};
3421 v.c = abc_getproperty2(v.c, &m);
3422 if(TYPE_IS_XML(v.t)) {
3425 v.c = abc_coerce_a(v.c);
3430 E : E ".." SUBNODE {
3431 typedcode_t v = node_read($1);
3432 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3433 v.c = abc_getdescendants2(v.c, &m);
3437 E : E '.' '[' E ']' {
3438 typedcode_t v = node_read($1);
3439 typedcode_t w = node_read($4);
3440 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3441 v.c = code_append(v.c, w.c);
3442 v.c = converttype(w.c, w.t, TYPE_STRING);
3443 v.c = abc_getproperty2(v.c, &m);
3448 E : E '.' '@' SUBNODE {
3449 typedcode_t v = node_read($1);
3450 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3451 v.c = abc_getproperty2(v.c, &m);
3455 E : E ".." '@' SUBNODE {
3456 typedcode_t v = node_read($1);
3457 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3458 v.c = abc_getdescendants2(v.c, &m);
3462 E : E '.' '@' '[' E ']' {
3463 typedcode_t v = node_read($1);
3464 typedcode_t w = node_read($5);
3465 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3466 v.c = code_append(v.c, w.c);
3467 v.c = converttype(w.c, w.t, TYPE_STRING);
3468 v.c = abc_getproperty2(v.c, &m);
3472 E : E ".." '@' '[' E ']' {
3473 typedcode_t v = node_read($1);
3474 typedcode_t w = node_read($5);
3475 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3476 v.c = code_append(v.c, w.c);
3477 v.c = converttype(w.c, w.t, TYPE_STRING);
3478 v.c = abc_getdescendants2(v.c, &m);
3483 MEMBER : E '.' SUBNODE {
3484 typedcode_t v1 = node_read($1);
3486 classinfo_t*t = v1.t;
3488 if(TYPE_IS_CLASS(t) && t->data) {
3492 if(TYPE_IS_XML(t)) {
3493 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3494 $$.c = abc_getproperty2($$.c, &m);
3495 $$.c = abc_coerce_a($$.c);
3496 $$.t = TYPE_XMLLIST;
3498 if(t->subtype==INFOTYPE_UNRESOLVED) {
3499 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3501 memberinfo_t*f = findmember_nsset(t, $3, 1);
3503 if(f && !is_static != !(f->flags&FLAG_STATIC))
3505 if(f && f->slot && !noslot) {
3506 $$.c = abc_getslot($$.c, f->slot);
3509 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3511 MEMBER_MULTINAME(m, f, $3);
3512 $$.c = abc_getproperty2($$.c, &m);
3514 /* determine type */
3515 $$.t = slotinfo_gettype((slotinfo_t*)f);
3517 $$.c = abc_coerce_a($$.c);
3519 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3520 string_t*package = v1.c->data[0];
3521 char*package2 = concat3(package->str, ".", $3);
3523 slotinfo_t*a = registry_find(package->str, $3);
3526 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3527 registry_ispackage(package2)) {
3529 $$.c->data[0] = string_new4(package2);
3532 syntaxerror("couldn't resolve %s", package2);
3535 /* when resolving a property on an unknown type, we do know the
3536 name of the property (and don't seem to need the package), but
3537 we need to make avm2 try out all access modes */
3538 as3_softwarning("Resolving %s on unknown type", $3);
3539 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3540 $$.c = abc_getproperty2($$.c, &m);
3541 $$.c = abc_coerce_a($$.c);
3547 node_t* resolve_identifier(char*name)
3557 /* look at variables */
3558 if((v = find_variable(state, name))) {
3559 // name is a local variable
3560 o.c = abc_getlocal(o.c, v->index);
3562 return mkcodenode(o);
3564 if((v = find_slot(state, name))) {
3565 o.c = abc_getscopeobject(o.c, 1);
3566 o.c = abc_getslot(o.c, v->index);
3568 return mkcodenode(o);
3571 int i_am_static = state->method->is_static;
3573 /* look at current class' members */
3574 if(!state->method->inner &&
3575 !state->xmlfilter &&
3577 (f = findmember_nsset(state->cls->info, name, 1)))
3579 // name is a member or attribute in this class
3580 int var_is_static = (f->flags&FLAG_STATIC);
3582 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3583 /* if the variable is a constant (and we know what is evaluates to), we
3584 can just use the value itself */
3585 varinfo_t*v = (varinfo_t*)f;
3587 return mkconstnode(v->value);
3591 if(var_is_static >= i_am_static) {
3592 if(f->kind == INFOTYPE_METHOD) {
3593 o.t = TYPE_FUNCTION(f);
3598 if(var_is_static && !i_am_static) {
3599 /* access to a static member from a non-static location.
3600 do this via findpropstrict:
3601 there doesn't seem to be any non-lookup way to access
3602 static properties of a class */
3603 state->method->late_binding = 1;
3605 namespace_t ns = {f->access, f->package};
3606 multiname_t m = {QNAME, &ns, 0, name};
3607 o.c = abc_findpropstrict2(o.c, &m);
3608 o.c = abc_getproperty2(o.c, &m);
3609 return mkcodenode(o);
3610 } else if(f->slot>0) {
3611 o.c = abc_getlocal_0(o.c);
3612 o.c = abc_getslot(o.c, f->slot);
3613 return mkcodenode(o);
3615 MEMBER_MULTINAME(m, f, name);
3616 o.c = abc_getlocal_0(o.c);
3617 o.c = abc_getproperty2(o.c, &m);
3618 return mkcodenode(o);
3623 /* look at actual classes, in the current package and imported */
3624 if(!state->xmlfilter && (a = find_class(name))) {
3625 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3626 o.c = abc_getlocal_0(0);
3627 o.t = TYPE_CLASS((classinfo_t*)a);
3631 return mkcodenode(o);
3634 /* look through package prefixes */
3635 if(!state->xmlfilter &&
3636 (dict_contains(state->import_toplevel_packages, name) ||
3637 registry_ispackage(name))) {
3638 o.c = abc___pushpackage__(o.c, name);
3640 return mkcodenode(o); //?
3643 /* unknown object, let the avm2 resolve it */
3645 if(!state->method->inner && !state->xmlfilter) {
3646 /* we really should make inner functions aware of the class context */
3647 as3_warning("Couldn't resolve '%s', doing late binding", name);
3649 state->method->late_binding = 1;
3651 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3654 o.c = abc_findpropstrict2(o.c, &m);
3655 o.c = abc_getproperty2(o.c, &m);
3656 return mkcodenode(o);
3661 VAR_READ : T_IDENTIFIER {
3663 /* Queue unresolved identifiers for checking against the parent
3664 function's variables.
3665 We consider everything which is not a local variable "unresolved".
3666 This encompasses class names, members of the surrounding class
3667 etc. which is *correct* because local variables of the parent function
3671 if(!find_variable(state, $1)) {
3672 if(state->method->inner) {
3673 unknown_variable($1);
3675 /* let the compiler know that it might want to check the current directory/package
3676 for this identifier- maybe there's a file $1.as defining $1. */
3677 as3_schedule_class_noerror(state->package, $1);
3683 $$ = resolve_identifier($1);
3686 // ----------------- namespaces -------------------------------------------------
3689 void add_active_url(const char*url)
3693 list_append(state->active_namespace_urls, n);
3697 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3699 NEW(namespace_decl_t,n);
3704 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3706 NEW(namespace_decl_t,n);
3711 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3713 NEW(namespace_decl_t,n);
3718 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3720 trie_put(active_namespaces, $2->name, (void*)$2->url);
3722 namespace_t access = modifiers2access(&$1);
3723 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3724 var->type = TYPE_NAMESPACE;
3726 ns.access = ACCESS_NAMESPACE;
3728 var->value = constant_new_namespace(&ns);
3731 MULTINAME(m, TYPE_NAMESPACE);
3732 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3733 t->value = var->value;
3734 t->type_name = multiname_clone(&m);
3740 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3742 as3_warning("default xml namespaces not supported yet");
3745 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3747 const char*url = $3->name;
3749 varinfo_t*s = (varinfo_t*)$3;
3750 if(s->kind == INFOTYPE_UNRESOLVED) {
3751 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3753 syntaxerror("Couldn't resolve namespace %s", $3->name);
3756 if(!s || s->kind != INFOTYPE_VAR)
3757 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3758 if(!s->value || !NS_TYPE(s->value->type))
3759 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3760 url = s->value->ns->name;
3762 trie_put(active_namespaces, $3->name, (void*)url);
3763 add_active_url(url);