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);
669 //c = abc_pushundefined(c);
670 syntaxerror("internal error: can't generate default value for * type");
674 c = abc_coerce2(c, &m);
679 static int alloc_local()
681 return state->method->variable_count++;
684 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
687 variable_t*v = find_slot(state, name);
695 v->index = alloc_local();
700 dict_put(state->vars, name, v);
701 dict_put(state->allvars, name, v);
706 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
708 return new_variable2(name, type, init, maybeslot)->index;
711 #define TEMPVARNAME "__as3_temp__"
714 variable_t*v = find_variable(state, TEMPVARNAME);
719 i = new_variable(TEMPVARNAME, 0, 0, 0);
724 static code_t* var_block(code_t*body)
730 DICT_ITERATE_DATA(state->vars, variable_t*, v) {
731 if(v->type && v->init) {
732 c = defaultvalue(c, v->type);
733 c = abc_setlocal(c, v->index);
734 k = abc_kill(k, v->index);
742 if(x->opcode== OPCODE___BREAK__ ||
743 x->opcode== OPCODE___CONTINUE__) {
744 /* link kill code before break/continue */
745 code_t*e = code_dup(k);
746 code_t*s = code_start(e);
758 c = code_append(c, body);
759 c = code_append(c, k);
763 static void unknown_variable(char*name)
765 if(!state->method->unresolved_variables)
766 state->method->unresolved_variables = dict_new();
767 if(!dict_contains(state->method->unresolved_variables, name))
768 dict_put(state->method->unresolved_variables, name, 0);
771 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
773 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
774 c = abc_getlocal_0(c);
775 c = abc_pushscope(c);
778 /* FIXME: this alloc_local() causes variable indexes to be
779 different in pass2 than in pass1 */
780 if(!m->activation_var) {
781 m->activation_var = alloc_local();
784 c = abc_newactivation(c);
786 c = abc_pushscope(c);
787 c = abc_setlocal(c, m->activation_var);
789 c = abc_getlocal(c, m->activation_var);
790 c = abc_pushscope(c);
796 static code_t* method_header(methodstate_t*m)
800 c = add_scope_code(c, m, 1);
802 methodstate_list_t*l = m->innerfunctions;
804 parserassert(l->methodstate->abc);
805 if(m->uses_slots && l->methodstate->is_a_slot) {
806 c = abc_getscopeobject(c, 1);
807 c = abc_newfunction(c, l->methodstate->abc);
809 c = abc_setlocal(c, l->methodstate->var_index);
810 c = abc_setslot(c, l->methodstate->slot_index);
812 c = abc_newfunction(c, l->methodstate->abc);
813 c = abc_setlocal(c, l->methodstate->var_index);
815 free(l->methodstate);l->methodstate=0;
819 c = code_append(c, m->header);
822 if(m->is_constructor && !m->has_super) {
823 // call default constructor
824 c = abc_getlocal_0(c);
825 c = abc_constructsuper(c, 0);
829 /* all parameters that are used by inner functions
830 need to be copied from local to slot */
831 parserassert(m->activation_var);
832 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
833 if(v->is_parameter) {
834 c = abc_getlocal(c, m->activation_var);
835 c = abc_getlocal(c, v->index);
836 c = abc_setslot(c, v->index);
840 list_free(m->innerfunctions);
841 m->innerfunctions = 0;
846 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
848 c = code_append(c, header);
849 c = code_append(c, var_block(body));
850 /* append return if necessary */
851 if(!c || (c->opcode != OPCODE_RETURNVOID &&
852 c->opcode != OPCODE_RETURNVALUE)) {
853 c = abc_returnvoid(c);
858 static void startpackage(char*name)
861 state->package = strdup(name);
863 static void endpackage()
865 //used e.g. in classinfo_register:
866 //free(state->package);state->package=0;
870 #define FLAG_PUBLIC 256
871 #define FLAG_PROTECTED 512
872 #define FLAG_PRIVATE 1024
873 #define FLAG_PACKAGEINTERNAL 2048
874 #define FLAG_NAMESPACE 4096
876 static namespace_t modifiers2access(modifiers_t*mod)
881 if(mod->flags&FLAG_NAMESPACE) {
882 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
883 syntaxerror("invalid combination of access levels and namespaces");
884 ns.access = ACCESS_NAMESPACE;
886 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
888 /* shouldn't happen- the tokenizer only reports something as a namespace
889 if it was already registered */
890 trie_dump(active_namespaces);
891 syntaxerror("unknown namespace: %s", mod->ns);
894 } else if(mod->flags&FLAG_PUBLIC) {
895 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
896 syntaxerror("invalid combination of access levels");
897 ns.access = ACCESS_PACKAGE;
898 } else if(mod->flags&FLAG_PRIVATE) {
899 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
900 syntaxerror("invalid combination of access levels");
901 ns.access = ACCESS_PRIVATE;
902 } else if(mod->flags&FLAG_PROTECTED) {
903 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
904 syntaxerror("invalid combination of access levels");
905 ns.access = ACCESS_PROTECTED;
907 ns.access = ACCESS_PACKAGEINTERNAL;
911 static slotinfo_t* find_class(const char*name);
913 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
915 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
918 static void innerfunctions2vars(methodstate_t*m)
920 methodstate_list_t*l = m->innerfunctions;
922 methodstate_t*m = l->methodstate;
924 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 0);
925 m->var_index = v->index;
927 m->slot_index = m->is_a_slot;
928 v->is_inner_method = m;
933 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
938 index = new_variable("this", 0, 0, 0);
939 else if(!m->is_global)
940 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
942 index = new_variable("globalscope", 0, 0, 0);
943 parserassert(!index);
948 for(p=params->list;p;p=p->next) {
949 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
952 if(as3_pass==2 && m->need_arguments) {
953 /* arguments can never be used by an innerfunction (the inner functions
954 have their own arguments var), so it's ok to not initialize this until
955 pass 2. (We don't know whether we need it before, anyway) */
956 variable_t*v = new_variable2("arguments", TYPE_ARRAY, 0, 0);
957 m->need_arguments = v->index;
961 innerfunctions2vars(m);
964 m->scope_code = add_scope_code(m->scope_code, m, 0);
966 /* exchange unresolved identifiers with the actual objects */
967 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
968 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
969 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
970 if(!type || type->kind != INFOTYPE_CLASS) {
971 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
981 char*as3_globalclass=0;
982 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
985 syntaxerror("inner classes now allowed");
990 classinfo_list_t*mlist=0;
992 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
993 syntaxerror("invalid modifier(s)");
995 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
996 syntaxerror("public and internal not supported at the same time.");
998 if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
999 syntaxerror("protected and static not supported at the same time.");
1001 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1002 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1003 // all classes extend object
1004 extends = registry_getobjectclass();
1007 /* create the class name, together with the proper attributes */
1011 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
1012 access = ACCESS_PRIVATE; package = internal_filename_package;
1013 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
1014 access = ACCESS_PACKAGEINTERNAL; package = state->package;
1015 } else if(state->package!=internal_filename_package) {
1016 access = ACCESS_PACKAGE; package = state->package;
1018 syntaxerror("public classes only allowed inside a package");
1022 state->cls = rfx_calloc(sizeof(classstate_t));
1023 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1024 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1025 state->cls->static_init->is_static=FLAG_STATIC;
1026 state->cls->static_init->variable_count=1;
1027 /* notice: we make no effort to initialize the top variable (local0) here,
1028 even though it has special meaning. We just rely on the fact
1029 that pass 1 won't do anything with variables */
1031 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1033 /* set current method to constructor- all code within the class-level (except
1034 static variable initializations) will be executed during construction time */
1035 state->method = state->cls->init;
1037 if(registry_find(package, classname)) {
1038 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1040 /* build info struct */
1041 int num_interfaces = (list_length(implements));
1042 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1043 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1044 state->cls->info->superclass = extends;
1047 classinfo_list_t*l = implements;
1048 for(l=implements;l;l=l->next) {
1049 state->cls->info->interfaces[pos++] = l->classinfo;
1054 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1056 state->method = state->cls->init;
1057 parserassert(state->cls && state->cls->info);
1059 function_initvars(state->cls->init, 0, 0, 0, 1);
1060 function_initvars(state->cls->static_init, 0, 0, 0, 0);
1062 if(extends && (extends->flags & FLAG_FINAL))
1063 syntaxerror("Can't extend final class '%s'", extends->name);
1066 while(state->cls->info->interfaces[pos]) {
1067 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1068 syntaxerror("'%s' is not an interface",
1069 state->cls->info->interfaces[pos]->name);
1073 /* generate the abc code for this class */
1074 MULTINAME(classname2,state->cls->info);
1075 multiname_t*extends2 = sig2mname(extends);
1077 /* don't add the class to the class index just yet- that will be done later
1079 state->cls->abc = abc_class_new(0, &classname2, extends2);
1080 state->cls->abc->file = global->file;
1082 multiname_destroy(extends2);
1083 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1084 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1085 if(state->cls->info->flags&FLAG_INTERFACE) {
1086 abc_class_interface(state->cls->abc);
1089 for(mlist=implements;mlist;mlist=mlist->next) {
1090 MULTINAME(m, mlist->classinfo);
1091 abc_class_add_interface(state->cls->abc, &m);
1094 state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
1095 list_append(global->classes, state->cls->dependencies);
1097 /* flash.display.MovieClip handling */
1098 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1099 if(state->package && state->package[0]) {
1100 as3_globalclass = concat3(state->package, ".", classname);
1102 as3_globalclass = strdup(classname);
1108 static void endclass()
1111 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1113 c = abc_getlocal_0(c);
1114 c = abc_constructsuper(c, 0);
1115 state->cls->init->header = code_append(state->cls->init->header, c);
1116 state->cls->has_constructor=1;
1118 if(state->cls->init) {
1119 if(state->cls->info->flags&FLAG_INTERFACE) {
1120 if(state->cls->init->header)
1121 syntaxerror("interface can not have class-level code");
1123 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1124 code_t*c = method_header(state->cls->init);
1125 m->body->code = wrap_function(c, 0, m->body->code);
1128 if(state->cls->static_init) {
1129 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1130 code_t*c = method_header(state->cls->static_init);
1131 m->body->code = wrap_function(c, 0, m->body->code);
1134 trait_list_t*trait = state->cls->abc->traits;
1135 /* switch all protected members to the protected ns of this class */
1137 trait_t*t = trait->trait;
1138 if(t->name->ns->access == ACCESS_PROTECTED) {
1139 if(!state->cls->abc->protectedNS) {
1140 char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
1141 state->cls->abc->protectedNS = namespace_new_protected(n);
1142 state->cls->abc->flags |= CLASS_PROTECTED_NS;
1144 t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
1146 trait = trait->next;
1153 void check_code_for_break(code_t*c)
1156 if(c->opcode == OPCODE___BREAK__) {
1157 char*name = string_cstr(c->data[0]);
1158 syntaxerror("Unresolved \"break %s\"", name);
1160 if(c->opcode == OPCODE___CONTINUE__) {
1161 char*name = string_cstr(c->data[0]);
1162 syntaxerror("Unresolved \"continue %s\"", name);
1164 if(c->opcode == OPCODE___RETHROW__) {
1165 syntaxerror("Unresolved \"rethrow\"");
1167 if(c->opcode == OPCODE___FALLTHROUGH__) {
1168 syntaxerror("Unresolved \"fallthrough\"");
1170 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1171 char*name = string_cstr(c->data[0]);
1172 syntaxerror("Can't reference a package (%s) as such", name);
1178 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1180 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1181 if(TYPE_IS_NUMBER(t)) {
1182 xassert(c->type == CONSTANT_FLOAT
1183 || c->type == CONSTANT_INT
1184 || c->type == CONSTANT_UINT);
1185 } else if(TYPE_IS_UINT(t)) {
1186 xassert(c->type == CONSTANT_UINT ||
1187 (c->type == CONSTANT_INT && c->i>=0));
1188 } else if(TYPE_IS_INT(t)) {
1189 xassert(c->type == CONSTANT_INT);
1190 } else if(TYPE_IS_BOOLEAN(t)) {
1191 xassert(c->type == CONSTANT_TRUE
1192 || c->type == CONSTANT_FALSE);
1196 static void check_override(memberinfo_t*m, int flags)
1200 if(m->parent == state->cls->info)
1201 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1203 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1204 if(m->access==ACCESS_PRIVATE)
1206 if(m->flags & FLAG_FINAL)
1207 syntaxerror("can't override final member %s", m->name);
1209 /* allow this. it's no issue.
1210 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1211 syntaxerror("can't override static member %s", m->name);*/
1213 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1214 syntaxerror("can't override non-static member %s with static declaration", m->name);
1216 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1217 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1218 if(m->kind == INFOTYPE_METHOD)
1219 syntaxerror("can't override without explicit 'override' declaration");
1221 syntaxerror("can't override '%s'", m->name);
1226 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1228 methodinfo_t*minfo = 0;
1229 namespace_t ns = modifiers2access(mod);
1232 minfo = methodinfo_register_global(ns.access, state->package, name);
1233 minfo->return_type = return_type;
1234 } else if(getset != KW_GET && getset != KW_SET) {
1236 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1238 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1240 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1241 minfo->return_type = return_type;
1242 // getslot on a member slot only returns "undefined", so no need
1243 // to actually store these
1244 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1246 //class getter/setter
1247 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1249 if(getset == KW_GET) {
1251 } else if(params->list && params->list->param && !params->list->next) {
1252 type = params->list->param->type;
1254 syntaxerror("setter function needs to take exactly one argument");
1255 // not sure wether to look into superclasses here, too
1256 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1258 if(minfo->kind!=INFOTYPE_VAR)
1259 syntaxerror("class already contains a method called '%s'", name);
1260 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1261 syntaxerror("class already contains a field called '%s'", name);
1262 if(minfo->subtype & gs)
1263 syntaxerror("getter/setter for '%s' already defined", name);
1264 /* make a setter or getter into a getset */
1265 minfo->subtype |= gs;
1268 FIXME: this check needs to be done in pass 2
1270 if((!minfo->return_type != !type) ||
1271 (minfo->return_type && type &&
1272 !strcmp(minfo->return_type->name, type->name))) {
1273 syntaxerror("different type in getter and setter: %s and %s",
1274 minfo->return_type?minfo->return_type->name:"*",
1275 type?type->name:"*");
1278 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1279 minfo->kind = INFOTYPE_VAR; //hack
1280 minfo->subtype = gs;
1281 minfo->return_type = type;
1284 /* can't assign a slot as getter and setter might have different slots */
1285 //minfo->slot = slot;
1287 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1288 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1289 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1294 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1296 //parserassert(state->method && state->method->info);
1298 methodstate_t*parent_method = state->method;
1301 return_type = 0; // not valid in pass 1
1305 state->new_vars = 1;
1306 state->allvars = dict_new();
1309 state->method = rfx_calloc(sizeof(methodstate_t));
1310 state->method->inner = 1;
1311 state->method->is_static = parent_method->is_static;
1312 state->method->variable_count = 0;
1313 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1315 NEW(methodinfo_t,minfo);
1316 minfo->kind = INFOTYPE_METHOD;
1317 minfo->access = ACCESS_PACKAGEINTERNAL;
1319 state->method->info = minfo;
1322 list_append(parent_method->innerfunctions, state->method);
1324 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1326 function_initvars(state->method, 1, params, 0, 1);
1330 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1331 state->method->variable_count = 0;
1332 parserassert(state->method);
1334 state->method->info->return_type = return_type;
1335 function_initvars(state->method, 1, params, 0, 1);
1339 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1340 params_t*params, classinfo_t*return_type)
1342 if(state->method && state->method->info) {
1343 syntaxerror("not able to start another method scope");
1346 state->new_vars = 1;
1347 state->allvars = dict_new();
1350 state->method = rfx_calloc(sizeof(methodstate_t));
1351 state->method->has_super = 0;
1352 state->method->is_static = mod->flags&FLAG_STATIC;
1355 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1357 state->method->is_global = 1;
1358 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1360 if(state->method->is_constructor)
1361 name = "__as3_constructor__";
1363 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1365 function_initvars(state->method, 1, params, mod->flags, 1);
1367 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1371 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1372 state->method->variable_count = 0;
1373 parserassert(state->method);
1376 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1377 check_override(m, mod->flags);
1381 state->cls->has_constructor |= state->method->is_constructor;
1384 function_initvars(state->method, 1, params, mod->flags, 1);
1388 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1389 params_t*params, classinfo_t*return_type, code_t*body)
1392 innerfunctions2vars(state->method);
1394 methodstate_list_t*ml = state->method->innerfunctions;
1396 dict_t*xvars = dict_new();
1399 methodstate_t*m = ml->methodstate;
1400 parserassert(m->inner);
1401 if(m->unresolved_variables) {
1402 dict_t*d = m->unresolved_variables;
1404 DICT_ITERATE_KEY(d, char*, id) {
1405 /* check parent method's variables */
1407 if((v=find_variable(state, id))) {
1408 m->uses_parent_function = 1;
1409 state->method->uses_slots = 1;
1410 dict_put(xvars, id, 0);
1413 dict_destroy(m->unresolved_variables);m->unresolved_variables = 0;
1418 if(state->method->uses_slots) {
1419 state->method->slots = dict_new();
1421 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1422 if(!name) syntaxerror("internal error");
1423 if(v->index && dict_contains(xvars, name)) {
1426 if(v->is_inner_method) {
1427 v->is_inner_method->is_a_slot = i;
1430 dict_put(state->method->slots, name, v);
1433 state->method->uses_slots = i;
1434 dict_destroy(state->vars);state->vars = 0;
1435 parserassert(state->new_vars);
1436 dict_destroy(state->allvars);state->allvars = 0;
1443 /*if(state->method->uses_parent_function){
1444 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1449 multiname_t*type2 = sig2mname(return_type);
1451 if(state->method->inner) {
1452 f = state->method->abc;
1453 abc_method_init(f, global->file, type2, 1);
1454 } else if(state->method->is_constructor) {
1455 f = abc_class_getconstructor(state->cls->abc, type2);
1456 } else if(!state->method->is_global) {
1457 namespace_t ns = modifiers2access(mod);
1458 multiname_t mname = {QNAME, &ns, 0, name};
1459 if(mod->flags&FLAG_STATIC)
1460 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1462 f = abc_class_method(state->cls->abc, type2, &mname);
1463 slot = f->trait->slot_id;
1465 namespace_t mname_ns = {state->method->info->access, state->package};
1466 multiname_t mname = {QNAME, &mname_ns, 0, name};
1468 f = abc_method_new(global->file, type2, 1);
1469 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1470 //abc_code_t*c = global->init->method->body->code;
1472 //flash doesn't seem to allow us to access function slots
1473 //state->method->info->slot = slot;
1475 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1476 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1477 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1478 if(params->varargs) f->flags |= METHOD_NEED_REST;
1479 if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
1483 for(p=params->list;p;p=p->next) {
1484 if(params->varargs && !p->next) {
1485 break; //varargs: omit last parameter in function signature
1487 multiname_t*m = sig2mname(p->param->type);
1488 list_append(f->parameters, m);
1489 if(p->param->value) {
1490 check_constant_against_type(p->param->type, p->param->value);
1491 opt=1;list_append(f->optional_parameters, p->param->value);
1493 syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
1496 if(state->method->slots) {
1497 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1499 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1500 multiname_t*type = sig2mname(v->type);
1501 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1502 t->slot_id = v->index;
1507 check_code_for_break(body);
1509 /* Seems this works now.
1510 if(state->method->exceptions && state->method->uses_slots) {
1511 as3_warning("try/catch and activation not supported yet within the same method");
1515 f->body->code = body;
1516 f->body->exceptions = state->method->exceptions;
1517 } else { //interface
1519 syntaxerror("interface methods can't have a method body");
1529 void breakjumpsto(code_t*c, char*name, code_t*jump)
1532 if(c->opcode == OPCODE___BREAK__) {
1533 string_t*name2 = c->data[0];
1534 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1535 c->opcode = OPCODE_JUMP;
1542 void continuejumpsto(code_t*c, char*name, code_t*jump)
1545 if(c->opcode == OPCODE___CONTINUE__) {
1546 string_t*name2 = c->data[0];
1547 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1548 c->opcode = OPCODE_JUMP;
1556 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1561 return abc_coerce_a(c);
1565 // cast an "any" type to a specific type. subject to
1566 // runtime exceptions
1567 return abc_coerce2(c, &m);
1570 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1571 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1572 // allow conversion between number types
1573 if(TYPE_IS_UINT(to))
1574 return abc_convert_u(c);
1575 else if(TYPE_IS_INT(to))
1576 return abc_convert_i(c);
1577 else if(TYPE_IS_NUMBER(to))
1578 return abc_convert_d(c);
1579 return abc_coerce2(c, &m);
1582 if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
1585 if(TYPE_IS_BOOLEAN(to))
1586 return abc_convert_b(c);
1587 if(TYPE_IS_STRING(to))
1588 return abc_convert_s(c);
1589 if(TYPE_IS_OBJECT(to))
1590 return abc_convert_o(c);
1592 classinfo_t*supertype = from;
1594 if(supertype == to) {
1595 // target type is one of from's superclasses
1596 return abc_coerce2(c, &m);
1599 while(supertype->interfaces[t]) {
1600 if(supertype->interfaces[t]==to) {
1601 // target type is one of from's interfaces
1602 return abc_coerce2(c, &m);
1606 supertype = supertype->superclass;
1608 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1610 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1612 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1615 as3_error("can't convert type %s%s%s to %s%s%s",
1616 from->package, from->package[0]?".":"", from->name,
1617 to->package, to->package[0]?".":"", to->name);
1621 /* move to ast.c todo end */
1623 char is_pushundefined(code_t*c)
1625 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1628 static const char* get_package_from_name(const char*name)
1630 /* try explicit imports */
1631 dictentry_t* e = dict_get_slot(state->imports, name);
1633 if(!strcmp(e->key, name)) {
1634 slotinfo_t*c = (slotinfo_t*)e->data;
1635 if(c) return c->package;
1641 static namespace_list_t*get_current_imports()
1643 namespace_list_t*searchlist = 0;
1645 list_append(searchlist, namespace_new_package(state->package));
1647 import_list_t*l = state->wildcard_imports;
1649 namespace_t*ns = namespace_new_package(l->import->package);
1650 list_append(searchlist, ns);
1653 list_append(searchlist, namespace_new_package(""));
1654 list_append(searchlist, namespace_new_package(internal_filename_package));
1658 static slotinfo_t* find_class(const char*name)
1662 c = registry_find(state->package, name);
1665 /* try explicit imports */
1666 dictentry_t* e = dict_get_slot(state->imports, name);
1669 if(!strcmp(e->key, name)) {
1670 c = (slotinfo_t*)e->data;
1676 /* try package.* imports */
1677 import_list_t*l = state->wildcard_imports;
1679 //printf("does package %s contain a class %s?\n", l->import->package, name);
1680 c = registry_find(l->import->package, name);
1685 /* try global package */
1686 c = registry_find("", name);
1689 /* try local "filename" package */
1690 c = registry_find(internal_filename_package, name);
1695 typedcode_t push_class(slotinfo_t*a)
1700 if(a->access == ACCESS_PACKAGEINTERNAL &&
1701 strcmp(a->package, state->package) &&
1702 strcmp(a->package, internal_filename_package)
1704 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1705 infotypename(a), a->name, a->package, state->package);
1709 if(a->kind != INFOTYPE_CLASS) {
1711 x.c = abc_findpropstrict2(x.c, &m);
1712 x.c = abc_getproperty2(x.c, &m);
1713 if(a->kind == INFOTYPE_METHOD) {
1714 methodinfo_t*f = (methodinfo_t*)a;
1715 x.t = TYPE_FUNCTION(f);
1717 varinfo_t*v = (varinfo_t*)a;
1722 if(state->cls && state->method == state->cls->static_init) {
1723 /* we're in the static initializer.
1724 record the fact that we're using this class here */
1725 parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
1727 classinfo_t*c = (classinfo_t*)a;
1729 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1730 x.c = abc_getglobalscope(x.c);
1731 x.c = abc_getslot(x.c, c->slot);
1734 x.c = abc_getlex2(x.c, &m);
1736 x.t = TYPE_CLASS(c);
1742 char is_break_or_jump(code_t*c)
1746 if(c->opcode == OPCODE_JUMP ||
1747 c->opcode == OPCODE___BREAK__ ||
1748 c->opcode == OPCODE___CONTINUE__ ||
1749 c->opcode == OPCODE_THROW ||
1750 c->opcode == OPCODE_RETURNVOID ||
1751 c->opcode == OPCODE_RETURNVALUE) {
1757 #define IS_FINALLY_TARGET(op) \
1758 ((op) == OPCODE___CONTINUE__ || \
1759 (op) == OPCODE___BREAK__ || \
1760 (op) == OPCODE_RETURNVOID || \
1761 (op) == OPCODE_RETURNVALUE || \
1762 (op) == OPCODE___RETHROW__)
1764 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1766 #define NEED_EXTRA_STACK_ARG
1767 code_t*finally_label = abc_nop(0);
1768 NEW(lookupswitch_t, l);
1774 code_t*prev = i->prev;
1775 if(IS_FINALLY_TARGET(i->opcode)) {
1778 if(i->opcode == OPCODE___RETHROW__ ||
1779 i->opcode == OPCODE_RETURNVALUE) {
1780 if(i->opcode == OPCODE___RETHROW__)
1781 i->opcode = OPCODE_THROW;
1783 p = abc_coerce_a(p);
1784 p = abc_setlocal(p, tempvar);
1786 p = abc_pushbyte(p, count++);
1787 p = abc_jump(p, finally_label);
1788 code_t*target = p = abc_label(p);
1789 #ifdef NEED_EXTRA_STACK_ARG
1793 p = abc_getlocal(p, tempvar);
1796 p->next = i;i->prev = p;
1797 list_append(l->targets, target);
1803 c = abc_pushbyte(c, -1);
1804 c = code_append(c, finally_label);
1805 c = code_append(c, finally);
1807 #ifdef NEED_EXTRA_STACK_ARG
1810 c = abc_lookupswitch(c, l);
1811 c = l->def = abc_label(c);
1812 #ifdef NEED_EXTRA_STACK_ARG
1819 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1823 code_t*prev = i->prev;
1824 if(IS_FINALLY_TARGET(i->opcode)) {
1825 if(i->opcode == OPCODE___RETHROW__)
1826 i->opcode = OPCODE_THROW;
1827 code_t*end = code_dup(finally);
1828 code_t*start = code_start(end);
1829 if(prev) prev->next = start;
1836 return code_append(c, finally);
1839 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1845 int num_insertion_points=0;
1847 if(IS_FINALLY_TARGET(i->opcode))
1848 num_insertion_points++;
1855 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1860 int simple_version_cost = (1+num_insertion_points)*code_size;
1861 int lookup_version_cost = 4*num_insertion_points + 5;
1863 if(cantdup || simple_version_cost > lookup_version_cost) {
1864 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1865 return insert_finally_lookup(c, finally, tempvar);
1867 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1868 return insert_finally_simple(c, finally, tempvar);
1872 #define PASS1 }} if(as3_pass == 1) {{
1873 #define PASS1END }} if(as3_pass == 2) {{
1874 #define PASS2 }} if(as3_pass == 2) {{
1875 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1876 #define PASS12END }} if(as3_pass == 2) {{
1877 #define PASS_ALWAYS }} {{
1883 /* ------------ code blocks / statements ---------------- */
1885 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1887 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1888 PROGRAM_CODE_LIST: PROGRAM_CODE
1889 | PROGRAM_CODE_LIST PROGRAM_CODE
1891 PROGRAM_CODE: PACKAGE_DECLARATION
1892 | INTERFACE_DECLARATION
1894 | FUNCTION_DECLARATION
1897 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1900 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1901 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1902 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1904 INPACKAGE_CODE: INTERFACE_DECLARATION
1906 | FUNCTION_DECLARATION
1909 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1912 MAYBECODE: CODE {$$=$1;}
1913 MAYBECODE: {$$=code_new();}
1915 CODE: CODE CODEPIECE {
1916 $$=code_append($1,$2);
1918 CODE: CODEPIECE {$$=$1;}
1920 // code which may appear outside of methods
1921 CODE_STATEMENT: DEFAULT_NAMESPACE
1922 CODE_STATEMENT: IMPORT
1924 CODE_STATEMENT: FOR_IN
1925 CODE_STATEMENT: WHILE
1926 CODE_STATEMENT: DO_WHILE
1927 CODE_STATEMENT: SWITCH
1929 CODE_STATEMENT: WITH
1931 CODE_STATEMENT: VOIDEXPRESSION
1932 CODE_STATEMENT: USE_NAMESPACE
1933 CODE_STATEMENT: NAMESPACE_DECLARATION
1934 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1935 CODE_STATEMENT: '{' '}' {$$=0;}
1937 // code which may appear in methods (includes the above)
1938 CODEPIECE: ';' {$$=0;}
1939 CODEPIECE: CODE_STATEMENT
1940 CODEPIECE: VARIABLE_DECLARATION
1945 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
1955 //CODEBLOCK : '{' CODE '}' {$$=$2;}
1956 //CODEBLOCK : '{' '}' {$$=0;}
1957 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1958 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1960 /* ------------ package init code ------------------- */
1962 PACKAGE_INITCODE: CODE_STATEMENT {
1963 code_t**cc = &global->init->method->body->code;
1964 *cc = code_append(*cc, $1);
1967 /* ------------ conditional compilation ------------- */
1969 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
1972 char*key = concat3($1,"::",$3);
1973 if(!definitions || !dict_contains(definitions, key)) {
1979 /* ------------ variables --------------------------- */
1982 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1988 MAYBEEXPRESSION : '=' E {$$=$2;}
1989 | {$$=mkdummynode();}
1991 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1992 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1994 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1995 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1997 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2000 if(variable_exists($1))
2001 syntaxerror("Variable %s already defined", $1);
2003 new_variable($1, 0, 1, 0);
2008 if(state->method->uses_slots) {
2009 variable_t* v = find_slot(state, $1);
2011 // this variable is stored in a slot
2019 index = new_variable($1, $2, 1, 0);
2022 $$ = slot?abc_getscopeobject(0, 1):0;
2024 typedcode_t v = node_read($3);
2025 if(!is_subtype_of(v.t, $2)) {
2026 syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
2029 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2030 $$ = code_append($$, v.c);
2031 $$ = converttype($$, v.t, $2);
2034 $$ = defaultvalue($$, $2);
2037 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2038 $$ = code_append($$, v.c);
2039 $$ = abc_coerce_a($$);
2041 // don't do anything
2049 $$ = abc_setslot($$, index);
2051 $$ = abc_setlocal($$, index);
2055 /* ------------ control flow ------------------------- */
2057 MAYBEELSE: %prec below_else {$$ = code_new();}
2058 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2059 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2061 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2064 $$ = code_append($$, $4.c);
2065 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2067 $$ = code_append($$, $6);
2069 myjmp = $$ = abc_jump($$, 0);
2071 myif->branch = $$ = abc_nop($$);
2073 $$ = code_append($$, $7);
2074 myjmp->branch = $$ = abc_nop($$);
2080 FOR_INIT : {$$=code_new();}
2081 FOR_INIT : VARIABLE_DECLARATION
2082 FOR_INIT : VOIDEXPRESSION
2084 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2085 // (I don't see any easy way to revolve this conflict otherwise, as we
2086 // can't touch VAR_READ without upsetting the precedence about "return")
2087 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2088 PASS1 $$=$2;new_variable($2,0,1,0);
2089 PASS2 $$=$2;new_variable($2,$3,1,0);
2091 FOR_IN_INIT : T_IDENTIFIER {
2096 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2097 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2099 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2100 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2102 $$ = code_append($$, $2);
2103 code_t*loopstart = $$ = abc_label($$);
2104 $$ = code_append($$, $4.c);
2105 code_t*myif = $$ = abc_iffalse($$, 0);
2106 $$ = code_append($$, $8);
2107 code_t*cont = $$ = abc_nop($$);
2108 $$ = code_append($$, $6);
2109 $$ = abc_jump($$, loopstart);
2110 code_t*out = $$ = abc_nop($$);
2111 breakjumpsto($$, $1.name, out);
2112 continuejumpsto($$, $1.name, cont);
2119 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2120 variable_t*var = find_variable(state, $2);
2122 syntaxerror("variable %s not known in this scope", $2);
2125 char*tmp1name = concat2($2, "__tmp1__");
2126 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2127 char*tmp2name = concat2($2, "__array__");
2128 int array = new_variable(tmp1name, 0, 0, 0);
2131 $$ = code_append($$, $4.c);
2132 $$ = abc_coerce_a($$);
2133 $$ = abc_setlocal($$, array);
2134 $$ = abc_pushbyte($$, 0);
2135 $$ = abc_setlocal($$, it);
2137 code_t*loopstart = $$ = abc_label($$);
2139 $$ = abc_hasnext2($$, array, it);
2140 code_t*myif = $$ = abc_iffalse($$, 0);
2141 $$ = abc_getlocal($$, array);
2142 $$ = abc_getlocal($$, it);
2144 $$ = abc_nextname($$);
2146 $$ = abc_nextvalue($$);
2147 $$ = converttype($$, 0, var->type);
2148 $$ = abc_setlocal($$, var->index);
2150 $$ = code_append($$, $6);
2151 $$ = abc_jump($$, loopstart);
2153 code_t*out = $$ = abc_nop($$);
2154 breakjumpsto($$, $1.name, out);
2155 continuejumpsto($$, $1.name, loopstart);
2167 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2171 code_t*myjmp = $$ = abc_jump($$, 0);
2172 code_t*loopstart = $$ = abc_label($$);
2173 $$ = code_append($$, $6);
2174 code_t*cont = $$ = abc_nop($$);
2175 myjmp->branch = cont;
2176 $$ = code_append($$, $4.c);
2177 $$ = abc_iftrue($$, loopstart);
2178 code_t*out = $$ = abc_nop($$);
2179 breakjumpsto($$, $1, out);
2180 continuejumpsto($$, $1, cont);
2186 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2188 code_t*loopstart = $$ = abc_label($$);
2189 $$ = code_append($$, $3);
2190 code_t*cont = $$ = abc_nop($$);
2191 $$ = code_append($$, $6.c);
2192 $$ = abc_iftrue($$, loopstart);
2193 code_t*out = $$ = abc_nop($$);
2194 breakjumpsto($$, $1, out);
2195 continuejumpsto($$, $1, cont);
2201 BREAK : "break" %prec prec_none {
2202 $$ = abc___break__(0, "");
2204 BREAK : "break" T_IDENTIFIER {
2205 $$ = abc___break__(0, $2);
2207 CONTINUE : "continue" %prec prec_none {
2208 $$ = abc___continue__(0, "");
2210 CONTINUE : "continue" T_IDENTIFIER {
2211 $$ = abc___continue__(0, $2);
2214 MAYBE_CASE_LIST : {$$=0;}
2215 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2216 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2217 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2218 CASE_LIST: CASE {$$=$1;}
2219 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2221 CASE: "case" E ':' MAYBECODE {
2222 $$ = abc_getlocal(0, state->switch_var);
2223 $$ = code_append($$, node_read($2).c);
2224 code_t*j = $$ = abc_ifne($$, 0);
2225 $$ = code_append($$, $4);
2226 if($$->opcode != OPCODE___BREAK__) {
2227 $$ = abc___fallthrough__($$, "");
2229 code_t*e = $$ = abc_nop($$);
2232 DEFAULT: "default" ':' MAYBECODE {
2235 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2236 $$ = node_read($4).c;
2237 $$ = abc_setlocal($$, state->switch_var);
2238 $$ = code_append($$, $7);
2240 code_t*out = $$ = abc_kill($$, state->switch_var);
2241 breakjumpsto($$, $1, out);
2243 code_t*c = $$,*lastblock=0;
2245 if(c->opcode == OPCODE_IFNE) {
2246 if(!c->next) syntaxerror("internal error in fallthrough handling");
2248 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2250 c->opcode = OPCODE_JUMP;
2251 c->branch = lastblock;
2253 /* fall through end of switch */
2254 c->opcode = OPCODE_NOP;
2264 /* ------------ try / catch /finally ---------------- */
2266 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2267 state->exception_name=$3;
2268 PASS1 new_variable($3, 0, 0, 0);
2269 PASS2 new_variable($3, $4, 0, 0);
2272 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2273 multiname_t name = {QNAME, &name_ns, 0, $3};
2275 NEW(abc_exception_t, e)
2276 e->exc_type = sig2mname($4);
2277 e->var_name = multiname_clone(&name);
2281 int i = find_variable_safe(state, $3)->index;
2282 e->target = c = abc_nop(0);
2283 c = abc_setlocal(c, i);
2284 c = code_append(c, code_dup(state->method->scope_code));
2285 c = code_append(c, $8);
2291 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2296 NEW(abc_exception_t, e)
2297 e->exc_type = 0; //all exceptions
2298 e->var_name = 0; //no name
2301 e->to = code_append(e->to, $4);
2307 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2308 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2309 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2310 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2314 list_append($$.l,$2);
2315 $$.finally = $2->to;$2->to=0;
2318 CATCH_FINALLY_LIST: FINALLY {
2322 list_append($$.l,$1);
2323 $$.finally = $1->to;$1->to=0;
2327 TRY : "try" '{' {PASS12 new_state();
2328 state->method->has_exceptions=1;
2329 state->method->late_binding=1;//for invariant scope_code
2330 } MAYBECODE '}' CATCH_FINALLY_LIST {
2331 code_t*out = abc_nop(0);
2333 code_t*start = abc_nop(0);
2334 $$ = code_append(start, $4);
2335 if(!is_break_or_jump($4)) {
2336 $$ = abc_jump($$, out);
2338 code_t*end = $$ = abc_nop($$);
2342 tmp = new_variable("__finally__", 0, 0, 0);
2344 abc_exception_list_t*l = $6.l;
2347 abc_exception_t*e = l->abc_exception;
2349 $$ = code_append($$, e->target);
2350 $$ = abc_jump($$, out);
2352 parserassert((ptroff_t)$6.finally);
2354 e->target = $$ = abc_nop($$);
2355 $$ = code_append($$, code_dup(state->method->scope_code));
2356 $$ = abc___rethrow__($$);
2364 $$ = code_append($$, out);
2366 $$ = insert_finally($$, $6.finally, tmp);
2368 list_concat(state->method->exceptions, $6.l);
2374 /* ------------ throw ------------------------------- */
2376 THROW : "throw" EXPRESSION {
2380 THROW : "throw" %prec prec_none {
2381 if(!state->exception_name)
2382 syntaxerror("re-throw only possible within a catch block");
2383 variable_t*v = find_variable(state, state->exception_name);
2385 $$=abc_getlocal($$, v->index);
2389 /* ------------ with -------------------------------- */
2391 WITH_HEAD : "with" '(' EXPRESSION ')' {
2393 if(state->method->has_exceptions) {
2394 int v = alloc_local();
2395 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2396 state->method->scope_code = abc_pushwith(state->method->scope_code);
2401 WITH : WITH_HEAD CODEBLOCK {
2402 /* remove getlocal;pushwith from scope code again */
2403 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2406 if(state->method->has_exceptions) {
2408 $$ = abc_setlocal($$, $1.number);
2410 $$ = abc_pushwith($$);
2411 $$ = code_append($$, $2);
2412 $$ = abc_popscope($$);
2416 /* ------------ packages and imports ---------------- */
2418 X_IDENTIFIER: T_IDENTIFIER
2419 | "package" {PASS12 $$="package";}
2420 | "namespace" {PASS12 $$="namespace";}
2421 | T_NAMESPACE {PASS12 $$=$1;}
2423 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2424 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2426 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2427 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2428 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2429 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2432 static void state_has_imports()
2434 state->wildcard_imports = list_clone(state->wildcard_imports);
2435 state->imports = dict_clone(state->imports);
2436 state->has_own_imports = 1;
2438 static void import_toplevel(const char*package)
2440 char* s = strdup(package);
2442 dict_put(state->import_toplevel_packages, s, 0);
2443 char*x = strrchr(s, '.');
2451 IMPORT : "import" PACKAGEANDCLASS {
2453 slotinfo_t*s = registry_find($2->package, $2->name);
2454 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2455 as3_schedule_class($2->package, $2->name);
2459 syntaxerror("Couldn't import class\n");
2460 state_has_imports();
2461 dict_put(state->imports, c->name, c);
2462 import_toplevel(c->package);
2465 IMPORT : "import" PACKAGE '.' '*' {
2467 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2468 as3_schedule_package($2);
2473 state_has_imports();
2474 list_append(state->wildcard_imports, i);
2475 import_toplevel(i->package);
2479 /* ------------ classes and interfaces (header) -------------- */
2481 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2482 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2483 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2484 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2486 $$.flags=$1.flags|$2.flags;
2487 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2488 $$.ns=$1.ns?$1.ns:$2.ns;
2491 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2492 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2493 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2494 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2495 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2496 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2497 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2498 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2499 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2500 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2504 EXTENDS : {PASS12 $$=0;}
2505 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2507 EXTENDS_LIST : {PASS12 $$=list_new();}
2508 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2510 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2511 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2513 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2514 EXTENDS IMPLEMENTS_LIST
2515 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2517 '}' {PASS12 endclass();$$=0;}
2519 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2521 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2522 startclass(&$1,$3,0,$4);}
2523 MAYBE_INTERFACE_BODY
2524 '}' {PASS12 endclass();$$=0;}
2526 /* ------------ classes and interfaces (body) -------------- */
2529 MAYBE_CLASS_BODY : CLASS_BODY
2530 CLASS_BODY : CLASS_BODY_ITEM
2531 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2532 CLASS_BODY_ITEM : ';'
2533 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2534 CLASS_BODY_ITEM : SLOT_DECLARATION
2535 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2537 CLASS_BODY_ITEM : CODE_STATEMENT {
2538 code_t*c = state->cls->static_init->header;
2539 c = code_append(c, $1);
2540 state->cls->static_init->header = c;
2543 MAYBE_INTERFACE_BODY :
2544 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2545 INTERFACE_BODY : IDECLARATION
2546 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2548 IDECLARATION : "var" T_IDENTIFIER {
2549 syntaxerror("variable declarations not allowed in interfaces");
2551 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2553 $1.flags |= FLAG_PUBLIC;
2554 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2555 syntaxerror("invalid method modifiers: interface methods always need to be public");
2557 startfunction(&$1,$3,$4,&$6,$8);
2558 endfunction(&$1,$3,$4,&$6,$8, 0);
2559 list_deep_free($6.list);
2562 /* ------------ classes and interfaces (body, slots ) ------- */
2565 static int slotstate_varconst = 0;
2566 static modifiers_t*slotstate_flags = 0;
2567 static void setslotstate(modifiers_t* flags, int varconst)
2569 slotstate_varconst = varconst;
2570 slotstate_flags = flags;
2573 if(flags->flags&FLAG_STATIC) {
2574 state->method = state->cls->static_init;
2576 state->method = state->cls->init;
2579 // reset to "default" state (all in class code is static by default) */
2580 state->method = state->cls->static_init;
2583 parserassert(state->method);
2586 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2588 int flags = modifiers->flags;
2589 namespace_t ns = modifiers2access(modifiers);
2592 multiname_t mname = {QNAME, &ns, 0, name};
2594 trait_list_t**traits;
2598 ns.name = state->package;
2599 traits = &global->init->traits;
2600 code = &global->init->method->body->code;
2601 } else if(flags&FLAG_STATIC) {
2603 traits = &state->cls->abc->static_traits;
2604 code = &state->cls->static_init->header;
2606 // instance variable
2607 traits = &state->cls->abc->traits;
2608 code = &state->cls->init->header;
2610 if(ns.access == ACCESS_PROTECTED) {
2611 ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
2617 *m = *multiname_clone(&mname);
2619 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2623 VARCONST: "var" | "const"
2625 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2627 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2628 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2630 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2633 int flags = slotstate_flags->flags;
2634 namespace_t ns = modifiers2access(slotstate_flags);
2638 varinfo_t* info = 0;
2640 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2642 check_override(i, flags);
2644 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2646 slotinfo_t*i = registry_find(state->package, $1);
2648 syntaxerror("package %s already contains '%s'", state->package, $1);
2650 if(ns.name && ns.name[0]) {
2651 syntaxerror("namespaces not allowed on package-level variables");
2653 info = varinfo_register_global(ns.access, state->package, $1);
2657 info->flags = flags;
2659 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2663 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2667 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2671 t->type_name = multiname_clone(&m);
2673 info->slot = t->slot_id;
2675 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2676 FIXME: is there a way to use slots and still don't have conflicting overrides?
2678 info->slot = t->slot_id = 0;
2680 constant_t cval = $3->type->eval($3);
2681 if(cval.type!=CONSTANT_UNKNOWN) {
2682 /* compile time constant */
2683 t->value = malloc(sizeof(constant_t));
2684 memcpy(t->value, &cval, sizeof(constant_t));
2685 info->value = constant_clone(t->value);
2687 typedcode_t v = node_read($3);
2688 /* initalization code (if needed) */
2690 if(v.c && !is_pushundefined(v.c)) {
2691 c = abc_getlocal_0(c);
2692 c = code_append(c, v.c);
2693 c = converttype(c, v.t, $2);
2695 c = abc_initproperty2(c, &mname);
2697 c = abc_setslot(c, t->slot_id);
2700 *code = code_append(*code, c);
2703 if(slotstate_varconst==KW_CONST) {
2704 t->kind= TRAIT_CONST;
2705 info->flags |= FLAG_CONST;
2712 /* ------------ constants -------------------------------------- */
2714 MAYBECONSTANT: {$$=0;}
2715 MAYBECONSTANT: '=' E {
2716 $$ = malloc(sizeof(constant_t));
2717 *$$ = node_eval($2);
2718 if($$->type == CONSTANT_UNKNOWN) {
2719 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2723 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2724 CONSTANT : T_INT {$$ = constant_new_int($1);}
2726 $$ = constant_new_uint($1);
2728 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2729 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2730 CONSTANT : "true" {$$ = constant_new_true($1);}
2731 CONSTANT : "false" {$$ = constant_new_false($1);}
2732 CONSTANT : "null" {$$ = constant_new_null($1);}
2733 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2734 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2737 CONSTANT : T_IDENTIFIER {
2738 if(!strcmp($1, "NaN")) {
2739 $$ = constant_new_float(__builtin_nan(""));
2741 as3_warning("Couldn't evaluate constant value of %s", $1);
2742 $$ = constant_new_null($1);
2746 /* ---------------------------xml ------------------------------ */
2749 static int xml_level = 0;
2754 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2755 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2756 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2758 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2760 as3_warning("xml string substitution not yet supported");
2762 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2764 as3_warning("xml string substitution not yet supported");
2767 XMLTEXT : XMLTEXT XMLEXPR1 {
2768 $$ = concat2($1, "{...}");
2770 XMLTEXT : XMLTEXT T_STRING {$$=concat2($1, string_cstr(&$2));}
2771 XMLTEXT : XMLTEXT '>' {$$=concat2($1, ">");}
2773 XML2 : XMLNODE XMLTEXT {$$=concat2($1,$2);}
2774 XML2 : XML2 XMLNODE XMLTEXT {$$=concat3($1,$2,$3);free($1);free($2);free($3);}
2776 XML_ID_OR_EXPR: T_IDENTIFIER {$$=$1;}
2777 XML_ID_OR_EXPR: XMLEXPR2 {$$=$1;}
2779 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2780 $$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2781 free($2);free($3);free($5);free($8);
2783 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2784 $$ = allocprintf("<%s%s/>", $2, $3);
2786 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2787 $$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2788 free($2);free($3);free($5);free($6);free($9);
2791 MAYBE_XMLATTRIBUTES: {$$=strdup("");}
2792 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {$$=concat2(" ",$1);}
2793 XMLATTRIBUTES: XMLATTRIBUTE {$$=$1;}
2794 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {$$=concat3($1," ",$2);free($1);free($2);}
2796 XMLATTRIBUTE: XMLEXPR2 {
2797 $$ = strdup("{...}");
2799 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2800 char* str = string_cstr(&$3);
2801 $$ = concat2("{...}=",str);
2803 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2804 $$ = strdup("{...}={...}");
2806 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2807 $$ = concat2($1,"={...}");
2809 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2810 char* str = string_cstr(&$3);
2811 $$=allocprintf("%s=%s", $1,str);
2813 free($1);free((char*)$3.str);
2816 /* ------------ classes and interfaces (body, functions) ------- */
2818 // non-vararg version
2821 memset(&$$,0,sizeof($$));
2823 MAYBE_PARAM_LIST: PARAM_LIST {
2829 MAYBE_PARAM_LIST: "..." PARAM {
2831 memset(&$$,0,sizeof($$));
2833 list_append($$.list, $2);
2835 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2839 list_append($$.list, $4);
2843 PARAM_LIST: PARAM_LIST ',' PARAM {
2846 list_append($$.list, $3);
2850 memset(&$$,0,sizeof($$));
2851 list_append($$.list, $1);
2854 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2856 $$ = rfx_calloc(sizeof(param_t));
2862 PARAM: T_IDENTIFIER MAYBECONSTANT {
2864 $$ = rfx_calloc(sizeof(param_t));
2866 $$->type = TYPE_ANY;
2874 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2875 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2878 endfunction(&$1,$3,$4,&$6,0,0);
2880 if(!state->method->info) syntaxerror("internal error");
2882 code_t*c = method_header(state->method);
2883 c = wrap_function(c, 0, $11);
2885 endfunction(&$1,$3,$4,&$6,$8,c);
2887 list_deep_free($6.list);
2891 MAYBE_IDENTIFIER: T_IDENTIFIER
2892 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2893 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2894 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2897 endfunction(0,0,$2,&$4,0,0);
2899 methodinfo_t*f = state->method->info;
2900 if(!f || !f->kind) syntaxerror("internal error");
2902 code_t*c = method_header(state->method);
2903 c = wrap_function(c, 0, $9);
2905 int index = state->method->var_index;
2906 endfunction(0,0,$2,&$4,$6,c);
2908 $$.c = abc_getlocal(0, index);
2909 $$.t = TYPE_FUNCTION(f);
2911 PASS12 list_deep_free($4.list);
2915 /* ------------- package + class ids --------------- */
2917 CLASS: X_IDENTIFIER {
2918 PASS1 NEW(unresolvedinfo_t,c);
2919 memset(c, 0, sizeof(*c));
2920 c->kind = INFOTYPE_UNRESOLVED;
2922 c->package = get_package_from_name($1);
2924 c->nsset = get_current_imports();
2925 /* make the compiler look for this class in the current directory,
2927 as3_schedule_class_noerror(state->package, $1);
2929 $$ = (classinfo_t*)c;
2931 slotinfo_t*s = find_class($1);
2932 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2933 $$ = (classinfo_t*)s;
2936 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2937 PASS1 NEW(unresolvedinfo_t,c);
2938 memset(c, 0, sizeof(*c));
2939 c->kind = INFOTYPE_UNRESOLVED;
2942 $$ = (classinfo_t*)c;
2944 slotinfo_t*s = registry_find($1, $3);
2945 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2947 $$ = (classinfo_t*)s;
2950 CLASS_SPEC: PACKAGEANDCLASS
2953 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2954 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2956 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2957 | '*' {PASS12 $$=TYPE_ANY;}
2958 | "void" {PASS12 $$=TYPE_VOID;}
2960 | "String" {$$=registry_getstringclass();}
2961 | "int" {$$=registry_getintclass();}
2962 | "uint" {$$=registry_getuintclass();}
2963 | "Boolean" {$$=registry_getbooleanclass();}
2964 | "Number" {$$=registry_getnumberclass();}
2967 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2968 MAYBETYPE: {PASS12 $$=0;}
2970 /* ----------function calls, delete, constructor calls ------ */
2972 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
2973 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2975 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
2976 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2977 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2979 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
2983 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
2984 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
2985 $$.number= $1.number+1;
2986 $$.cc = code_append($1.cc, $2.c);
2990 NEW : "new" E XX MAYBE_PARAM_VALUES {
2991 typedcode_t v = node_read($2);
2993 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2995 code_t*paramcode = $4.cc;
2996 if($$.c->opcode == OPCODE_GETPROPERTY) {
2997 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2998 $$.c = code_cutlast($$.c);
2999 $$.c = code_append($$.c, paramcode);
3000 $$.c = abc_constructprop2($$.c, name, $4.number);
3001 multiname_destroy(name);
3002 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3004 classinfo_t*c = v.t->data;
3006 $$.c = abc_findpropstrict2(0, &m);
3007 $$.c = code_append($$.c, paramcode);
3008 $$.c = abc_constructprop2($$.c, &m, $4.number);
3009 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3010 int slot = (int)(ptroff_t)$$.c->data[0];
3011 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3012 multiname_t*name = t->name;
3013 $$.c = code_cutlast($$.c);
3014 $$.c = code_append($$.c, paramcode);
3015 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3017 $$.c = code_append($$.c, paramcode);
3018 $$.c = abc_construct($$.c, $4.number);
3022 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3025 $$.c = abc_coerce_a($$.c);
3030 /* TODO: use abc_call (for calling local variables),
3031 abc_callstatic (for calling own methods)
3034 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3036 typedcode_t v = node_read($1);
3038 if($$.c->opcode == OPCODE_COERCE_A) {
3039 $$.c = code_cutlast($$.c);
3041 code_t*paramcode = $3.cc;
3044 if($$.c->opcode == OPCODE_GETPROPERTY) {
3045 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3046 $$.c = code_cutlast($$.c);
3047 $$.c = code_append($$.c, paramcode);
3048 $$.c = abc_callproperty2($$.c, name, $3.number);
3049 multiname_destroy(name);
3050 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3051 int slot = (int)(ptroff_t)$$.c->data[0];
3052 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3053 if(t->kind!=TRAIT_METHOD) {
3054 //ok: flash allows to assign closures to members.
3056 multiname_t*name = t->name;
3057 $$.c = code_cutlast($$.c);
3058 $$.c = code_append($$.c, paramcode);
3059 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3060 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3061 } else if($$.c->opcode == OPCODE_GETSUPER) {
3062 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3063 $$.c = code_cutlast($$.c);
3064 $$.c = code_append($$.c, paramcode);
3065 $$.c = abc_callsuper2($$.c, name, $3.number);
3066 multiname_destroy(name);
3068 $$.c = abc_getglobalscope($$.c);
3069 $$.c = code_append($$.c, paramcode);
3070 $$.c = abc_call($$.c, $3.number);
3073 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3074 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3075 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3076 // calling a class is like a typecast
3077 $$.t = (classinfo_t*)v.t->data;
3079 $$.c = abc_coerce_a($$.c);
3084 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3085 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3086 if(!state->method) syntaxerror("super() not allowed outside of a function");
3087 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3090 $$.c = abc_getlocal_0($$.c);
3092 $$.c = code_append($$.c, $3.cc);
3094 this is dependent on the control path, check this somewhere else
3095 if(state->method->has_super)
3096 syntaxerror("constructor may call super() only once");
3098 state->method->has_super = 1;
3100 $$.c = abc_constructsuper($$.c, $3.number);
3101 $$.c = abc_pushundefined($$.c);
3105 DELETE: "delete" E {
3106 typedcode_t v = node_read($2);
3108 if($$.c->opcode == OPCODE_COERCE_A) {
3109 $$.c = code_cutlast($$.c);
3111 multiname_t*name = 0;
3112 if($$.c->opcode == OPCODE_GETPROPERTY) {
3113 $$.c->opcode = OPCODE_DELETEPROPERTY;
3114 } else if($$.c->opcode == OPCODE_GETSLOT) {
3115 int slot = (int)(ptroff_t)$$.c->data[0];
3116 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3117 $$.c = code_cutlast($$.c);
3118 $$.c = abc_deleteproperty2($$.c, name);
3120 $$.c = abc_getlocal_0($$.c);
3121 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3122 $$.c = abc_deleteproperty2($$.c, &m);
3124 $$.t = TYPE_BOOLEAN;
3127 RETURN: "return" %prec prec_none {
3128 $$ = abc_returnvoid(0);
3130 RETURN: "return" EXPRESSION {
3132 $$ = abc_returnvalue($$);
3135 // ----------------------- expression types -------------------------------------
3137 NONCOMMAEXPRESSION : E %prec below_lt {
3140 EXPRESSION : COMMA_EXPRESSION {
3143 COMMA_EXPRESSION : E %prec below_lt {
3144 $$ = mkmultinode(&node_comma, $1);
3146 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3147 $$ = multinode_extend($1, $3);
3149 VOIDEXPRESSION : E %prec below_minus {
3152 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3154 $$ = code_append($$, node_exec($3));
3157 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3158 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3160 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3161 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3162 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3163 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3164 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3166 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3168 $$.cc = code_append($$.cc, $1);
3169 $$.cc = code_append($$.cc, $3.c);
3172 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3174 $$.number = $1.number+2;
3175 $$.cc = code_append($$.cc, $3);
3176 $$.cc = code_append($$.cc, $5.c);
3179 // ----------------------- expression evaluation -------------------------------------
3181 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3182 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3183 E : NEW {$$ = mkcodenode($1);}
3184 E : DELETE {$$ = mkcodenode($1);}
3185 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3186 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3189 $$ = mkconstnode($1);
3195 multiname_t m = {QNAME, &stdns, 0, "XML"};
3196 v.c = abc_getlex2(v.c, &m);
3197 v.c = abc_pushstring(v.c, $1);
3198 v.c = abc_construct(v.c, 1);
3207 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3209 v.c = abc_getlex2(v.c, &m);
3210 v.c = abc_pushstring(v.c, $1.pattern);
3211 v.c = abc_construct(v.c, 1);
3213 v.c = abc_getlex2(v.c, &m);
3214 v.c = abc_pushstring(v.c, $1.pattern);
3215 v.c = abc_pushstring(v.c, $1.options);
3216 v.c = abc_construct(v.c, 2);
3224 state->method->need_arguments = 1;
3227 v.c = abc_getlocal(0, state->method->need_arguments);
3233 E : '[' MAYBE_EXPRESSION_LIST ']' {
3236 v.c = code_append(v.c, $2.cc);
3237 v.c = abc_newarray(v.c, $2.number);
3238 v.t = registry_getarrayclass();
3243 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3246 v.c = code_append(v.c, $2.cc);
3247 v.c = abc_newobject(v.c, $2.number/2);
3248 v.t = registry_getobjectclass();
3252 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3253 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3254 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3255 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3256 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3257 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3258 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3259 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3260 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3261 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3262 E : '!' E {$$ = mknode1(&node_not, $2);}
3263 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3264 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3265 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3266 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3267 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3268 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3269 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3270 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3271 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3272 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3273 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3274 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3275 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3276 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3277 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3278 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3279 E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
3280 E : "void" E {$$ = mknode1(&node_void, $2);}
3281 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3282 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3283 E : '-' E {$$ = mknode1(&node_neg, $2);}
3284 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3285 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3286 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3287 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3288 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3289 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3290 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3291 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3292 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3293 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3294 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3295 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3296 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3297 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3299 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3300 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3301 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3302 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3304 E : "super" '.' T_IDENTIFIER
3305 { if(!state->cls->info)
3306 syntaxerror("super keyword not allowed outside a class");
3307 classinfo_t*t = state->cls->info->superclass;
3308 if(!t) t = TYPE_OBJECT;
3309 memberinfo_t*f = findmember_nsset(t, $3, 1);
3310 MEMBER_MULTINAME(m, f, $3);
3313 v.c = abc_getlocal_0(v.c);
3314 v.c = abc_getsuper2(v.c, &m);
3315 v.t = slotinfo_gettype((slotinfo_t*)f);
3319 E : '@' T_IDENTIFIER {
3321 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3322 v.c = abc_getlex2(0, &m);
3327 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3330 typedcode_t v = node_read($1);
3331 typedcode_t w = node_read($5);
3333 int index = alloc_local();
3334 int result = alloc_local();
3335 int tmp = alloc_local();
3336 int xml = alloc_local();
3338 c = code_append(c, v.c);
3339 c = abc_checkfilter(c);
3340 c = abc_coerce_a(c); //hasnext2 converts to *
3341 c = abc_setlocal(c, xml);
3342 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3343 c = abc_getlex2(c, &m);
3344 c = abc_construct(c, 0);
3345 c = abc_setlocal(c, result);
3346 c = abc_pushbyte(c, 0);
3347 c = abc_setlocal(c, index);
3348 code_t*jmp = c = abc_jump(c, 0);
3349 code_t*loop = c = abc_label(c);
3350 c = abc_getlocal(c, xml);
3351 c = abc_getlocal(c, index);
3352 c = abc_nextvalue(c);
3354 c = abc_setlocal(c, tmp);
3355 c = abc_pushwith(c);
3356 c = code_append(c, w.c);
3357 c = abc_popscope(c);
3358 code_t*b = c = abc_iffalse(c, 0);
3359 c = abc_getlocal(c, result);
3360 c = abc_getlocal(c, index);
3361 c = abc_getlocal(c, tmp);
3362 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3363 c = abc_setproperty2(c, &m2);
3364 c = b->branch = jmp->branch = abc_nop(c);
3365 c = abc_kill(c, tmp);
3366 c = abc_hasnext2(c, xml, index);
3367 c = abc_iftrue(c, loop);
3368 c = abc_getlocal(c, result);
3369 c = abc_kill(c, xml);
3370 c = abc_kill(c, result);
3371 c = abc_kill(c, index);
3381 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3382 ID_OR_NS : '*' {$$="*";}
3383 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3384 SUBNODE: X_IDENTIFIER
3388 MAYBE_NS: T_IDENTIFIER "::" {$$=$1;}
3389 | T_NAMESPACE "::" {$$=(char*)$1;}
3390 | '*' "::" {$$="*";}
3393 E : E '.' ID_OR_NS "::" SUBNODE {
3394 typedcode_t v = node_read($1);
3395 typedcode_t w = node_read(resolve_identifier($3));
3396 v.c = code_append(v.c, w.c);
3397 if(!TYPE_IS_NAMESPACE(w.t)) {
3398 as3_softwarning("%s might not be a namespace", $3);
3400 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3401 multiname_t m = {RTQNAME, 0, 0, $5};
3402 v.c = abc_getproperty2(v.c, &m);
3403 if(TYPE_IS_XML(v.t)) {
3406 v.c = abc_coerce_a(v.c);
3411 E : E ".." SUBNODE {
3412 typedcode_t v = node_read($1);
3413 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3414 v.c = abc_getdescendants2(v.c, &m);
3418 E : E '.' '[' E ']' {
3419 typedcode_t v = node_read($1);
3420 typedcode_t w = node_read($4);
3421 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3422 v.c = code_append(v.c, w.c);
3423 v.c = converttype(w.c, w.t, TYPE_STRING);
3424 v.c = abc_getproperty2(v.c, &m);
3429 E : E '.' '@' SUBNODE {
3430 typedcode_t v = node_read($1);
3431 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3432 v.c = abc_getproperty2(v.c, &m);
3436 E : E ".." '@' SUBNODE {
3437 typedcode_t v = node_read($1);
3438 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3439 v.c = abc_getdescendants2(v.c, &m);
3443 E : E '.' '@' '[' E ']' {
3444 typedcode_t v = node_read($1);
3445 typedcode_t w = node_read($5);
3446 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3447 v.c = code_append(v.c, w.c);
3448 v.c = converttype(w.c, w.t, TYPE_STRING);
3449 v.c = abc_getproperty2(v.c, &m);
3453 E : E ".." '@' '[' E ']' {
3454 typedcode_t v = node_read($1);
3455 typedcode_t w = node_read($5);
3456 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3457 v.c = code_append(v.c, w.c);
3458 v.c = converttype(w.c, w.t, TYPE_STRING);
3459 v.c = abc_getdescendants2(v.c, &m);
3464 MEMBER : E '.' SUBNODE {
3465 typedcode_t v1 = node_read($1);
3467 classinfo_t*t = v1.t;
3469 if(TYPE_IS_CLASS(t) && t->data) {
3473 if(TYPE_IS_XML(t)) {
3474 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3475 $$.c = abc_getproperty2($$.c, &m);
3476 $$.c = abc_coerce_a($$.c);
3477 $$.t = TYPE_XMLLIST;
3479 if(t->subtype==INFOTYPE_UNRESOLVED) {
3480 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3482 memberinfo_t*f = findmember_nsset(t, $3, 1);
3484 if(f && !is_static != !(f->flags&FLAG_STATIC))
3486 if(f && f->slot && !noslot) {
3487 $$.c = abc_getslot($$.c, f->slot);
3490 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3492 MEMBER_MULTINAME(m, f, $3);
3493 $$.c = abc_getproperty2($$.c, &m);
3495 /* determine type */
3496 $$.t = slotinfo_gettype((slotinfo_t*)f);
3498 $$.c = abc_coerce_a($$.c);
3500 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3501 string_t*package = v1.c->data[0];
3502 char*package2 = concat3(package->str, ".", $3);
3504 slotinfo_t*a = registry_find(package->str, $3);
3507 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3508 registry_ispackage(package2)) {
3510 $$.c->data[0] = string_new4(package2);
3513 syntaxerror("couldn't resolve %s", package2);
3516 /* when resolving a property on an unknown type, we do know the
3517 name of the property (and don't seem to need the package), but
3518 we need to make avm2 try out all access modes */
3519 as3_softwarning("Resolving %s on unknown type", $3);
3520 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3521 $$.c = abc_getproperty2($$.c, &m);
3522 $$.c = abc_coerce_a($$.c);
3528 node_t* resolve_identifier(char*name)
3538 /* look at variables */
3539 if((v = find_variable(state, name))) {
3540 // name is a local variable
3541 o.c = abc_getlocal(o.c, v->index);
3543 return mkcodenode(o);
3545 if((v = find_slot(state, name))) {
3546 o.c = abc_getscopeobject(o.c, 1);
3547 o.c = abc_getslot(o.c, v->index);
3549 return mkcodenode(o);
3552 int i_am_static = state->method->is_static;
3554 /* look at current class' members */
3555 if(!state->method->inner &&
3556 !state->xmlfilter &&
3558 (f = findmember_nsset(state->cls->info, name, 1)))
3560 // name is a member or attribute in this class
3561 int var_is_static = (f->flags&FLAG_STATIC);
3563 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3564 /* if the variable is a constant (and we know what is evaluates to), we
3565 can just use the value itself */
3566 varinfo_t*v = (varinfo_t*)f;
3568 return mkconstnode(v->value);
3572 if(var_is_static >= i_am_static) {
3573 if(f->kind == INFOTYPE_METHOD) {
3574 o.t = TYPE_FUNCTION(f);
3579 if(var_is_static && !i_am_static) {
3580 /* access to a static member from a non-static location.
3581 do this via findpropstrict:
3582 there doesn't seem to be any non-lookup way to access
3583 static properties of a class */
3584 state->method->late_binding = 1;
3586 namespace_t ns = {f->access, f->package};
3587 multiname_t m = {QNAME, &ns, 0, name};
3588 o.c = abc_findpropstrict2(o.c, &m);
3589 o.c = abc_getproperty2(o.c, &m);
3590 return mkcodenode(o);
3591 } else if(f->slot>0) {
3592 o.c = abc_getlocal_0(o.c);
3593 o.c = abc_getslot(o.c, f->slot);
3594 return mkcodenode(o);
3596 MEMBER_MULTINAME(m, f, name);
3597 o.c = abc_getlocal_0(o.c);
3598 o.c = abc_getproperty2(o.c, &m);
3599 return mkcodenode(o);
3604 /* look at actual classes, in the current package and imported */
3605 if(!state->xmlfilter && (a = find_class(name))) {
3606 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3607 o.c = abc_getlocal_0(0);
3608 o.t = TYPE_CLASS((classinfo_t*)a);
3612 return mkcodenode(o);
3615 /* look through package prefixes */
3616 if(!state->xmlfilter &&
3617 (dict_contains(state->import_toplevel_packages, name) ||
3618 registry_ispackage(name))) {
3619 o.c = abc___pushpackage__(o.c, name);
3621 return mkcodenode(o); //?
3624 /* unknown object, let the avm2 resolve it */
3626 if(!state->method->inner && !state->xmlfilter) {
3627 /* we really should make inner functions aware of the class context */
3628 as3_warning("Couldn't resolve '%s', doing late binding", name);
3630 state->method->late_binding = 1;
3632 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3635 o.c = abc_findpropstrict2(o.c, &m);
3636 o.c = abc_getproperty2(o.c, &m);
3637 return mkcodenode(o);
3642 VAR_READ : T_IDENTIFIER {
3644 /* Queue unresolved identifiers for checking against the parent
3645 function's variables.
3646 We consider everything which is not a local variable "unresolved".
3647 This encompasses class names, members of the surrounding class
3648 etc. which is *correct* because local variables of the parent function
3652 if(!find_variable(state, $1)) {
3653 if(state->method->inner) {
3654 unknown_variable($1);
3656 /* let the compiler know that it might want to check the current directory/package
3657 for this identifier- maybe there's a file $1.as defining $1. */
3658 as3_schedule_class_noerror(state->package, $1);
3664 $$ = resolve_identifier($1);
3667 // ----------------- namespaces -------------------------------------------------
3670 void add_active_url(const char*url)
3674 list_append(state->active_namespace_urls, n);
3678 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3680 NEW(namespace_decl_t,n);
3685 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3687 NEW(namespace_decl_t,n);
3692 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3694 NEW(namespace_decl_t,n);
3699 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3701 trie_put(active_namespaces, $2->name, (void*)$2->url);
3703 namespace_t access = modifiers2access(&$1);
3704 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3705 var->type = TYPE_NAMESPACE;
3707 ns.access = ACCESS_NAMESPACE;
3709 var->value = constant_new_namespace(&ns);
3712 MULTINAME(m, TYPE_NAMESPACE);
3713 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3714 t->value = var->value;
3715 t->type_name = multiname_clone(&m);
3721 DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
3723 as3_warning("default xml namespaces not supported yet");
3726 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3728 const char*url = $3->name;
3730 varinfo_t*s = (varinfo_t*)$3;
3731 if(s->kind == INFOTYPE_UNRESOLVED) {
3732 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3734 syntaxerror("Couldn't resolve namespace %s", $3->name);
3737 if(!s || s->kind != INFOTYPE_VAR)
3738 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3739 if(!s->value || !NS_TYPE(s->value->type))
3740 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3741 url = s->value->ns->name;
3743 trie_put(active_namespaces, $3->name, (void*)url);
3744 add_active_url(url);