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_PUBLIC "public"
98 %token<token> KW_PRIVATE "private"
99 %token<token> KW_USE "use"
100 %token<token> KW_INTERNAL "internal"
101 %token<token> KW_NEW "new"
102 %token<token> KW_NATIVE "native"
103 %token<token> KW_FUNCTION "function"
104 %token<token> KW_FINALLY "finally"
105 %token<token> KW_UNDEFINED "undefined"
106 %token<token> KW_NAN "NaN"
107 %token<token> KW_CONTINUE "continue"
108 %token<token> KW_CLASS "class"
109 %token<token> KW_CONST "const"
110 %token<token> KW_CATCH "catch"
111 %token<token> KW_CASE "case"
112 %token<token> KW_SET "set"
113 %token<token> KW_VOID "void"
114 %token<token> KW_THROW "throw"
115 %token<token> KW_STATIC "static"
116 %token<token> KW_WITH "with"
117 %token<token> KW_INSTANCEOF "instanceof"
118 %token<token> KW_IMPORT "import"
119 %token<token> KW_RETURN "return"
120 %token<token> KW_TYPEOF "typeof"
121 %token<token> KW_INTERFACE "interface"
122 %token<token> KW_NULL "null"
123 %token<token> KW_VAR "var"
124 %token<token> KW_DYNAMIC "dynamic"
125 %token<token> KW_OVERRIDE "override"
126 %token<token> KW_FINAL "final"
127 %token<token> KW_EACH "each"
128 %token<token> KW_GET "get"
129 %token<token> KW_TRY "try"
130 %token<token> KW_SUPER "super"
131 %token<token> KW_EXTENDS "extends"
132 %token<token> KW_FALSE "false"
133 %token<token> KW_TRUE "true"
134 %token<token> KW_BOOLEAN "Boolean"
135 %token<token> KW_UINT "uint"
136 %token<token> KW_INT "int"
137 %token<token> KW_NUMBER "Number"
138 %token<token> KW_STRING "String"
139 %token<token> KW_DEFAULT "default"
140 %token<token> KW_DELETE "delete"
141 %token<token> KW_IF "if"
142 %token<token> KW_ELSE "else"
143 %token<token> KW_BREAK "break"
144 %token<token> KW_IS "is"
145 %token<token> KW_IN "in"
146 %token<token> KW_AS "as"
148 %token<token> T_DICTSTART "{ (dictionary)"
149 %token<token> T_EQEQ "=="
150 %token<token> T_EQEQEQ "==="
151 %token<token> T_NE "!="
152 %token<token> T_NEE "!=="
153 %token<token> T_LE "<="
154 %token<token> T_GE ">="
155 %token<token> T_ORBY "|="
156 %token<token> T_DIVBY "/="
157 %token<token> T_MODBY "%="
158 %token<token> T_MULBY "*="
159 %token<token> T_ANDBY "&="
160 %token<token> T_PLUSBY "+="
161 %token<token> T_MINUSBY "-="
162 %token<token> T_XORBY "^="
163 %token<token> T_SHRBY ">>="
164 %token<token> T_SHLBY "<<="
165 %token<token> T_USHRBY ">>>="
166 %token<token> T_OROR "||"
167 %token<token> T_ANDAND "&&"
168 %token<token> T_COLONCOLON "::"
169 %token<token> T_MINUSMINUS "--"
170 %token<token> T_PLUSPLUS "++"
171 %token<token> T_DOTDOT ".."
172 %token<token> T_DOTDOTDOT "..."
173 %token<token> T_SHL "<<"
174 %token<token> T_USHR ">>>"
175 %token<token> T_SHR ">>"
177 %type <number_int> CONDITIONAL_COMPILATION
178 %type <for_start> FOR_START
179 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER ID_OR_NS SUBNODE
180 %type <namespace_decl> NAMESPACE_ID
181 %type <token> VARCONST
183 %type <code> CODEPIECE CODE_STATEMENT
184 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
185 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
186 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
187 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
188 %type <exception> CATCH FINALLY
189 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
190 %type <code> CLASS_DECLARATION
191 %type <code> NAMESPACE_DECLARATION
192 %type <code> INTERFACE_DECLARATION
193 %type <code> VOIDEXPRESSION
194 %type <value> EXPRESSION NONCOMMAEXPRESSION
195 %type <node> MAYBEEXPRESSION
197 %type <node> E COMMA_EXPRESSION
198 %type <node> VAR_READ
199 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
200 %type <value> INNERFUNCTION
201 %type <code> USE_NAMESPACE
202 %type <code> FOR_INIT
204 %type <classinfo> MAYBETYPE
207 %type <params> PARAM_LIST
208 %type <params> MAYBE_PARAM_LIST
209 %type <flags> MAYBE_MODIFIERS
210 %type <flags> MODIFIER_LIST
211 %type <flags> MODIFIER
212 %type <constant> CONSTANT MAYBECONSTANT
213 %type <classinfo_list> IMPLEMENTS_LIST
214 %type <classinfo> EXTENDS CLASS_SPEC
215 %type <classinfo_list> EXTENDS_LIST
216 %type <classinfo> CLASS PACKAGEANDCLASS
217 %type <classinfo_list> CLASS_SPEC_LIST
218 %type <id> XML XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT
219 %type <classinfo> TYPE
220 //%type <token> VARIABLE
223 //%type <token> T_IDENTIFIER
224 %type <value> FUNCTIONCALL
225 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES
226 %type <value_list> MAYBE_DICT_EXPRPAIR_LIST DICT_EXPRPAIR_LIST WITH_HEAD
229 // precedence: from low to high
233 %left below_semicolon
236 %nonassoc below_assignment // for ?:, contrary to spec
237 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
244 %nonassoc "==" "!=" "===" "!=="
245 %nonassoc "is" "as" "in"
247 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
248 %left "<<" ">>" ">>>"
252 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
254 %nonassoc below_curly
258 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
261 %left above_identifier
265 // needed for "return" precedence:
266 %nonassoc T_STRING T_REGEXP
267 %nonassoc T_INT T_UINT T_FLOAT KW_NAN
268 %nonassoc "false" "true" "null" "undefined" "super" "function"
275 static int a3_error(char*s)
277 syntaxerror("%s", s);
278 return 0; //make gcc happy
281 static void parsererror(const char*file, int line, const char*f)
283 syntaxerror("internal error in %s, %s:%d", f, file, line);
286 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
289 static char* concat2(const char* t1, const char* t2)
293 char*text = malloc(l1+l2+1);
294 memcpy(text , t1, l1);
295 memcpy(text+l1, t2, l2);
299 static char* concat3(const char* t1, const char* t2, const char* t3)
304 char*text = malloc(l1+l2+l3+1);
305 memcpy(text , t1, l1);
306 memcpy(text+l1, t2, l2);
307 memcpy(text+l1+l2, t3, l3);
312 typedef struct _import {
315 DECLARE_LIST(import);
317 DECLARE(methodstate);
318 DECLARE_LIST(methodstate);
320 typedef struct _classstate {
326 methodstate_t*static_init;
328 //code_t*static_init;
330 char has_constructor;
333 struct _methodstate {
343 dict_t*unresolved_variables;
346 char uses_parent_function;
352 int var_index; // for inner methods
353 int slot_index; // for inner methods
354 char is_a_slot; // for inner methods
359 abc_exception_list_t*exceptions;
361 methodstate_list_t*innerfunctions;
364 typedef struct _state {
369 import_list_t*wildcard_imports;
370 dict_t*import_toplevel_packages;
373 namespace_list_t*active_namespace_urls;
375 char has_own_imports;
376 char new_vars; // e.g. transition between two functions
379 methodstate_t*method;
386 dict_t*allvars; // also contains variables from sublevels
389 typedef struct _global {
392 parsedclass_list_t*classes;
393 abc_script_t*classinit;
395 abc_script_t*init; //package-level code
398 dict_t*file2token2info;
401 static global_t*global = 0;
402 static state_t* state = 0;
406 #define MEMBER_MULTINAME(m,f,n) \
410 if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
411 m##_ns.name = ((slotinfo_t*)(f))->package; \
416 m.namespace_set = 0; \
417 m.name = ((slotinfo_t*)(f))->name; \
419 m.type = MULTINAME; \
421 m.namespace_set = &nopackage_namespace_set; \
425 /* warning: list length of namespace set is undefined */
426 #define MULTINAME_LATE(m, access, package) \
427 namespace_t m##_ns = {access, package}; \
428 namespace_set_t m##_nsset; \
429 namespace_list_t m##_l;m##_l.next = 0; \
430 m##_nsset.namespaces = &m##_l; \
431 m##_nsset = m##_nsset; \
432 m##_l.namespace = &m##_ns; \
433 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
435 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
436 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
437 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
438 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
439 static namespace_list_t nl4 = {&ns4,0};
440 static namespace_list_t nl3 = {&ns3,&nl4};
441 static namespace_list_t nl2 = {&ns2,&nl3};
442 static namespace_list_t nl1 = {&ns1,&nl2};
443 static namespace_set_t nopackage_namespace_set = {&nl1};
445 static dict_t*definitions=0;
446 void as3_set_define(const char*c)
449 definitions = dict_new();
450 if(!dict_contains(definitions,c))
451 dict_put(definitions,c,0);
454 static void new_state()
457 state_t*oldstate = state;
459 memcpy(s, state, sizeof(state_t)); //shallow copy
461 s->imports = dict_new();
463 if(!s->import_toplevel_packages) {
464 s->import_toplevel_packages = dict_new();
468 state->has_own_imports = 0;
469 state->vars = dict_new();
470 state->old = oldstate;
473 trie_remember(active_namespaces);
476 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
479 static void state_destroy(state_t*state)
481 if(state->has_own_imports) {
482 list_free(state->wildcard_imports);
483 dict_destroy(state->imports);state->imports=0;
485 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
486 dict_destroy(state->imports);state->imports=0;
489 dict_destroy(state->vars);state->vars=0;
491 if(state->new_vars && state->allvars) {
492 parserassert(!state->old || state->old->allvars != state->allvars);
493 DICT_ITERATE_DATA(state->allvars, void*, data) {
496 dict_destroy(state->allvars);
499 list_free(state->active_namespace_urls)
500 state->active_namespace_urls = 0;
505 static void old_state()
507 trie_rollback(active_namespaces);
509 if(!state || !state->old)
510 syntaxerror("invalid nesting");
511 state_t*leaving = state;
515 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
516 free(leaving->method);
519 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
524 state_destroy(leaving);
527 static code_t* method_header(methodstate_t*m);
528 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
529 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
532 static char* internal_filename_package = 0;
533 void initialize_file(char*filename)
536 syntaxerror("invalid call to initialize_file during parsing of another file");
539 active_namespaces = trie_new();
542 state->package = internal_filename_package = strdup(filename);
543 state->allvars = dict_new();
545 global->token2info = dict_lookup(global->file2token2info,
546 current_filename // use long version
548 if(!global->token2info) {
549 global->token2info = dict_new2(&ptr_type);
550 dict_put(global->file2token2info, current_filename, global->token2info);
554 state->method = rfx_calloc(sizeof(methodstate_t));
555 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
556 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
558 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
560 syntaxerror("internal error: skewed tokencount");
561 function_initvars(state->method, 0, 0, 1);
562 global->init = abc_initscript(global->file);
568 if(!state || state->level!=1) {
569 syntaxerror("unexpected end of file in pass %d", as3_pass);
573 dict_del(global->file2token2info, current_filename);
574 code_t*header = method_header(state->method);
575 code_t*c = wrap_function(header, 0, global->init->method->body->code);
576 global->init->method->body->code = abc_returnvoid(c);
577 free(state->method);state->method=0;
580 //free(state->package);state->package=0; // used in registry
581 state_destroy(state);state=0;
584 void initialize_parser()
586 global = rfx_calloc(sizeof(global_t));
587 global->file = abc_file_new();
588 global->file->flags &= ~ABCFILE_LAZY;
589 global->file2token2info = dict_new();
590 global->token2info = 0;
591 global->classinit = abc_initscript(global->file);
594 void* finish_parser()
596 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
597 global->token2info=0;
599 initcode_add_classlist(global->classinit, global->classes);
604 typedef struct _variable {
609 methodstate_t*is_inner_method;
612 static variable_t* find_variable(state_t*s, char*name)
617 v = dict_lookup(s->vars, name);
619 if(s->new_vars) break;
622 return dict_lookup(top->allvars, name);
624 static variable_t* find_slot(state_t*s, const char*name)
626 if(s->method && s->method->slots)
627 return dict_lookup(s->method->slots, name);
631 static variable_t* find_variable_safe(state_t*s, char*name)
633 variable_t* v = find_variable(s, name);
635 syntaxerror("undefined variable: %s", name);
639 static char variable_exists(char*name)
641 return dict_contains(state->vars, name);
644 static code_t*defaultvalue(code_t*c, classinfo_t*type)
646 if(TYPE_IS_INT(type)) {
647 c = abc_pushbyte(c, 0);
648 } else if(TYPE_IS_UINT(type)) {
649 c = abc_pushuint(c, 0);
650 } else if(TYPE_IS_FLOAT(type)) {
652 } else if(TYPE_IS_BOOLEAN(type)) {
653 c = abc_pushfalse(c);
655 //c = abc_pushundefined(c);
656 syntaxerror("internal error: can't generate default value for * type");
660 c = abc_coerce2(c, &m);
665 static int alloc_local()
667 return state->method->variable_count++;
670 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
673 variable_t*v = find_slot(state, name);
679 v->index = alloc_local();
684 dict_put(state->vars, name, v);
685 dict_put(state->allvars, name, v);
690 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
692 return new_variable2(name, type, init, maybeslot)->index;
695 #define TEMPVARNAME "__as3_temp__"
698 variable_t*v = find_variable(state, TEMPVARNAME);
703 i = new_variable(TEMPVARNAME, 0, 0, 0);
708 static code_t* var_block(code_t*body)
714 for(t=0;t<state->vars->hashsize;t++) {
715 dictentry_t*e = state->vars->slots[t];
717 variable_t*v = (variable_t*)e->data;
718 if(v->type && v->init) {
719 c = defaultvalue(c, v->type);
720 c = abc_setlocal(c, v->index);
721 k = abc_kill(k, v->index);
731 if(x->opcode== OPCODE___BREAK__ ||
732 x->opcode== OPCODE___CONTINUE__) {
733 /* link kill code before break/continue */
734 code_t*e = code_dup(k);
735 code_t*s = code_start(e);
747 c = code_append(c, body);
748 c = code_append(c, k);
752 static void unknown_variable(char*name)
754 if(!state->method->unresolved_variables)
755 state->method->unresolved_variables = dict_new();
756 if(!dict_contains(state->method->unresolved_variables, name))
757 dict_put(state->method->unresolved_variables, name, 0);
760 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
762 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
763 c = abc_getlocal_0(c);
764 c = abc_pushscope(c);
767 /* FIXME: this alloc_local() causes variable indexes to be
768 different in pass2 than in pass1 */
769 if(!m->activation_var)
770 m->activation_var = alloc_local();
772 c = abc_newactivation(c);
774 c = abc_pushscope(c);
775 c = abc_setlocal(c, m->activation_var);
777 c = abc_getlocal(c, m->activation_var);
778 c = abc_pushscope(c);
784 static code_t* method_header(methodstate_t*m)
788 c = add_scope_code(c, m, 1);
790 methodstate_list_t*l = m->innerfunctions;
792 parserassert(l->methodstate->abc);
793 if(m->uses_slots && l->methodstate->is_a_slot) {
794 c = abc_getscopeobject(c, 1);
795 c = abc_newfunction(c, l->methodstate->abc);
797 c = abc_setlocal(c, l->methodstate->var_index);
798 c = abc_setslot(c, l->methodstate->slot_index);
800 c = abc_newfunction(c, l->methodstate->abc);
801 c = abc_setlocal(c, l->methodstate->var_index);
803 free(l->methodstate);l->methodstate=0;
807 c = code_append(c, m->header);
810 if(m->is_constructor && !m->has_super) {
811 // call default constructor
812 c = abc_getlocal_0(c);
813 c = abc_constructsuper(c, 0);
817 /* all parameters that are used by inner functions
818 need to be copied from local to slot */
819 parserassert(m->activation_var);
820 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
821 if(v->is_parameter) {
822 c = abc_getlocal(c, m->activation_var);
823 c = abc_getlocal(c, v->index);
824 c = abc_setslot(c, v->index);
828 list_free(m->innerfunctions);
829 m->innerfunctions = 0;
834 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
836 c = code_append(c, header);
837 c = code_append(c, var_block(body));
838 /* append return if necessary */
839 if(!c || (c->opcode != OPCODE_RETURNVOID &&
840 c->opcode != OPCODE_RETURNVALUE)) {
841 c = abc_returnvoid(c);
846 static void startpackage(char*name)
849 state->package = strdup(name);
851 static void endpackage()
853 //used e.g. in classinfo_register:
854 //free(state->package);state->package=0;
858 #define FLAG_PUBLIC 256
859 #define FLAG_PROTECTED 512
860 #define FLAG_PRIVATE 1024
861 #define FLAG_PACKAGEINTERNAL 2048
862 #define FLAG_NAMESPACE 4096
864 static namespace_t modifiers2access(modifiers_t*mod)
869 if(mod->flags&FLAG_NAMESPACE) {
870 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
871 syntaxerror("invalid combination of access levels and namespaces");
872 ns.access = ACCESS_NAMESPACE;
874 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
876 /* shouldn't happen- the tokenizer only reports something as a namespace
877 if it was already registered */
878 trie_dump(active_namespaces);
879 syntaxerror("unknown namespace: %s", mod->ns);
882 } else if(mod->flags&FLAG_PUBLIC) {
883 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
884 syntaxerror("invalid combination of access levels");
885 ns.access = ACCESS_PACKAGE;
886 } else if(mod->flags&FLAG_PRIVATE) {
887 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
888 syntaxerror("invalid combination of access levels");
889 ns.access = ACCESS_PRIVATE;
890 } else if(mod->flags&FLAG_PROTECTED) {
891 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
892 syntaxerror("invalid combination of access levels");
893 ns.access = ACCESS_PROTECTED;
895 ns.access = ACCESS_PACKAGEINTERNAL;
899 static slotinfo_t* find_class(const char*name);
901 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
903 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
906 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
911 index = new_variable("this", 0, 0, 0);
912 else if(!m->is_global)
913 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
915 index = new_variable("globalscope", 0, 0, 0);
916 parserassert(!index);
920 /* as variables and slots share the same number, make sure
921 that those variable indices are reserved. It's up to the
922 optimizer to later shuffle the variables down to lower
924 m->variable_count = m->uses_slots;
929 for(p=params->list;p;p=p->next) {
930 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
935 methodstate_list_t*l = m->innerfunctions;
937 methodstate_t*m = l->methodstate;
939 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
940 m->var_index = v->index;
941 m->slot_index = v->index;
942 v->is_inner_method = m;
948 m->scope_code = add_scope_code(m->scope_code, m, 0);
951 if(as3_pass==2 && m->slots) {
952 /* exchange unresolved identifiers with the actual objects */
953 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
954 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
955 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
956 if(!type || type->kind != INFOTYPE_CLASS) {
957 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
966 char*as3_globalclass=0;
967 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
970 syntaxerror("inner classes now allowed");
975 classinfo_list_t*mlist=0;
977 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
978 syntaxerror("invalid modifier(s)");
980 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
981 syntaxerror("public and internal not supported at the same time.");
983 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
984 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
985 // all classes extend object
986 extends = registry_getobjectclass();
989 /* create the class name, together with the proper attributes */
993 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
994 access = ACCESS_PRIVATE; package = internal_filename_package;
995 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
996 access = ACCESS_PACKAGEINTERNAL; package = state->package;
997 } else if(state->package!=internal_filename_package) {
998 access = ACCESS_PACKAGE; package = state->package;
1000 syntaxerror("public classes only allowed inside a package");
1004 state->cls = rfx_calloc(sizeof(classstate_t));
1005 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1006 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1007 state->cls->static_init->variable_count=1;
1008 /* notice: we make no effort to initialize the top variable (local0) here,
1009 even though it has special meaning. We just rely on the facat
1010 that pass 1 won't do anything with variables */
1012 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1014 /* set current method to constructor- all code within the class-level (except
1015 static variable initializations) will be executed during construction time */
1016 state->method = state->cls->init;
1018 if(registry_find(package, classname)) {
1019 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1021 /* build info struct */
1022 int num_interfaces = (list_length(implements));
1023 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1024 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1025 state->cls->info->superclass = extends;
1028 classinfo_list_t*l = implements;
1029 for(l=implements;l;l=l->next) {
1030 state->cls->info->interfaces[pos++] = l->classinfo;
1035 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1037 state->method = state->cls->init;
1038 parserassert(state->cls && state->cls->info);
1040 function_initvars(state->cls->init, 0, 0, 1);
1041 function_initvars(state->cls->static_init, 0, 0, 0);
1043 if(extends && (extends->flags & FLAG_FINAL))
1044 syntaxerror("Can't extend final class '%s'", extends->name);
1047 while(state->cls->info->interfaces[pos]) {
1048 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1049 syntaxerror("'%s' is not an interface",
1050 state->cls->info->interfaces[pos]->name);
1054 /* generate the abc code for this class */
1055 MULTINAME(classname2,state->cls->info);
1056 multiname_t*extends2 = sig2mname(extends);
1058 /* don't add the class to the class index just yet- that will be done later
1060 state->cls->abc = abc_class_new(0, &classname2, extends2);
1061 state->cls->abc->file = global->file;
1063 multiname_destroy(extends2);
1064 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1065 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1066 if(state->cls->info->flags&FLAG_INTERFACE) {
1067 abc_class_interface(state->cls->abc);
1070 abc_class_protectedNS(state->cls->abc, classname);
1072 for(mlist=implements;mlist;mlist=mlist->next) {
1073 MULTINAME(m, mlist->classinfo);
1074 abc_class_add_interface(state->cls->abc, &m);
1077 NEW(parsedclass_t,p);
1078 p->cls = state->cls->info;
1079 p->abc = state->cls->abc;
1080 list_append(global->classes, p);
1082 /* flash.display.MovieClip handling */
1083 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1084 if(state->package && state->package[0]) {
1085 as3_globalclass = concat3(state->package, ".", classname);
1087 as3_globalclass = strdup(classname);
1093 static void endclass()
1096 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1098 c = abc_getlocal_0(c);
1099 c = abc_constructsuper(c, 0);
1100 state->cls->init->header = code_append(state->cls->init->header, c);
1101 state->cls->has_constructor=1;
1103 if(state->cls->init) {
1104 if(state->cls->info->flags&FLAG_INTERFACE) {
1105 if(state->cls->init->header)
1106 syntaxerror("interface can not have class-level code");
1108 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1109 code_t*c = method_header(state->cls->init);
1110 m->body->code = wrap_function(c, 0, m->body->code);
1113 if(state->cls->static_init) {
1114 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1115 code_t*c = method_header(state->cls->static_init);
1116 m->body->code = wrap_function(c, 0, m->body->code);
1123 void check_code_for_break(code_t*c)
1126 if(c->opcode == OPCODE___BREAK__) {
1127 char*name = string_cstr(c->data[0]);
1128 syntaxerror("Unresolved \"break %s\"", name);
1130 if(c->opcode == OPCODE___CONTINUE__) {
1131 char*name = string_cstr(c->data[0]);
1132 syntaxerror("Unresolved \"continue %s\"", name);
1134 if(c->opcode == OPCODE___RETHROW__) {
1135 syntaxerror("Unresolved \"rethrow\"");
1137 if(c->opcode == OPCODE___FALLTHROUGH__) {
1138 syntaxerror("Unresolved \"fallthrough\"");
1140 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1141 char*name = string_cstr(c->data[0]);
1142 syntaxerror("Can't reference a package (%s) as such", name);
1148 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1150 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1151 if(TYPE_IS_NUMBER(t)) {
1152 xassert(c->type == CONSTANT_FLOAT
1153 || c->type == CONSTANT_INT
1154 || c->type == CONSTANT_UINT);
1155 } else if(TYPE_IS_UINT(t)) {
1156 xassert(c->type == CONSTANT_UINT ||
1157 (c->type == CONSTANT_INT && c->i>=0));
1158 } else if(TYPE_IS_INT(t)) {
1159 xassert(c->type == CONSTANT_INT);
1160 } else if(TYPE_IS_BOOLEAN(t)) {
1161 xassert(c->type == CONSTANT_TRUE
1162 || c->type == CONSTANT_FALSE);
1166 static void check_override(memberinfo_t*m, int flags)
1170 if(m->parent == state->cls->info)
1171 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1173 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1174 if(m->access==ACCESS_PRIVATE)
1176 if(m->flags & FLAG_FINAL)
1177 syntaxerror("can't override final member %s", m->name);
1179 /* allow this. it's no issue.
1180 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1181 syntaxerror("can't override static member %s", m->name);*/
1183 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1184 syntaxerror("can't override non-static member %s with static declaration", m->name);
1186 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1187 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1188 if(m->kind == INFOTYPE_METHOD)
1189 syntaxerror("can't override without explicit 'override' declaration");
1191 syntaxerror("can't override '%s'", m->name);
1196 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1198 methodinfo_t*minfo = 0;
1199 namespace_t ns = modifiers2access(mod);
1202 minfo = methodinfo_register_global(ns.access, state->package, name);
1203 minfo->return_type = return_type;
1204 } else if(getset != KW_GET && getset != KW_SET) {
1206 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1208 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1210 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1211 minfo->return_type = return_type;
1212 // getslot on a member slot only returns "undefined", so no need
1213 // to actually store these
1214 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1216 //class getter/setter
1217 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1219 if(getset == KW_GET) {
1221 } else if(params->list && params->list->param && !params->list->next) {
1222 type = params->list->param->type;
1224 syntaxerror("setter function needs to take exactly one argument");
1225 // not sure wether to look into superclasses here, too
1226 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1228 if(minfo->kind!=INFOTYPE_VAR)
1229 syntaxerror("class already contains a method called '%s'", name);
1230 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1231 syntaxerror("class already contains a field called '%s'", name);
1232 if(minfo->subtype & gs)
1233 syntaxerror("getter/setter for '%s' already defined", name);
1234 /* make a setter or getter into a getset */
1235 minfo->subtype |= gs;
1238 FIXME: this check needs to be done in pass 2
1240 if((!minfo->return_type != !type) ||
1241 (minfo->return_type && type &&
1242 !strcmp(minfo->return_type->name, type->name))) {
1243 syntaxerror("different type in getter and setter: %s and %s",
1244 minfo->return_type?minfo->return_type->name:"*",
1245 type?type->name:"*");
1248 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1249 minfo->kind = INFOTYPE_VAR; //hack
1250 minfo->subtype = gs;
1251 minfo->return_type = type;
1254 /* can't assign a slot as getter and setter might have different slots */
1255 //minfo->slot = slot;
1257 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1258 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1259 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1264 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1266 //parserassert(state->method && state->method->info);
1268 methodstate_t*parent_method = state->method;
1271 return_type = 0; // not valid in pass 1
1275 state->new_vars = 1;
1276 state->allvars = dict_new();
1279 state->method = rfx_calloc(sizeof(methodstate_t));
1280 state->method->inner = 1;
1281 state->method->variable_count = 0;
1282 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1284 NEW(methodinfo_t,minfo);
1285 minfo->kind = INFOTYPE_METHOD;
1286 minfo->access = ACCESS_PACKAGEINTERNAL;
1288 state->method->info = minfo;
1291 list_append(parent_method->innerfunctions, state->method);
1293 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1295 function_initvars(state->method, params, 0, 1);
1299 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1300 state->method->variable_count = 0;
1301 parserassert(state->method);
1303 state->method->info->return_type = return_type;
1304 function_initvars(state->method, params, 0, 1);
1308 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1309 params_t*params, classinfo_t*return_type)
1311 if(state->method && state->method->info) {
1312 syntaxerror("not able to start another method scope");
1315 state->new_vars = 1;
1316 state->allvars = dict_new();
1319 state->method = rfx_calloc(sizeof(methodstate_t));
1320 state->method->has_super = 0;
1323 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1325 state->method->is_global = 1;
1326 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1328 if(state->method->is_constructor)
1329 name = "__as3_constructor__";
1331 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1333 function_initvars(state->method, params, mod->flags, 1);
1335 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1339 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1340 state->method->variable_count = 0;
1341 parserassert(state->method);
1344 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1345 check_override(m, mod->flags);
1349 state->cls->has_constructor |= state->method->is_constructor;
1352 function_initvars(state->method, params, mod->flags, 1);
1356 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1357 params_t*params, classinfo_t*return_type, code_t*body)
1360 // store inner methods in variables
1361 function_initvars(state->method, 0, 0, 0);
1363 methodstate_list_t*ml = state->method->innerfunctions;
1365 dict_t*xvars = dict_new();
1368 methodstate_t*m = ml->methodstate;
1369 parserassert(m->inner);
1370 if(m->unresolved_variables) {
1371 dict_t*d = m->unresolved_variables;
1373 for(t=0;t<d->hashsize;t++) {
1374 dictentry_t*l = d->slots[t];
1376 /* check parent method's variables */
1378 if((v=find_variable(state, l->key))) {
1379 m->uses_parent_function = 1;
1380 state->method->uses_slots = 1;
1381 dict_put(xvars, l->key, 0);
1388 dict_destroy(m->unresolved_variables);
1389 m->unresolved_variables = 0;
1394 if(state->method->uses_slots) {
1395 state->method->slots = dict_new();
1397 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1398 if(!name) syntaxerror("internal error");
1399 if(v->index && dict_contains(xvars, name)) {
1402 if(v->is_inner_method) {
1403 v->is_inner_method->is_a_slot = 1;
1406 dict_put(state->method->slots, name, v);
1409 state->method->uses_slots = i;
1410 dict_destroy(state->vars);state->vars = 0;
1411 parserassert(state->new_vars);
1412 dict_destroy(state->allvars);state->allvars = 0;
1419 /*if(state->method->uses_parent_function){
1420 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1425 multiname_t*type2 = sig2mname(return_type);
1427 if(state->method->inner) {
1428 f = state->method->abc;
1429 abc_method_init(f, global->file, type2, 1);
1430 } else if(state->method->is_constructor) {
1431 f = abc_class_getconstructor(state->cls->abc, type2);
1432 } else if(!state->method->is_global) {
1433 namespace_t ns = modifiers2access(mod);
1435 /* deal with protected */
1436 if(ns.access == ACCESS_PROTECTED && state->cls)
1437 ns.name = state->cls->info->name;
1439 multiname_t mname = {QNAME, &ns, 0, name};
1441 if(mod->flags&FLAG_STATIC)
1442 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1444 f = abc_class_method(state->cls->abc, type2, &mname);
1445 slot = f->trait->slot_id;
1447 namespace_t mname_ns = {state->method->info->access, state->package};
1448 multiname_t mname = {QNAME, &mname_ns, 0, name};
1450 f = abc_method_new(global->file, type2, 1);
1451 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1452 //abc_code_t*c = global->init->method->body->code;
1454 //flash doesn't seem to allow us to access function slots
1455 //state->method->info->slot = slot;
1457 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1458 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1459 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1460 if(params->varargs) f->flags |= METHOD_NEED_REST;
1464 for(p=params->list;p;p=p->next) {
1465 if(params->varargs && !p->next) {
1466 break; //varargs: omit last parameter in function signature
1468 multiname_t*m = sig2mname(p->param->type);
1469 list_append(f->parameters, m);
1470 if(p->param->value) {
1471 check_constant_against_type(p->param->type, p->param->value);
1472 opt=1;list_append(f->optional_parameters, p->param->value);
1474 syntaxerror("non-optional parameter not allowed after optional parameters");
1477 if(state->method->slots) {
1478 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1480 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1481 multiname_t*type = sig2mname(v->type);
1482 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1483 t->slot_id = v->index;
1488 check_code_for_break(body);
1490 /* Seems this works now.
1491 if(state->method->exceptions && state->method->uses_slots) {
1492 as3_warning("try/catch and activation not supported yet within the same method");
1496 f->body->code = body;
1497 f->body->exceptions = state->method->exceptions;
1498 } else { //interface
1500 syntaxerror("interface methods can't have a method body");
1510 void breakjumpsto(code_t*c, char*name, code_t*jump)
1513 if(c->opcode == OPCODE___BREAK__) {
1514 string_t*name2 = c->data[0];
1515 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1516 c->opcode = OPCODE_JUMP;
1523 void continuejumpsto(code_t*c, char*name, code_t*jump)
1526 if(c->opcode == OPCODE___CONTINUE__) {
1527 string_t*name2 = c->data[0];
1528 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1529 c->opcode = OPCODE_JUMP;
1537 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1539 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1544 return abc_coerce_a(c);
1548 // cast an "any" type to a specific type. subject to
1549 // runtime exceptions
1550 return abc_coerce2(c, &m);
1553 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1554 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1555 // allow conversion between number types
1556 if(TYPE_IS_UINT(to))
1557 return abc_convert_u(c);
1558 else if(TYPE_IS_INT(to))
1559 return abc_convert_i(c);
1560 else if(TYPE_IS_NUMBER(to))
1561 return abc_convert_d(c);
1562 return abc_coerce2(c, &m);
1565 if(TYPE_IS_BOOLEAN(to))
1566 return abc_convert_b(c);
1567 if(TYPE_IS_STRING(to))
1568 return abc_convert_s(c);
1569 if(TYPE_IS_OBJECT(to))
1570 return abc_convert_o(c);
1572 classinfo_t*supertype = from;
1574 if(supertype == to) {
1575 // target type is one of from's superclasses
1576 return abc_coerce2(c, &m);
1579 while(supertype->interfaces[t]) {
1580 if(supertype->interfaces[t]==to) {
1581 // target type is one of from's interfaces
1582 return abc_coerce2(c, &m);
1586 supertype = supertype->superclass;
1588 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1590 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1592 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1595 as3_error("can't convert type %s%s%s to %s%s%s",
1596 from->package, from->package[0]?".":"", from->name,
1597 to->package, to->package[0]?".":"", to->name);
1601 /* move to ast.c todo end */
1603 char is_pushundefined(code_t*c)
1605 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1608 static const char* get_package_from_name(const char*name)
1610 /* try explicit imports */
1611 dictentry_t* e = dict_get_slot(state->imports, name);
1613 if(!strcmp(e->key, name)) {
1614 slotinfo_t*c = (slotinfo_t*)e->data;
1615 if(c) return c->package;
1621 static namespace_list_t*get_current_imports()
1623 namespace_list_t*searchlist = 0;
1625 list_append(searchlist, namespace_new_package(state->package));
1627 import_list_t*l = state->wildcard_imports;
1629 namespace_t*ns = namespace_new_package(l->import->package);
1630 list_append(searchlist, ns);
1633 list_append(searchlist, namespace_new_package(""));
1634 list_append(searchlist, namespace_new_package(internal_filename_package));
1638 static slotinfo_t* find_class(const char*name)
1642 c = registry_find(state->package, name);
1645 /* try explicit imports */
1646 dictentry_t* e = dict_get_slot(state->imports, name);
1649 if(!strcmp(e->key, name)) {
1650 c = (slotinfo_t*)e->data;
1656 /* try package.* imports */
1657 import_list_t*l = state->wildcard_imports;
1659 //printf("does package %s contain a class %s?\n", l->import->package, name);
1660 c = registry_find(l->import->package, name);
1665 /* try global package */
1666 c = registry_find("", name);
1669 /* try local "filename" package */
1670 c = registry_find(internal_filename_package, name);
1675 typedcode_t push_class(slotinfo_t*a)
1680 if(a->access == ACCESS_PACKAGEINTERNAL &&
1681 strcmp(a->package, state->package) &&
1682 strcmp(a->package, internal_filename_package)
1684 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1685 infotypename(a), a->name, a->package, state->package);
1688 if(a->kind != INFOTYPE_CLASS) {
1690 x.c = abc_findpropstrict2(x.c, &m);
1691 x.c = abc_getproperty2(x.c, &m);
1692 if(a->kind == INFOTYPE_METHOD) {
1693 methodinfo_t*f = (methodinfo_t*)a;
1694 x.t = TYPE_FUNCTION(f);
1696 varinfo_t*v = (varinfo_t*)a;
1700 classinfo_t*c = (classinfo_t*)a;
1702 x.c = abc_getglobalscope(x.c);
1703 x.c = abc_getslot(x.c, c->slot);
1706 x.c = abc_getlex2(x.c, &m);
1708 x.t = TYPE_CLASS(c);
1714 char is_break_or_jump(code_t*c)
1718 if(c->opcode == OPCODE_JUMP ||
1719 c->opcode == OPCODE___BREAK__ ||
1720 c->opcode == OPCODE___CONTINUE__ ||
1721 c->opcode == OPCODE_THROW ||
1722 c->opcode == OPCODE_RETURNVOID ||
1723 c->opcode == OPCODE_RETURNVALUE) {
1729 #define IS_FINALLY_TARGET(op) \
1730 ((op) == OPCODE___CONTINUE__ || \
1731 (op) == OPCODE___BREAK__ || \
1732 (op) == OPCODE_RETURNVOID || \
1733 (op) == OPCODE_RETURNVALUE || \
1734 (op) == OPCODE___RETHROW__)
1736 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1738 #define NEED_EXTRA_STACK_ARG
1739 code_t*finally_label = abc_nop(0);
1740 NEW(lookupswitch_t, l);
1746 code_t*prev = i->prev;
1747 if(IS_FINALLY_TARGET(i->opcode)) {
1750 if(i->opcode == OPCODE___RETHROW__ ||
1751 i->opcode == OPCODE_RETURNVALUE) {
1752 if(i->opcode == OPCODE___RETHROW__)
1753 i->opcode = OPCODE_THROW;
1755 p = abc_coerce_a(p);
1756 p = abc_setlocal(p, tempvar);
1758 p = abc_pushbyte(p, count++);
1759 p = abc_jump(p, finally_label);
1760 code_t*target = p = abc_label(p);
1761 #ifdef NEED_EXTRA_STACK_ARG
1765 p = abc_getlocal(p, tempvar);
1768 p->next = i;i->prev = p;
1769 list_append(l->targets, target);
1775 c = abc_pushbyte(c, -1);
1776 c = code_append(c, finally_label);
1777 c = code_append(c, finally);
1779 #ifdef NEED_EXTRA_STACK_ARG
1782 c = abc_lookupswitch(c, l);
1783 c = l->def = abc_label(c);
1784 #ifdef NEED_EXTRA_STACK_ARG
1791 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1795 code_t*prev = i->prev;
1796 if(IS_FINALLY_TARGET(i->opcode)) {
1797 if(i->opcode == OPCODE___RETHROW__)
1798 i->opcode = OPCODE_THROW;
1799 code_t*end = code_dup(finally);
1800 code_t*start = code_start(end);
1801 if(prev) prev->next = start;
1808 return code_append(c, finally);
1811 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1817 int num_insertion_points=0;
1819 if(IS_FINALLY_TARGET(i->opcode))
1820 num_insertion_points++;
1827 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1832 int simple_version_cost = (1+num_insertion_points)*code_size;
1833 int lookup_version_cost = 4*num_insertion_points + 5;
1835 if(cantdup || simple_version_cost > lookup_version_cost) {
1836 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1837 return insert_finally_lookup(c, finally, tempvar);
1839 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1840 return insert_finally_simple(c, finally, tempvar);
1844 #define PASS1 }} if(as3_pass == 1) {{
1845 #define PASS1END }} if(as3_pass == 2) {{
1846 #define PASS2 }} if(as3_pass == 2) {{
1847 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1848 #define PASS12END }} if(as3_pass == 2) {{
1849 #define PASS_ALWAYS }} {{
1855 /* ------------ code blocks / statements ---------------- */
1857 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1859 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1860 PROGRAM_CODE_LIST: PROGRAM_CODE
1861 | PROGRAM_CODE_LIST PROGRAM_CODE
1863 PROGRAM_CODE: PACKAGE_DECLARATION
1864 | INTERFACE_DECLARATION
1866 | FUNCTION_DECLARATION
1869 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1872 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1873 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1874 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1876 INPACKAGE_CODE: INTERFACE_DECLARATION
1878 | FUNCTION_DECLARATION
1881 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1884 MAYBECODE: CODE {$$=$1;}
1885 MAYBECODE: {$$=code_new();}
1887 CODE: CODE CODEPIECE {
1888 $$=code_append($1,$2);
1890 CODE: CODEPIECE {$$=$1;}
1892 // code which may appear outside of methods
1893 CODE_STATEMENT: IMPORT
1895 CODE_STATEMENT: FOR_IN
1896 CODE_STATEMENT: WHILE
1897 CODE_STATEMENT: DO_WHILE
1898 CODE_STATEMENT: SWITCH
1900 CODE_STATEMENT: WITH
1902 CODE_STATEMENT: VOIDEXPRESSION
1903 CODE_STATEMENT: USE_NAMESPACE
1904 CODE_STATEMENT: NAMESPACE_DECLARATION
1905 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1906 CODE_STATEMENT: '{' '}' {$$=0;}
1908 // code which may appear in methods
1909 CODEPIECE: ';' {$$=0;}
1910 CODEPIECE: CODE_STATEMENT
1911 CODEPIECE: VARIABLE_DECLARATION
1916 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
1926 //CODEBLOCK : '{' CODE '}' {$$=$2;}
1927 //CODEBLOCK : '{' '}' {$$=0;}
1928 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1929 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1931 /* ------------ package init code ------------------- */
1933 PACKAGE_INITCODE: CODE_STATEMENT {
1934 code_t**cc = &global->init->method->body->code;
1935 *cc = code_append(*cc, $1);
1938 /* ------------ conditional compilation ------------- */
1940 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
1943 char*key = concat3($1,"::",$3);
1944 if(!definitions || !dict_contains(definitions, key)) {
1950 /* ------------ variables --------------------------- */
1953 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1959 MAYBEEXPRESSION : '=' E {$$=$2;}
1960 | {$$=mkdummynode();}
1962 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1963 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1965 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1966 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1968 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1971 if(variable_exists($1))
1972 syntaxerror("Variable %s already defined", $1);
1974 new_variable($1, 0, 1, 0);
1979 if(state->method->uses_slots) {
1980 variable_t* v = find_slot(state, $1);
1982 // this variable is stored in a slot
1990 index = new_variable($1, $2, 1, 0);
1993 $$ = slot?abc_getscopeobject(0, 1):0;
1995 typedcode_t v = node_read($3);
1996 if(!is_subtype_of(v.t, $2)) {
1997 syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
2000 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2001 $$ = code_append($$, v.c);
2002 $$ = converttype($$, v.t, $2);
2005 $$ = defaultvalue($$, $2);
2008 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2009 $$ = code_append($$, v.c);
2010 $$ = abc_coerce_a($$);
2012 // don't do anything
2020 $$ = abc_setslot($$, index);
2022 $$ = abc_setlocal($$, index);
2026 /* ------------ control flow ------------------------- */
2028 MAYBEELSE: %prec below_else {$$ = code_new();}
2029 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2030 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2032 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2035 $$ = code_append($$, $4.c);
2036 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2038 $$ = code_append($$, $6);
2040 myjmp = $$ = abc_jump($$, 0);
2042 myif->branch = $$ = abc_nop($$);
2044 $$ = code_append($$, $7);
2045 myjmp->branch = $$ = abc_nop($$);
2051 FOR_INIT : {$$=code_new();}
2052 FOR_INIT : VARIABLE_DECLARATION
2053 FOR_INIT : VOIDEXPRESSION
2055 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2056 // (I don't see any easy way to revolve this conflict otherwise, as we
2057 // can't touch VAR_READ without upsetting the precedence about "return")
2058 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2059 PASS1 $$=$2;new_variable($2,0,1,0);
2060 PASS2 $$=$2;new_variable($2,$3,1,0);
2062 FOR_IN_INIT : T_IDENTIFIER {
2067 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2068 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2070 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2071 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2073 $$ = code_append($$, $2);
2074 code_t*loopstart = $$ = abc_label($$);
2075 $$ = code_append($$, $4.c);
2076 code_t*myif = $$ = abc_iffalse($$, 0);
2077 $$ = code_append($$, $8);
2078 code_t*cont = $$ = abc_nop($$);
2079 $$ = code_append($$, $6);
2080 $$ = abc_jump($$, loopstart);
2081 code_t*out = $$ = abc_nop($$);
2082 breakjumpsto($$, $1.name, out);
2083 continuejumpsto($$, $1.name, cont);
2090 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2091 variable_t*var = find_variable(state, $2);
2093 syntaxerror("variable %s not known in this scope", $2);
2096 char*tmp1name = concat2($2, "__tmp1__");
2097 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2098 char*tmp2name = concat2($2, "__array__");
2099 int array = new_variable(tmp1name, 0, 0, 0);
2102 $$ = code_append($$, $4.c);
2103 $$ = abc_coerce_a($$);
2104 $$ = abc_setlocal($$, array);
2105 $$ = abc_pushbyte($$, 0);
2106 $$ = abc_setlocal($$, it);
2108 code_t*loopstart = $$ = abc_label($$);
2110 $$ = abc_hasnext2($$, array, it);
2111 code_t*myif = $$ = abc_iffalse($$, 0);
2112 $$ = abc_getlocal($$, array);
2113 $$ = abc_getlocal($$, it);
2115 $$ = abc_nextname($$);
2117 $$ = abc_nextvalue($$);
2118 $$ = converttype($$, 0, var->type);
2119 $$ = abc_setlocal($$, var->index);
2121 $$ = code_append($$, $6);
2122 $$ = abc_jump($$, loopstart);
2124 code_t*out = $$ = abc_nop($$);
2125 breakjumpsto($$, $1.name, out);
2126 continuejumpsto($$, $1.name, loopstart);
2138 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2142 code_t*myjmp = $$ = abc_jump($$, 0);
2143 code_t*loopstart = $$ = abc_label($$);
2144 $$ = code_append($$, $6);
2145 code_t*cont = $$ = abc_nop($$);
2146 myjmp->branch = cont;
2147 $$ = code_append($$, $4.c);
2148 $$ = abc_iftrue($$, loopstart);
2149 code_t*out = $$ = abc_nop($$);
2150 breakjumpsto($$, $1, out);
2151 continuejumpsto($$, $1, cont);
2157 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2159 code_t*loopstart = $$ = abc_label($$);
2160 $$ = code_append($$, $3);
2161 code_t*cont = $$ = abc_nop($$);
2162 $$ = code_append($$, $6.c);
2163 $$ = abc_iftrue($$, loopstart);
2164 code_t*out = $$ = abc_nop($$);
2165 breakjumpsto($$, $1, out);
2166 continuejumpsto($$, $1, cont);
2172 BREAK : "break" %prec prec_none {
2173 $$ = abc___break__(0, "");
2175 BREAK : "break" T_IDENTIFIER {
2176 $$ = abc___break__(0, $2);
2178 CONTINUE : "continue" %prec prec_none {
2179 $$ = abc___continue__(0, "");
2181 CONTINUE : "continue" T_IDENTIFIER {
2182 $$ = abc___continue__(0, $2);
2185 MAYBE_CASE_LIST : {$$=0;}
2186 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2187 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2188 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2189 CASE_LIST: CASE {$$=$1;}
2190 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2192 CASE: "case" E ':' MAYBECODE {
2193 $$ = abc_getlocal(0, state->switch_var);
2194 $$ = code_append($$, node_read($2).c);
2195 code_t*j = $$ = abc_ifne($$, 0);
2196 $$ = code_append($$, $4);
2197 if($$->opcode != OPCODE___BREAK__) {
2198 $$ = abc___fallthrough__($$, "");
2200 code_t*e = $$ = abc_nop($$);
2203 DEFAULT: "default" ':' MAYBECODE {
2206 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2207 $$ = node_read($4).c;
2208 $$ = abc_setlocal($$, state->switch_var);
2209 $$ = code_append($$, $7);
2211 code_t*out = $$ = abc_kill($$, state->switch_var);
2212 breakjumpsto($$, $1, out);
2214 code_t*c = $$,*lastblock=0;
2216 if(c->opcode == OPCODE_IFNE) {
2217 if(!c->next) syntaxerror("internal error in fallthrough handling");
2219 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2221 c->opcode = OPCODE_JUMP;
2222 c->branch = lastblock;
2224 /* fall through end of switch */
2225 c->opcode = OPCODE_NOP;
2235 /* ------------ try / catch /finally ---------------- */
2237 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2238 state->exception_name=$3;
2239 PASS1 new_variable($3, 0, 0, 0);
2240 PASS2 new_variable($3, $4, 0, 0);
2243 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2244 multiname_t name = {QNAME, &name_ns, 0, $3};
2246 NEW(abc_exception_t, e)
2247 e->exc_type = sig2mname($4);
2248 e->var_name = multiname_clone(&name);
2252 int i = find_variable_safe(state, $3)->index;
2253 e->target = c = abc_nop(0);
2254 c = abc_setlocal(c, i);
2255 c = code_append(c, code_dup(state->method->scope_code));
2256 c = code_append(c, $8);
2262 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2267 NEW(abc_exception_t, e)
2268 e->exc_type = 0; //all exceptions
2269 e->var_name = 0; //no name
2272 e->to = code_append(e->to, $4);
2278 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2279 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2280 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2281 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2285 list_append($$.l,$2);
2286 $$.finally = $2->to;$2->to=0;
2289 CATCH_FINALLY_LIST: FINALLY {
2293 list_append($$.l,$1);
2294 $$.finally = $1->to;$1->to=0;
2298 TRY : "try" '{' {PASS12 new_state();
2299 state->method->has_exceptions=1;
2300 state->method->late_binding=1;//for invariant scope_code
2301 } MAYBECODE '}' CATCH_FINALLY_LIST {
2302 code_t*out = abc_nop(0);
2304 code_t*start = abc_nop(0);
2305 $$ = code_append(start, $4);
2306 if(!is_break_or_jump($4)) {
2307 $$ = abc_jump($$, out);
2309 code_t*end = $$ = abc_nop($$);
2313 tmp = new_variable("__finally__", 0, 0, 0);
2315 abc_exception_list_t*l = $6.l;
2318 abc_exception_t*e = l->abc_exception;
2320 $$ = code_append($$, e->target);
2321 $$ = abc_jump($$, out);
2323 parserassert((ptroff_t)$6.finally);
2325 e->target = $$ = abc_nop($$);
2326 $$ = code_append($$, code_dup(state->method->scope_code));
2327 $$ = abc___rethrow__($$);
2335 $$ = code_append($$, out);
2337 $$ = insert_finally($$, $6.finally, tmp);
2339 list_concat(state->method->exceptions, $6.l);
2345 /* ------------ throw ------------------------------- */
2347 THROW : "throw" EXPRESSION {
2351 THROW : "throw" %prec prec_none {
2352 if(!state->exception_name)
2353 syntaxerror("re-throw only possible within a catch block");
2354 variable_t*v = find_variable(state, state->exception_name);
2356 $$=abc_getlocal($$, v->index);
2360 /* ------------ with -------------------------------- */
2362 WITH_HEAD : "with" '(' EXPRESSION ')' {
2364 if(state->method->has_exceptions) {
2365 int v = alloc_local();
2366 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2367 state->method->scope_code = abc_pushwith(state->method->scope_code);
2372 WITH : WITH_HEAD CODEBLOCK {
2373 /* remove getlocal;pushwith from scope code again */
2374 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2377 if(state->method->has_exceptions) {
2379 $$ = abc_setlocal($$, $1.number);
2381 $$ = abc_pushwith($$);
2382 $$ = code_append($$, $2);
2383 $$ = abc_popscope($$);
2387 /* ------------ packages and imports ---------------- */
2389 X_IDENTIFIER: T_IDENTIFIER
2390 | "package" {PASS12 $$="package";}
2391 | T_NAMESPACE {PASS12 $$=$1;}
2393 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2394 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2396 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2397 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2398 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2399 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2402 static void state_has_imports()
2404 state->wildcard_imports = list_clone(state->wildcard_imports);
2405 state->imports = dict_clone(state->imports);
2406 state->has_own_imports = 1;
2408 static void import_toplevel(const char*package)
2410 char* s = strdup(package);
2412 dict_put(state->import_toplevel_packages, s, 0);
2413 char*x = strrchr(s, '.');
2421 IMPORT : "import" PACKAGEANDCLASS {
2423 slotinfo_t*s = registry_find($2->package, $2->name);
2424 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2425 as3_schedule_class($2->package, $2->name);
2429 syntaxerror("Couldn't import class\n");
2430 state_has_imports();
2431 dict_put(state->imports, c->name, c);
2432 import_toplevel(c->package);
2435 IMPORT : "import" PACKAGE '.' '*' {
2437 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2438 as3_schedule_package($2);
2443 state_has_imports();
2444 list_append(state->wildcard_imports, i);
2445 import_toplevel(i->package);
2449 /* ------------ classes and interfaces (header) -------------- */
2451 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2452 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2453 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2454 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2456 $$.flags=$1.flags|$2.flags;
2457 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2458 $$.ns=$1.ns?$1.ns:$2.ns;
2461 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2462 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2463 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2464 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2465 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2466 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2467 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2468 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2469 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2470 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2474 EXTENDS : {PASS12 $$=0;}
2475 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2477 EXTENDS_LIST : {PASS12 $$=list_new();}
2478 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2480 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2481 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2483 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2484 EXTENDS IMPLEMENTS_LIST
2485 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2487 '}' {PASS12 endclass();$$=0;}
2489 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2491 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2492 startclass(&$1,$3,0,$4);}
2493 MAYBE_INTERFACE_BODY
2494 '}' {PASS12 endclass();$$=0;}
2496 /* ------------ classes and interfaces (body) -------------- */
2499 MAYBE_CLASS_BODY : CLASS_BODY
2500 CLASS_BODY : CLASS_BODY_ITEM
2501 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2502 CLASS_BODY_ITEM : ';'
2503 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2504 CLASS_BODY_ITEM : SLOT_DECLARATION
2505 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2507 CLASS_BODY_ITEM : CODE_STATEMENT {
2508 code_t*c = state->cls->static_init->header;
2509 c = code_append(c, $1);
2510 state->cls->static_init->header = c;
2513 MAYBE_INTERFACE_BODY :
2514 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2515 INTERFACE_BODY : IDECLARATION
2516 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2518 IDECLARATION : "var" T_IDENTIFIER {
2519 syntaxerror("variable declarations not allowed in interfaces");
2521 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2523 $1.flags |= FLAG_PUBLIC;
2524 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2525 syntaxerror("invalid method modifiers: interface methods always need to be public");
2527 startfunction(&$1,$3,$4,&$6,$8);
2528 endfunction(&$1,$3,$4,&$6,$8, 0);
2529 list_deep_free($6.list);
2532 /* ------------ classes and interfaces (body, slots ) ------- */
2535 static int slotstate_varconst = 0;
2536 static modifiers_t*slotstate_flags = 0;
2537 static void setslotstate(modifiers_t* flags, int varconst)
2539 slotstate_varconst = varconst;
2540 slotstate_flags = flags;
2542 if(flags && flags->flags&FLAG_STATIC) {
2543 state->method = state->cls->static_init;
2545 state->method = state->cls->init;
2548 parserassert(state->method);
2551 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2553 int flags = modifiers->flags;
2554 namespace_t ns = modifiers2access(modifiers);
2555 /* deal with protected */
2556 if(ns.access == ACCESS_PROTECTED && state->cls)
2557 ns.name = state->cls->info->name;
2560 multiname_t mname = {QNAME, &ns, 0, name};
2562 trait_list_t**traits;
2566 ns.name = state->package;
2567 traits = &global->init->traits;
2568 code = &global->init->method->body->code;
2569 } else if(flags&FLAG_STATIC) {
2571 traits = &state->cls->abc->static_traits;
2572 code = &state->cls->static_init->header;
2574 // instance variable
2575 traits = &state->cls->abc->traits;
2576 code = &state->cls->init->header;
2581 memcpy(m, &mname, sizeof(multiname_t));
2583 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2587 VARCONST: "var" | "const"
2589 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2591 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2592 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2594 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2597 int flags = slotstate_flags->flags;
2598 namespace_t ns = modifiers2access(slotstate_flags);
2602 varinfo_t* info = 0;
2604 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2606 check_override(i, flags);
2608 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2610 slotinfo_t*i = registry_find(state->package, $1);
2612 syntaxerror("package %s already contains '%s'", state->package, $1);
2614 if(ns.name && ns.name[0]) {
2615 syntaxerror("namespaces not allowed on package-level variables");
2617 info = varinfo_register_global(ns.access, state->package, $1);
2621 info->flags = flags;
2623 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2627 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2631 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2635 t->type_name = multiname_clone(&m);
2637 info->slot = t->slot_id;
2639 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2640 FIXME: is there a way to use slots and still don't have conflicting overrides?
2642 info->slot = t->slot_id = 0;
2644 constant_t cval = $3->type->eval($3);
2645 if(cval.type!=CONSTANT_UNKNOWN) {
2646 /* compile time constant */
2647 t->value = malloc(sizeof(constant_t));
2648 memcpy(t->value, &cval, sizeof(constant_t));
2649 info->value = constant_clone(t->value);
2651 typedcode_t v = node_read($3);
2652 /* initalization code (if needed) */
2654 if(v.c && !is_pushundefined(v.c)) {
2655 c = abc_getlocal_0(c);
2656 c = code_append(c, v.c);
2657 c = converttype(c, v.t, $2);
2659 c = abc_setproperty2(c, &mname);
2661 c = abc_setslot(c, t->slot_id);
2664 *code = code_append(*code, c);
2667 if(slotstate_varconst==KW_CONST) {
2668 t->kind= TRAIT_CONST;
2669 info->flags |= FLAG_CONST;
2676 /* ------------ constants -------------------------------------- */
2678 MAYBECONSTANT: {$$=0;}
2679 MAYBECONSTANT: '=' E {
2680 $$ = malloc(sizeof(constant_t));
2681 *$$ = node_eval($2);
2682 if($$->type == CONSTANT_UNKNOWN) {
2683 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2687 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2688 CONSTANT : T_INT {$$ = constant_new_int($1);}
2690 $$ = constant_new_uint($1);
2692 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2693 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2694 CONSTANT : "true" {$$ = constant_new_true($1);}
2695 CONSTANT : "false" {$$ = constant_new_false($1);}
2696 CONSTANT : "null" {$$ = constant_new_null($1);}
2697 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2698 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2701 CONSTANT : T_IDENTIFIER {
2702 if(!strcmp($1, "NaN")) {
2703 $$ = constant_new_float(__builtin_nan(""));
2705 as3_warning("Couldn't evaluate constant value of %s", $1);
2706 $$ = constant_new_null($1);
2710 /* ---------------------------xml ------------------------------ */
2713 static int xml_level = 0;
2718 OPEN : '<' {PASS_ALWAYS tokenizer_begin_xml();xml_level++;}
2719 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2720 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2723 XMLTEXT : XMLTEXT T_STRING {$$=concat2($1, string_cstr(&$2));}
2724 XMLTEXT : XMLTEXT '>' {$$=concat2($1, ">");}
2726 XML2 : XMLNODE XMLTEXT {$$=concat2($1,$2);}
2727 XML2 : XML2 XMLNODE XMLTEXT {$$=concat3($1,$2,$3);free($1);free($2);free($3);}
2729 XMLNODE : OPEN T_IDENTIFIER MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' T_IDENTIFIER CLOSE2 '>' {
2730 $$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2731 free($2);free($3);free($5);free($8);
2733 XMLNODE : OPEN T_IDENTIFIER MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2734 $$ = allocprintf("<%s%s/>", $2, $3);
2736 XMLNODE : OPEN T_IDENTIFIER MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' T_IDENTIFIER CLOSE2 '>' {
2737 $$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2738 free($2);free($3);free($5);free($6);free($6);free($9);
2741 MAYBE_XMLATTRIBUTES: {$$=strdup("");}
2742 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {$$=concat2(" ",$1);}
2743 XMLATTRIBUTES: XMLATTRIBUTE {$$=$1;}
2744 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {$$=concat3($1," ",$2);free($1);free($2);}
2745 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2746 char* str = string_cstr(&$3);
2747 $$=allocprintf("%s=\"%s\"", $1,str);
2749 free($1);free((char*)$3.str);
2752 /* ------------ classes and interfaces (body, functions) ------- */
2754 // non-vararg version
2757 memset(&$$,0,sizeof($$));
2759 MAYBE_PARAM_LIST: PARAM_LIST {
2765 MAYBE_PARAM_LIST: "..." PARAM {
2767 memset(&$$,0,sizeof($$));
2769 list_append($$.list, $2);
2771 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2775 list_append($$.list, $4);
2779 PARAM_LIST: PARAM_LIST ',' PARAM {
2782 list_append($$.list, $3);
2786 memset(&$$,0,sizeof($$));
2787 list_append($$.list, $1);
2790 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2792 $$ = rfx_calloc(sizeof(param_t));
2798 PARAM: T_IDENTIFIER MAYBECONSTANT {
2800 $$ = rfx_calloc(sizeof(param_t));
2802 $$->type = TYPE_ANY;
2810 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2811 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2814 endfunction(&$1,$3,$4,&$6,0,0);
2816 if(!state->method->info) syntaxerror("internal error");
2818 code_t*c = method_header(state->method);
2819 c = wrap_function(c, 0, $11);
2821 endfunction(&$1,$3,$4,&$6,$8,c);
2823 list_deep_free($6.list);
2827 MAYBE_IDENTIFIER: T_IDENTIFIER
2828 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2829 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2830 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2833 endfunction(0,0,$2,&$4,0,0);
2835 methodinfo_t*f = state->method->info;
2836 if(!f || !f->kind) syntaxerror("internal error");
2838 code_t*c = method_header(state->method);
2839 c = wrap_function(c, 0, $9);
2841 int index = state->method->var_index;
2842 endfunction(0,0,$2,&$4,$6,c);
2844 $$.c = abc_getlocal(0, index);
2845 $$.t = TYPE_FUNCTION(f);
2847 PASS12 list_deep_free($4.list);
2851 /* ------------- package + class ids --------------- */
2853 CLASS: X_IDENTIFIER {
2854 PASS1 NEW(unresolvedinfo_t,c);
2855 memset(c, 0, sizeof(*c));
2856 c->kind = INFOTYPE_UNRESOLVED;
2858 c->package = get_package_from_name($1);
2860 c->nsset = get_current_imports();
2861 /* make the compiler look for this class in the current directory,
2863 as3_schedule_class_noerror(state->package, $1);
2865 $$ = (classinfo_t*)c;
2867 slotinfo_t*s = find_class($1);
2868 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2869 $$ = (classinfo_t*)s;
2872 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2873 PASS1 NEW(unresolvedinfo_t,c);
2874 memset(c, 0, sizeof(*c));
2875 c->kind = INFOTYPE_UNRESOLVED;
2878 $$ = (classinfo_t*)c;
2880 slotinfo_t*s = registry_find($1, $3);
2881 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2883 $$ = (classinfo_t*)s;
2886 CLASS_SPEC: PACKAGEANDCLASS
2889 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2890 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2892 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2893 | '*' {PASS12 $$=TYPE_ANY;}
2894 | "void" {PASS12 $$=TYPE_VOID;}
2896 | "String" {$$=registry_getstringclass();}
2897 | "int" {$$=registry_getintclass();}
2898 | "uint" {$$=registry_getuintclass();}
2899 | "Boolean" {$$=registry_getbooleanclass();}
2900 | "Number" {$$=registry_getnumberclass();}
2903 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2904 MAYBETYPE: {PASS12 $$=0;}
2906 /* ----------function calls, delete, constructor calls ------ */
2908 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
2909 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2911 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
2912 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2913 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2915 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
2919 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
2920 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
2921 $$.number= $1.number+1;
2922 $$.cc = code_append($1.cc, $2.c);
2926 NEW : "new" E XX MAYBE_PARAM_VALUES {
2927 typedcode_t v = node_read($2);
2929 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2931 code_t*paramcode = $4.cc;
2932 if($$.c->opcode == OPCODE_GETPROPERTY) {
2933 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2934 $$.c = code_cutlast($$.c);
2935 $$.c = code_append($$.c, paramcode);
2936 $$.c = abc_constructprop2($$.c, name, $4.number);
2937 multiname_destroy(name);
2938 } else if($$.c->opcode == OPCODE_GETSLOT) {
2939 int slot = (int)(ptroff_t)$$.c->data[0];
2940 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
2941 multiname_t*name = t->name;
2942 $$.c = code_cutlast($$.c);
2943 $$.c = code_append($$.c, paramcode);
2944 $$.c = abc_constructprop2($$.c, name, $4.number);
2946 $$.c = code_append($$.c, paramcode);
2947 $$.c = abc_construct($$.c, $4.number);
2951 if(TYPE_IS_CLASS(v.t) && v.t->data) {
2954 $$.c = abc_coerce_a($$.c);
2959 /* TODO: use abc_call (for calling local variables),
2960 abc_callstatic (for calling own methods)
2963 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2965 typedcode_t v = node_read($1);
2967 if($$.c->opcode == OPCODE_COERCE_A) {
2968 $$.c = code_cutlast($$.c);
2970 code_t*paramcode = $3.cc;
2973 if($$.c->opcode == OPCODE_GETPROPERTY) {
2974 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2975 $$.c = code_cutlast($$.c);
2976 $$.c = code_append($$.c, paramcode);
2977 $$.c = abc_callproperty2($$.c, name, $3.number);
2978 multiname_destroy(name);
2979 } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
2980 int slot = (int)(ptroff_t)$$.c->data[0];
2981 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
2982 if(t->kind!=TRAIT_METHOD) {
2983 //ok: flash allows to assign closures to members.
2985 multiname_t*name = t->name;
2986 $$.c = code_cutlast($$.c);
2987 $$.c = code_append($$.c, paramcode);
2988 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2989 $$.c = abc_callproperty2($$.c, name, $3.number);
2990 } else if($$.c->opcode == OPCODE_GETSUPER) {
2991 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2992 $$.c = code_cutlast($$.c);
2993 $$.c = code_append($$.c, paramcode);
2994 $$.c = abc_callsuper2($$.c, name, $3.number);
2995 multiname_destroy(name);
2997 $$.c = abc_getglobalscope($$.c);
2998 $$.c = code_append($$.c, paramcode);
2999 $$.c = abc_call($$.c, $3.number);
3002 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3003 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3004 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3005 // calling a class is like a typecast
3006 $$.t = (classinfo_t*)v.t->data;
3008 $$.c = abc_coerce_a($$.c);
3013 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3014 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3015 if(!state->method) syntaxerror("super() not allowed outside of a function");
3016 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3019 $$.c = abc_getlocal_0($$.c);
3021 $$.c = code_append($$.c, $3.cc);
3023 this is dependent on the control path, check this somewhere else
3024 if(state->method->has_super)
3025 syntaxerror("constructor may call super() only once");
3027 state->method->has_super = 1;
3029 $$.c = abc_constructsuper($$.c, $3.number);
3030 $$.c = abc_pushundefined($$.c);
3034 DELETE: "delete" E {
3035 typedcode_t v = node_read($2);
3037 if($$.c->opcode == OPCODE_COERCE_A) {
3038 $$.c = code_cutlast($$.c);
3040 multiname_t*name = 0;
3041 if($$.c->opcode == OPCODE_GETPROPERTY) {
3042 $$.c->opcode = OPCODE_DELETEPROPERTY;
3043 } else if($$.c->opcode == OPCODE_GETSLOT) {
3044 int slot = (int)(ptroff_t)$$.c->data[0];
3045 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3046 $$.c = code_cutlast($$.c);
3047 $$.c = abc_deleteproperty2($$.c, name);
3049 $$.c = abc_getlocal_0($$.c);
3050 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3051 $$.c = abc_deleteproperty2($$.c, &m);
3053 $$.t = TYPE_BOOLEAN;
3056 RETURN: "return" %prec prec_none {
3057 $$ = abc_returnvoid(0);
3059 RETURN: "return" EXPRESSION {
3061 $$ = abc_returnvalue($$);
3064 // ----------------------- expression types -------------------------------------
3066 NONCOMMAEXPRESSION : E %prec below_lt {
3069 EXPRESSION : COMMA_EXPRESSION {
3072 COMMA_EXPRESSION : E %prec below_lt {
3073 $$ = mkmultinode(&node_comma, $1);
3075 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3076 $$ = multinode_extend($1, $3);
3078 VOIDEXPRESSION : E %prec below_minus {
3081 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3083 $$ = code_append($$, node_exec($3));
3086 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3087 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3089 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3090 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3092 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3094 $$.cc = code_append($$.cc, $1);
3095 $$.cc = code_append($$.cc, $3.c);
3098 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3100 $$.number = $1.number+2;
3101 $$.cc = code_append($$.cc, $3);
3102 $$.cc = code_append($$.cc, $5.c);
3105 // ----------------------- expression evaluation -------------------------------------
3107 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3108 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3109 E : NEW {$$ = mkcodenode($1);}
3110 E : DELETE {$$ = mkcodenode($1);}
3111 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3112 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3115 $$ = mkconstnode($1);
3121 namespace_t ns = {ACCESS_PACKAGE, ""};
3122 multiname_t m = {QNAME, &ns, 0, "XML"};
3123 v.c = abc_getlex2(v.c, &m);
3124 v.c = abc_pushstring(v.c, $1);
3125 v.c = abc_construct(v.c, 1);
3134 namespace_t ns = {ACCESS_PACKAGE, ""};
3135 multiname_t m = {QNAME, &ns, 0, "RegExp"};
3137 v.c = abc_getlex2(v.c, &m);
3138 v.c = abc_pushstring(v.c, $1.pattern);
3139 v.c = abc_construct(v.c, 1);
3141 v.c = abc_getlex2(v.c, &m);
3142 v.c = abc_pushstring(v.c, $1.pattern);
3143 v.c = abc_pushstring(v.c, $1.options);
3144 v.c = abc_construct(v.c, 2);
3151 E : '[' MAYBE_EXPRESSION_LIST ']' {
3154 v.c = code_append(v.c, $2.cc);
3155 v.c = abc_newarray(v.c, $2.number);
3156 v.t = registry_getarrayclass();
3161 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3164 v.c = code_append(v.c, $2.cc);
3165 v.c = abc_newobject(v.c, $2.number/2);
3166 v.t = registry_getobjectclass();
3170 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3171 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3172 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3173 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3174 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3175 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3176 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3177 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3178 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3179 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3180 E : '!' E {$$ = mknode1(&node_not, $2);}
3181 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3182 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3183 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3184 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3185 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3186 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3187 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3188 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3189 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3190 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3191 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3192 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3193 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3194 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3195 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3196 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3197 E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
3198 E : "void" E {$$ = mknode1(&node_void, $2);}
3199 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3200 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3201 E : '-' E {$$ = mknode1(&node_neg, $2);}
3202 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3203 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3204 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3205 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3206 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3207 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3208 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3209 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3210 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3211 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3212 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3213 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3214 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3215 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3217 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3218 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3219 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3220 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3222 E : "super" '.' T_IDENTIFIER
3223 { if(!state->cls->info)
3224 syntaxerror("super keyword not allowed outside a class");
3225 classinfo_t*t = state->cls->info->superclass;
3226 if(!t) t = TYPE_OBJECT;
3227 memberinfo_t*f = findmember_nsset(t, $3, 1);
3228 MEMBER_MULTINAME(m, f, $3);
3231 v.c = abc_getlocal_0(v.c);
3232 v.c = abc_getsuper2(v.c, &m);
3233 v.t = slotinfo_gettype((slotinfo_t*)f);
3237 E : '@' T_IDENTIFIER {
3238 // attribute occuring in .() loops
3241 as3_warning("ignored @ operator");
3244 E : E '.' '(' E ')' {
3246 // TODO: this needs to be implemented using a loop
3248 as3_warning("ignored .() operator");
3251 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3252 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3253 SUBNODE: T_IDENTIFIER
3256 E : E '.' ID_OR_NS "::" SUBNODE {
3257 typedcode_t v = node_read($1);
3258 typedcode_t w = node_read(resolve_identifier($3));
3259 v.c = code_append(v.c, w.c);
3260 if(!TYPE_IS_NAMESPACE(w.t)) {
3261 as3_softwarning("%s might not be a namespace", $3);
3263 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3264 multiname_t m = {RTQNAME, 0, 0, $5};
3265 v.c = abc_getproperty2(v.c, &m);
3266 if(TYPE_IS_XML(v.t)) {
3269 v.c = abc_coerce_a(v.c);
3274 E : E ".." SUBNODE {
3275 typedcode_t v = node_read($1);
3276 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3277 v.c = abc_getdescendants2(v.c, &m);
3281 E : E '.' '[' E ']' {
3282 typedcode_t v = node_read($1);
3283 typedcode_t w = node_read($4);
3284 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3285 v.c = code_append(v.c, w.c);
3286 v.c = converttype(w.c, w.t, TYPE_STRING);
3287 v.c = abc_getproperty2(v.c, &m);
3292 E : E '.' '@' SUBNODE {
3293 typedcode_t v = node_read($1);
3294 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3295 v.c = abc_getproperty2(v.c, &m);
3299 E : E ".." '@' SUBNODE {
3300 typedcode_t v = node_read($1);
3301 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3302 v.c = abc_getdescendants2(v.c, &m);
3306 E : E '.' '@' '[' E ']' {
3307 typedcode_t v = node_read($1);
3308 typedcode_t w = node_read($5);
3309 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3310 v.c = code_append(v.c, w.c);
3311 v.c = converttype(w.c, w.t, TYPE_STRING);
3312 v.c = abc_getproperty2(v.c, &m);
3316 E : E ".." '@' '[' E ']' {
3317 typedcode_t v = node_read($1);
3318 typedcode_t w = node_read($5);
3319 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3320 v.c = code_append(v.c, w.c);
3321 v.c = converttype(w.c, w.t, TYPE_STRING);
3322 v.c = abc_getdescendants2(v.c, &m);
3327 MEMBER : E '.' SUBNODE {
3328 typedcode_t v1 = node_read($1);
3330 classinfo_t*t = v1.t;
3332 if(TYPE_IS_CLASS(t) && t->data) {
3336 if(TYPE_IS_XML(t)) {
3337 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3338 $$.c = abc_getproperty2($$.c, &m);
3339 $$.c = abc_coerce_a($$.c);
3340 $$.t = TYPE_XMLLIST;
3342 if(t->subtype==INFOTYPE_UNRESOLVED) {
3343 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3345 memberinfo_t*f = findmember_nsset(t, $3, 1);
3347 if(f && !is_static != !(f->flags&FLAG_STATIC))
3349 if(f && f->slot && !noslot) {
3350 $$.c = abc_getslot($$.c, f->slot);
3353 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3355 MEMBER_MULTINAME(m, f, $3);
3356 $$.c = abc_getproperty2($$.c, &m);
3358 /* determine type */
3359 $$.t = slotinfo_gettype((slotinfo_t*)f);
3361 $$.c = abc_coerce_a($$.c);
3363 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3364 string_t*package = v1.c->data[0];
3365 char*package2 = concat3(package->str, ".", $3);
3367 slotinfo_t*a = registry_find(package->str, $3);
3370 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3371 registry_ispackage(package2)) {
3373 $$.c->data[0] = string_new4(package2);
3376 syntaxerror("couldn't resolve %s", package2);
3379 /* when resolving a property on an unknown type, we do know the
3380 name of the property (and don't seem to need the package), but
3381 we need to make avm2 try out all access modes */
3382 as3_warning("Resolving %s on unknown type", $3);
3383 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3384 $$.c = abc_getproperty2($$.c, &m);
3385 $$.c = abc_coerce_a($$.c);
3391 node_t* resolve_identifier(char*name)
3401 /* look at variables */
3402 if((v = find_variable(state, name))) {
3403 // name is a local variable
3404 o.c = abc_getlocal(o.c, v->index);
3406 return mkcodenode(o);
3408 if((v = find_slot(state, name))) {
3409 o.c = abc_getscopeobject(o.c, 1);
3410 o.c = abc_getslot(o.c, v->index);
3412 return mkcodenode(o);
3415 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3417 /* look at current class' members */
3418 if(!state->method->inner &&
3420 (f = findmember_nsset(state->cls->info, name, 1)))
3422 // name is a member or attribute in this class
3423 int var_is_static = (f->flags&FLAG_STATIC);
3425 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3426 /* if the variable is a constant (and we know what is evaluates to), we
3427 can just use the value itself */
3428 varinfo_t*v = (varinfo_t*)f;
3430 return mkconstnode(v->value);
3434 if(var_is_static >= i_am_static) {
3435 if(f->kind == INFOTYPE_METHOD) {
3436 o.t = TYPE_FUNCTION(f);
3441 if(var_is_static && !i_am_static) {
3442 /* access to a static member from a non-static location.
3443 do this via findpropstrict:
3444 there doesn't seem to be any non-lookup way to access
3445 static properties of a class */
3446 state->method->late_binding = 1;
3448 namespace_t ns = {f->access, f->package};
3449 multiname_t m = {QNAME, &ns, 0, name};
3450 o.c = abc_findpropstrict2(o.c, &m);
3451 o.c = abc_getproperty2(o.c, &m);
3452 return mkcodenode(o);
3453 } else if(f->slot>0) {
3454 o.c = abc_getlocal_0(o.c);
3455 o.c = abc_getslot(o.c, f->slot);
3456 return mkcodenode(o);
3458 namespace_t ns = {f->access, f->package};
3459 multiname_t m = {QNAME, &ns, 0, name};
3460 o.c = abc_getlocal_0(o.c);
3461 o.c = abc_getproperty2(o.c, &m);
3462 return mkcodenode(o);
3467 /* look at actual classes, in the current package and imported */
3468 if((a = find_class(name))) {
3470 return mkcodenode(o);
3473 /* look through package prefixes */
3474 if(dict_contains(state->import_toplevel_packages, name) ||
3475 registry_ispackage(name)) {
3476 o.c = abc___pushpackage__(o.c, name);
3478 return mkcodenode(o); //?
3481 /* unknown object, let the avm2 resolve it */
3483 //as3_softwarning("Couldn't resolve '%s', doing late binding", name);
3484 as3_warning("Couldn't resolve '%s', doing late binding", name);
3485 state->method->late_binding = 1;
3487 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3490 o.c = abc_findpropstrict2(o.c, &m);
3491 o.c = abc_getproperty2(o.c, &m);
3492 return mkcodenode(o);
3497 VAR_READ : T_IDENTIFIER {
3499 /* Queue unresolved identifiers for checking against the parent
3500 function's variables.
3501 We consider everything which is not a local variable "unresolved".
3502 This encompasses class names, members of the surrounding class
3503 etc. which is *correct* because local variables of the parent function
3506 if(!find_variable(state, $1)) {
3507 if(state->method->inner) {
3508 unknown_variable($1);
3510 /* let the compiler know that it might want to check the current directory/package
3511 for this identifier- maybe there's a file $1.as defining $1. */
3512 as3_schedule_class_noerror(state->package, $1);
3518 $$ = resolve_identifier($1);
3521 // ----------------- namespaces -------------------------------------------------
3524 void add_active_url(const char*url)
3528 list_append(state->active_namespace_urls, n);
3532 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3534 NEW(namespace_decl_t,n);
3539 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3541 NEW(namespace_decl_t,n);
3546 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3548 NEW(namespace_decl_t,n);
3553 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3555 trie_put(active_namespaces, $2->name, (void*)$2->url);
3557 namespace_t access = modifiers2access(&$1);
3558 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3559 var->type = TYPE_NAMESPACE;
3561 ns.access = ACCESS_NAMESPACE;
3563 var->value = constant_new_namespace(&ns);
3566 MULTINAME(m, TYPE_NAMESPACE);
3567 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3568 t->value = var->value;
3569 t->type_name = multiname_clone(&m);
3575 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3577 const char*url = $3->name;
3579 varinfo_t*s = (varinfo_t*)$3;
3580 if(s->kind == INFOTYPE_UNRESOLVED) {
3581 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3583 syntaxerror("Couldn't resolve namespace %s", $3->name);
3586 if(!s || s->kind != INFOTYPE_VAR)
3587 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3588 if(!s->value || !NS_TYPE(s->value->type))
3589 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3590 url = s->value->ns->name;
3592 trie_put(active_namespaces, $3->name, (void*)url);
3593 add_active_url(url);