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"
47 enum yytokentype token;
49 classinfo_t*classinfo;
50 classinfo_list_t*classinfo_list;
52 slotinfo_list_t*slotinfo_list;
55 unsigned int number_uint;
59 //typedcode_list_t*value_list;
60 codeandnumber_t value_list;
66 for_start_t for_start;
67 abc_exception_t *exception;
70 namespace_decl_t* namespace_decl;
73 abc_exception_list_t *l;
79 %token<id> T_IDENTIFIER T_NAMESPACE
81 %token<regexp> T_REGEXP
83 %token<number_int> T_INT
84 %token<number_uint> T_UINT
85 %token<number_float> T_FLOAT
87 %token<id> T_FOR "for"
88 %token<id> T_WHILE "while"
90 %token<id> T_SWITCH "switch"
92 %token<token> KW_IMPLEMENTS "implements"
93 %token<token> KW_NAMESPACE "namespace"
94 %token<token> KW_PACKAGE "package"
95 %token<token> KW_PROTECTED "protected"
96 %token<token> KW_PUBLIC "public"
97 %token<token> KW_PRIVATE "private"
98 %token<token> KW_USE "use"
99 %token<token> KW_INTERNAL "internal"
100 %token<token> KW_NEW "new"
101 %token<token> KW_NATIVE "native"
102 %token<token> KW_FUNCTION "function"
103 %token<token> KW_FINALLY "finally"
104 %token<token> KW_UNDEFINED "undefined"
105 %token<token> KW_NAN "NaN"
106 %token<token> KW_CONTINUE "continue"
107 %token<token> KW_CLASS "class"
108 %token<token> KW_CONST "const"
109 %token<token> KW_CATCH "catch"
110 %token<token> KW_CASE "case"
111 %token<token> KW_SET "set"
112 %token<token> KW_VOID "void"
113 %token<token> KW_THROW "throw"
114 %token<token> KW_STATIC "static"
115 %token<token> KW_WITH "with"
116 %token<token> KW_INSTANCEOF "instanceof"
117 %token<token> KW_IMPORT "import"
118 %token<token> KW_RETURN "return"
119 %token<token> KW_TYPEOF "typeof"
120 %token<token> KW_INTERFACE "interface"
121 %token<token> KW_NULL "null"
122 %token<token> KW_VAR "var"
123 %token<token> KW_DYNAMIC "dynamic"
124 %token<token> KW_OVERRIDE "override"
125 %token<token> KW_FINAL "final"
126 %token<token> KW_EACH "each"
127 %token<token> KW_GET "get"
128 %token<token> KW_TRY "try"
129 %token<token> KW_SUPER "super"
130 %token<token> KW_EXTENDS "extends"
131 %token<token> KW_FALSE "false"
132 %token<token> KW_TRUE "true"
133 %token<token> KW_BOOLEAN "Boolean"
134 %token<token> KW_UINT "uint"
135 %token<token> KW_INT "int"
136 %token<token> KW_NUMBER "Number"
137 %token<token> KW_STRING "String"
138 %token<token> KW_DEFAULT "default"
139 %token<token> KW_DELETE "delete"
140 %token<token> KW_IF "if"
141 %token<token> KW_ELSE "else"
142 %token<token> KW_BREAK "break"
143 %token<token> KW_IS "is"
144 %token<token> KW_IN "in"
145 %token<token> KW_AS "as"
147 %token<token> T_DICTSTART "{ (dictionary)"
148 %token<token> T_EQEQ "=="
149 %token<token> T_EQEQEQ "==="
150 %token<token> T_NE "!="
151 %token<token> T_NEE "!=="
152 %token<token> T_LE "<="
153 %token<token> T_GE ">="
154 %token<token> T_ORBY "|="
155 %token<token> T_DIVBY "/="
156 %token<token> T_MODBY "%="
157 %token<token> T_MULBY "*="
158 %token<token> T_ANDBY "&="
159 %token<token> T_PLUSBY "+="
160 %token<token> T_MINUSBY "-="
161 %token<token> T_XORBY "^="
162 %token<token> T_SHRBY ">>="
163 %token<token> T_SHLBY "<<="
164 %token<token> T_USHRBY ">>>="
165 %token<token> T_OROR "||"
166 %token<token> T_ANDAND "&&"
167 %token<token> T_COLONCOLON "::"
168 %token<token> T_MINUSMINUS "--"
169 %token<token> T_PLUSPLUS "++"
170 %token<token> T_DOTDOT ".."
171 %token<token> T_DOTDOTDOT "..."
172 %token<token> T_SHL "<<"
173 %token<token> T_USHR ">>>"
174 %token<token> T_SHR ">>"
176 %type <number_int> CONDITIONAL_COMPILATION
177 %type <for_start> FOR_START
178 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
179 %type <namespace_decl> NAMESPACE_ID
180 %type <token> VARCONST
182 %type <code> CODEPIECE CODE_STATEMENT
183 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
184 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
185 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
186 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
187 %type <exception> CATCH FINALLY
188 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
189 %type <code> CLASS_DECLARATION
190 %type <code> NAMESPACE_DECLARATION
191 %type <code> INTERFACE_DECLARATION
192 %type <code> VOIDEXPRESSION
193 %type <value> EXPRESSION NONCOMMAEXPRESSION
194 %type <node> MAYBEEXPRESSION
196 %type <node> E COMMA_EXPRESSION
197 %type <node> VAR_READ
198 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
199 %type <value> INNERFUNCTION
200 %type <code> USE_NAMESPACE
201 %type <code> FOR_INIT
203 %type <classinfo> MAYBETYPE
206 %type <params> PARAM_LIST
207 %type <params> MAYBE_PARAM_LIST
208 %type <flags> MAYBE_MODIFIERS
209 %type <flags> MODIFIER_LIST
210 %type <flags> MODIFIER
211 %type <constant> CONSTANT MAYBECONSTANT
212 %type <classinfo_list> IMPLEMENTS_LIST
213 %type <classinfo> EXTENDS CLASS_SPEC
214 %type <classinfo_list> EXTENDS_LIST
216 %type <classinfo> CLASS PACKAGEANDCLASS
217 %type <classinfo_list> CLASS_SPEC_LIST
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 MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST WITH_HEAD
227 // precedence: from low to high
231 %left below_semicolon
234 %nonassoc below_assignment // for ?:, contrary to spec
235 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
242 %nonassoc "==" "!=" "===" "!=="
243 %nonassoc "is" "as" "in"
244 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
245 %left "<<" ">>" ">>>"
249 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
251 %nonassoc below_curly
255 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
258 %left above_identifier
262 // needed for "return" precedence:
263 %nonassoc T_STRING T_REGEXP
264 %nonassoc T_INT T_UINT T_FLOAT KW_NAN
265 %nonassoc "false" "true" "null" "undefined" "super" "function"
272 static int a3_error(char*s)
274 syntaxerror("%s", s);
275 return 0; //make gcc happy
278 static void parsererror(const char*file, int line, const char*f)
280 syntaxerror("internal error in %s, %s:%d", f, file, line);
283 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
286 static char* concat2(const char* t1, const char* t2)
290 char*text = malloc(l1+l2+1);
291 memcpy(text , t1, l1);
292 memcpy(text+l1, t2, l2);
296 static char* concat3(const char* t1, const char* t2, const char* t3)
301 char*text = malloc(l1+l2+l3+1);
302 memcpy(text , t1, l1);
303 memcpy(text+l1, t2, l2);
304 memcpy(text+l1+l2, t3, l3);
309 typedef struct _import {
312 DECLARE_LIST(import);
314 DECLARE(methodstate);
315 DECLARE_LIST(methodstate);
317 typedef struct _classstate {
323 methodstate_t*static_init;
325 //code_t*static_init;
327 char has_constructor;
330 struct _methodstate {
340 dict_t*unresolved_variables;
343 char uses_parent_function;
349 int var_index; // for inner methods
350 int slot_index; // for inner methods
351 char is_a_slot; // for inner methods
356 abc_exception_list_t*exceptions;
358 methodstate_list_t*innerfunctions;
361 typedef struct _state {
366 import_list_t*wildcard_imports;
367 dict_t*import_toplevel_packages;
370 namespace_list_t*active_namespace_urls;
372 char has_own_imports;
373 char new_vars; // e.g. transition between two functions
376 methodstate_t*method;
385 typedef struct _global {
389 dict_t*file2token2info;
392 static global_t*global = 0;
393 static state_t* state = 0;
397 #define MULTINAME(m,x) \
401 registry_fill_multiname(&m, &m##_ns, (slotinfo_t*)(x));
403 #define MEMBER_MULTINAME(m,f,n) \
407 if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
408 m##_ns.name = ((slotinfo_t*)(f))->package; \
413 m.namespace_set = 0; \
414 m.name = ((slotinfo_t*)(f))->name; \
416 m.type = MULTINAME; \
418 m.namespace_set = &nopackage_namespace_set; \
422 /* warning: list length of namespace set is undefined */
423 #define MULTINAME_LATE(m, access, package) \
424 namespace_t m##_ns = {access, package}; \
425 namespace_set_t m##_nsset; \
426 namespace_list_t m##_l;m##_l.next = 0; \
427 m##_nsset.namespaces = &m##_l; \
428 m##_nsset = m##_nsset; \
429 m##_l.namespace = &m##_ns; \
430 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
432 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
433 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
434 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
435 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
436 static namespace_list_t nl4 = {&ns4,0};
437 static namespace_list_t nl3 = {&ns3,&nl4};
438 static namespace_list_t nl2 = {&ns2,&nl3};
439 static namespace_list_t nl1 = {&ns1,&nl2};
440 static namespace_set_t nopackage_namespace_set = {&nl1};
442 static dict_t*definitions=0;
443 void as3_set_define(const char*c)
446 definitions = dict_new();
447 if(!dict_contains(definitions,c))
448 dict_put(definitions,c,0);
451 static void new_state()
454 state_t*oldstate = state;
456 memcpy(s, state, sizeof(state_t)); //shallow copy
458 s->imports = dict_new();
460 if(!s->import_toplevel_packages) {
461 s->import_toplevel_packages = dict_new();
465 state->has_own_imports = 0;
466 state->vars = dict_new();
467 state->old = oldstate;
470 trie_remember(active_namespaces);
473 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
476 static void state_destroy(state_t*state)
478 if(state->has_own_imports) {
479 list_free(state->wildcard_imports);
480 dict_destroy(state->imports);state->imports=0;
482 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
483 dict_destroy(state->imports);state->imports=0;
487 for(t=0;t<state->vars->hashsize;t++) {
488 dictentry_t*e =state->vars->slots[t];
490 free(e->data);e->data=0;
494 dict_destroy(state->vars);state->vars=0;
497 list_free(state->active_namespace_urls)
498 state->active_namespace_urls = 0;
503 static void old_state()
505 trie_rollback(active_namespaces);
507 if(!state || !state->old)
508 syntaxerror("invalid nesting");
509 state_t*leaving = state;
513 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
514 free(leaving->method);
517 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
522 state_destroy(leaving);
525 static code_t* method_header(methodstate_t*m);
526 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
527 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
530 static char* internal_filename_package = 0;
531 void initialize_file(char*filename)
534 syntaxerror("invalid call to initialize_file during parsing of another file");
537 active_namespaces = trie_new();
540 state->package = internal_filename_package = strdup(filename);
542 global->token2info = dict_lookup(global->file2token2info,
543 current_filename // use long version
545 if(!global->token2info) {
546 global->token2info = dict_new2(&ptr_type);
547 dict_put(global->file2token2info, current_filename, global->token2info);
551 state->method = rfx_calloc(sizeof(methodstate_t));
552 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
553 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
555 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
557 syntaxerror("internal error: skewed tokencount");
558 function_initvars(state->method, 0, 0, 1);
559 global->init = abc_initscript(global->file);
565 if(!state || state->level!=1) {
566 syntaxerror("unexpected end of file in pass %d", as3_pass);
570 dict_del(global->file2token2info, current_filename);
572 code_t*header = method_header(state->method);
573 code_t*c = wrap_function(header, 0, global->init->method->body->code);
574 global->init->method->body->code = c;
575 free(state->method);state->method=0;
578 //free(state->package);state->package=0; // used in registry
579 state_destroy(state);state=0;
582 void initialize_parser()
584 global = rfx_calloc(sizeof(global_t));
585 global->file = abc_file_new();
586 global->file->flags &= ~ABCFILE_LAZY;
587 global->file2token2info = dict_new();
588 global->token2info = 0;
591 void* finish_parser()
593 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
594 global->token2info=0;
598 typedef struct _variable {
603 methodstate_t*is_inner_method;
606 static variable_t* find_variable(state_t*s, char*name)
610 v = dict_lookup(s->vars, name);
612 if(s->new_vars) break;
617 static variable_t* find_slot(state_t*s, const char*name)
619 if(s->method && s->method->slots)
620 return dict_lookup(s->method->slots, name);
624 static variable_t* find_variable_safe(state_t*s, char*name)
626 variable_t* v = find_variable(s, name);
628 syntaxerror("undefined variable: %s", name);
632 static char variable_exists(char*name)
634 return dict_contains(state->vars, name);
637 static code_t*defaultvalue(code_t*c, classinfo_t*type)
639 if(TYPE_IS_INT(type)) {
640 c = abc_pushbyte(c, 0);
641 } else if(TYPE_IS_UINT(type)) {
642 c = abc_pushuint(c, 0);
643 } else if(TYPE_IS_FLOAT(type)) {
645 } else if(TYPE_IS_BOOLEAN(type)) {
646 c = abc_pushfalse(c);
648 //c = abc_pushundefined(c);
649 syntaxerror("internal error: can't generate default value for * type");
653 c = abc_coerce2(c, &m);
658 static int alloc_local()
660 return state->method->variable_count++;
663 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
666 variable_t*v = find_slot(state, name);
672 v->index = alloc_local();
677 dict_put(state->vars, name, v);
681 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
683 return new_variable2(name, type, init, maybeslot)->index;
686 #define TEMPVARNAME "__as3_temp__"
689 variable_t*v = find_variable(state, TEMPVARNAME);
694 i = new_variable(TEMPVARNAME, 0, 0, 0);
699 static code_t* var_block(code_t*body)
705 for(t=0;t<state->vars->hashsize;t++) {
706 dictentry_t*e = state->vars->slots[t];
708 variable_t*v = (variable_t*)e->data;
709 if(v->type && v->init) {
710 c = defaultvalue(c, v->type);
711 c = abc_setlocal(c, v->index);
712 k = abc_kill(k, v->index);
722 if(x->opcode== OPCODE___BREAK__ ||
723 x->opcode== OPCODE___CONTINUE__) {
724 /* link kill code before break/continue */
725 code_t*e = code_dup(k);
726 code_t*s = code_start(e);
738 c = code_append(c, body);
739 c = code_append(c, k);
743 static void unknown_variable(char*name)
745 if(!state->method->unresolved_variables)
746 state->method->unresolved_variables = dict_new();
747 if(!dict_contains(state->method->unresolved_variables, name))
748 dict_put(state->method->unresolved_variables, name, 0);
751 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
753 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
754 c = abc_getlocal_0(c);
755 c = abc_pushscope(c);
758 /* FIXME: this alloc_local() causes variable indexes to be
759 different in pass2 than in pass1 */
760 if(!m->activation_var)
761 m->activation_var = alloc_local();
763 c = abc_newactivation(c);
765 c = abc_pushscope(c);
766 c = abc_setlocal(c, m->activation_var);
768 c = abc_getlocal(c, m->activation_var);
769 c = abc_pushscope(c);
775 static code_t* method_header(methodstate_t*m)
779 c = add_scope_code(c, m, 1);
781 methodstate_list_t*l = m->innerfunctions;
783 parserassert(l->methodstate->abc);
784 if(m->uses_slots && l->methodstate->is_a_slot) {
785 c = abc_getscopeobject(c, 1);
786 c = abc_newfunction(c, l->methodstate->abc);
788 c = abc_setlocal(c, l->methodstate->var_index);
789 c = abc_setslot(c, l->methodstate->slot_index);
791 c = abc_newfunction(c, l->methodstate->abc);
792 c = abc_setlocal(c, l->methodstate->var_index);
794 free(l->methodstate);l->methodstate=0;
798 c = code_append(c, m->header);
801 if(m->is_constructor && !m->has_super) {
802 // call default constructor
803 c = abc_getlocal_0(c);
804 c = abc_constructsuper(c, 0);
808 /* all parameters that are used by inner functions
809 need to be copied from local to slot */
810 parserassert(m->activation_var);
811 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
812 if(v->is_parameter) {
813 c = abc_getlocal(c, m->activation_var);
814 c = abc_getlocal(c, v->index);
815 c = abc_setslot(c, v->index);
819 list_free(m->innerfunctions);
820 m->innerfunctions = 0;
825 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
827 c = code_append(c, header);
828 c = code_append(c, var_block(body));
829 /* append return if necessary */
830 if(!c || (c->opcode != OPCODE_RETURNVOID &&
831 c->opcode != OPCODE_RETURNVALUE)) {
832 c = abc_returnvoid(c);
837 static void startpackage(char*name)
840 state->package = strdup(name);
842 static void endpackage()
844 //used e.g. in classinfo_register:
845 //free(state->package);state->package=0;
849 #define FLAG_PUBLIC 256
850 #define FLAG_PROTECTED 512
851 #define FLAG_PRIVATE 1024
852 #define FLAG_PACKAGEINTERNAL 2048
853 #define FLAG_NAMESPACE 4096
855 static namespace_t modifiers2access(modifiers_t*mod)
860 if(mod->flags&FLAG_NAMESPACE) {
861 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
862 syntaxerror("invalid combination of access levels and namespaces");
863 ns.access = ACCESS_NAMESPACE;
865 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
867 /* shouldn't happen- the tokenizer only reports something as a namespace
868 if it was already registered */
869 trie_dump(active_namespaces);
870 syntaxerror("unknown namespace: %s", mod->ns);
873 } else if(mod->flags&FLAG_PUBLIC) {
874 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
875 syntaxerror("invalid combination of access levels");
876 ns.access = ACCESS_PACKAGE;
877 } else if(mod->flags&FLAG_PRIVATE) {
878 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
879 syntaxerror("invalid combination of access levels");
880 ns.access = ACCESS_PRIVATE;
881 } else if(mod->flags&FLAG_PROTECTED) {
882 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
883 syntaxerror("invalid combination of access levels");
884 ns.access = ACCESS_PROTECTED;
886 ns.access = ACCESS_PACKAGEINTERNAL;
890 static slotinfo_t* find_class(const char*name);
892 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
894 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
897 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
902 index = new_variable("this", 0, 0, 0);
903 else if(!m->is_global)
904 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
906 index = new_variable("globalscope", 0, 0, 0);
907 parserassert(!index);
911 /* as variables and slots share the same number, make sure
912 that those variable indices are reserved. It's up to the
913 optimizer to later shuffle the variables down to lower
915 m->variable_count = m->uses_slots;
920 for(p=params->list;p;p=p->next) {
921 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
926 methodstate_list_t*l = m->innerfunctions;
928 methodstate_t*m = l->methodstate;
930 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
931 m->var_index = v->index;
932 m->slot_index = v->index;
933 v->is_inner_method = m;
939 m->scope_code = add_scope_code(m->scope_code, m, 0);
942 if(as3_pass==2 && m->slots) {
943 /* exchange unresolved identifiers with the actual objects */
944 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
945 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
946 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
947 if(!type || type->kind != INFOTYPE_CLASS) {
948 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
957 char*as3_globalclass=0;
958 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
961 syntaxerror("inner classes now allowed");
966 classinfo_list_t*mlist=0;
968 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
969 syntaxerror("invalid modifier(s)");
971 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
972 syntaxerror("public and internal not supported at the same time.");
974 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
975 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
976 // all classes extend object
977 extends = registry_getobjectclass();
980 /* create the class name, together with the proper attributes */
984 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
985 access = ACCESS_PRIVATE; package = internal_filename_package;
986 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
987 access = ACCESS_PACKAGEINTERNAL; package = state->package;
988 } else if(state->package!=internal_filename_package) {
989 access = ACCESS_PACKAGE; package = state->package;
991 syntaxerror("public classes only allowed inside a package");
995 state->cls = rfx_calloc(sizeof(classstate_t));
996 state->cls->init = rfx_calloc(sizeof(methodstate_t));
997 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
998 state->cls->static_init->variable_count=1;
999 /* notice: we make no effort to initialize the top variable (local0) here,
1000 even though it has special meaning. We just rely on the facat
1001 that pass 1 won't do anything with variables */
1003 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1005 /* set current method to constructor- all code within the class-level (except
1006 static variable initializations) will be executed during construction time */
1007 state->method = state->cls->init;
1009 if(registry_find(package, classname)) {
1010 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1012 /* build info struct */
1013 int num_interfaces = (list_length(implements));
1014 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1015 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1018 classinfo_list_t*l = implements;
1019 for(l=implements;l;l=l->next) {
1020 state->cls->info->interfaces[pos++] = l->classinfo;
1025 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1027 state->method = state->cls->init;
1028 parserassert(state->cls && state->cls->info);
1030 function_initvars(state->cls->init, 0, 0, 1);
1031 function_initvars(state->cls->static_init, 0, 0, 0);
1033 if(extends && (extends->flags & FLAG_FINAL))
1034 syntaxerror("Can't extend final class '%s'", extends->name);
1037 while(state->cls->info->interfaces[pos]) {
1038 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1039 syntaxerror("'%s' is not an interface",
1040 state->cls->info->interfaces[pos]->name);
1044 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
1045 state->cls->info->superclass = extends;
1047 /* generate the abc code for this class */
1048 MULTINAME(classname2,state->cls->info);
1049 multiname_t*extends2 = sig2mname(extends);
1051 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
1052 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1053 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1054 if(state->cls->info->flags&FLAG_INTERFACE) {
1055 abc_class_interface(state->cls->abc);
1058 abc_class_protectedNS(state->cls->abc, classname);
1060 for(mlist=implements;mlist;mlist=mlist->next) {
1061 MULTINAME(m, mlist->classinfo);
1062 abc_class_add_interface(state->cls->abc, &m);
1065 /* write the construction code for this class to the global init
1067 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
1069 abc_method_body_t*m = global->init->method->body;
1070 __ getglobalscope(m);
1071 classinfo_t*s = extends;
1076 //TODO: take a look at the current scope stack, maybe
1077 // we can re-use something
1082 multiname_t*s2 = sig2mname(s);
1084 multiname_destroy(s2);
1086 __ pushscope(m); count++;
1087 m->code = m->code->prev->prev; // invert
1089 /* continue appending after last op end */
1090 while(m->code && m->code->next) m->code = m->code->next;
1092 /* TODO: if this is one of *our* classes, we can also
1093 do a getglobalscope/getslot <nr> (which references
1094 the init function's slots) */
1096 __ getlex2(m, extends2);
1098 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
1099 stack is not the superclass */
1100 __ pushscope(m);count++;
1103 /* notice: we get a verify error #1107 if the top element on the scope
1104 stack is not the global object */
1106 __ pushscope(m);count++;
1108 __ newclass(m,state->cls->abc);
1112 __ setslot(m, slotindex);
1113 multiname_destroy(extends2);
1115 /* flash.display.MovieClip handling */
1117 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1118 if(state->package && state->package[0]) {
1119 as3_globalclass = concat3(state->package, ".", classname);
1121 as3_globalclass = strdup(classname);
1127 static void endclass()
1130 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1132 c = abc_getlocal_0(c);
1133 c = abc_constructsuper(c, 0);
1134 state->cls->init->header = code_append(state->cls->init->header, c);
1135 state->cls->has_constructor=1;
1137 if(state->cls->init) {
1138 if(state->cls->info->flags&FLAG_INTERFACE) {
1139 if(state->cls->init->header)
1140 syntaxerror("interface can not have class-level code");
1142 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1143 code_t*c = method_header(state->cls->init);
1144 m->body->code = wrap_function(c, 0, m->body->code);
1147 if(state->cls->static_init) {
1148 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1149 code_t*c = method_header(state->cls->static_init);
1150 m->body->code = wrap_function(c, 0, m->body->code);
1157 void check_code_for_break(code_t*c)
1160 if(c->opcode == OPCODE___BREAK__) {
1161 char*name = string_cstr(c->data[0]);
1162 syntaxerror("Unresolved \"break %s\"", name);
1164 if(c->opcode == OPCODE___CONTINUE__) {
1165 char*name = string_cstr(c->data[0]);
1166 syntaxerror("Unresolved \"continue %s\"", name);
1168 if(c->opcode == OPCODE___RETHROW__) {
1169 syntaxerror("Unresolved \"rethrow\"");
1171 if(c->opcode == OPCODE___FALLTHROUGH__) {
1172 syntaxerror("Unresolved \"fallthrough\"");
1174 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1175 char*name = string_cstr(c->data[0]);
1176 syntaxerror("Can't reference a package (%s) as such", name);
1182 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1184 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1185 if(TYPE_IS_NUMBER(t)) {
1186 xassert(c->type == CONSTANT_FLOAT
1187 || c->type == CONSTANT_INT
1188 || c->type == CONSTANT_UINT);
1189 } else if(TYPE_IS_UINT(t)) {
1190 xassert(c->type == CONSTANT_UINT ||
1191 (c->type == CONSTANT_INT && c->i>=0));
1192 } else if(TYPE_IS_INT(t)) {
1193 xassert(c->type == CONSTANT_INT);
1194 } else if(TYPE_IS_BOOLEAN(t)) {
1195 xassert(c->type == CONSTANT_TRUE
1196 || c->type == CONSTANT_FALSE);
1200 static void check_override(memberinfo_t*m, int flags)
1204 if(m->parent == state->cls->info)
1205 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1207 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1208 if(m->access==ACCESS_PRIVATE)
1210 if(m->flags & FLAG_FINAL)
1211 syntaxerror("can't override final member %s", m->name);
1213 /* allow this. it's no issue.
1214 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1215 syntaxerror("can't override static member %s", m->name);*/
1217 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1218 syntaxerror("can't override non-static member %s with static declaration", m->name);
1220 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1221 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1222 if(m->kind == INFOTYPE_METHOD)
1223 syntaxerror("can't override without explicit 'override' declaration");
1225 syntaxerror("can't override '%s'", m->name);
1230 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1232 methodinfo_t*minfo = 0;
1233 namespace_t ns = modifiers2access(mod);
1236 minfo = methodinfo_register_global(ns.access, state->package, name);
1237 minfo->return_type = 0; // save this for pass 2
1238 } else if(getset != KW_GET && getset != KW_SET) {
1240 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1242 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1244 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1245 minfo->return_type = 0; // save this for pass 2
1246 // getslot on a member slot only returns "undefined", so no need
1247 // to actually store these
1248 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1250 //class getter/setter
1251 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1253 if(getset == KW_GET) {
1255 } else if(params->list && params->list->param && !params->list->next) {
1256 type = params->list->param->type;
1258 syntaxerror("setter function needs to take exactly one argument");
1259 // not sure wether to look into superclasses here, too
1260 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1262 if(minfo->kind!=INFOTYPE_VAR)
1263 syntaxerror("class already contains a method called '%s'", name);
1264 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1265 syntaxerror("class already contains a field called '%s'", name);
1266 if(minfo->subtype & gs)
1267 syntaxerror("getter/setter for '%s' already defined", name);
1268 /* make a setter or getter into a getset */
1269 minfo->subtype |= gs;
1272 FIXME: this check needs to be done in pass 2
1274 if((!minfo->return_type != !type) ||
1275 (minfo->return_type && type &&
1276 !strcmp(minfo->return_type->name, type->name))) {
1277 syntaxerror("different type in getter and setter: %s and %s",
1278 minfo->return_type?minfo->return_type->name:"*",
1279 type?type->name:"*");
1282 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1283 minfo->kind = INFOTYPE_VAR; //hack
1284 minfo->subtype = gs;
1285 minfo->return_type = 0;
1287 /* can't assign a slot as getter and setter might have different slots */
1288 //minfo->slot = slot;
1290 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1291 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1292 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1297 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1299 //parserassert(state->method && state->method->info);
1301 methodstate_t*parent_method = state->method;
1304 return_type = 0; // not valid in pass 1
1308 state->new_vars = 1;
1311 state->method = rfx_calloc(sizeof(methodstate_t));
1312 state->method->inner = 1;
1313 state->method->variable_count = 0;
1314 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1316 NEW(methodinfo_t,minfo);
1317 minfo->kind = INFOTYPE_METHOD;
1318 minfo->access = ACCESS_PACKAGEINTERNAL;
1320 state->method->info = minfo;
1323 list_append(parent_method->innerfunctions, state->method);
1325 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1327 function_initvars(state->method, params, 0, 1);
1331 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1332 state->method->variable_count = 0;
1333 parserassert(state->method);
1335 state->method->info->return_type = return_type;
1336 function_initvars(state->method, params, 0, 1);
1340 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1341 params_t*params, classinfo_t*return_type)
1343 if(state->method && state->method->info) {
1344 syntaxerror("not able to start another method scope");
1347 state->new_vars = 1;
1350 state->method = rfx_calloc(sizeof(methodstate_t));
1351 state->method->has_super = 0;
1354 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1356 state->method->is_global = 1;
1357 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1359 if(state->method->is_constructor)
1360 name = "__as3_constructor__";
1362 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1364 function_initvars(state->method, params, mod->flags, 1);
1366 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1370 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1371 state->method->variable_count = 0;
1372 parserassert(state->method);
1375 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1376 check_override(m, mod->flags);
1380 state->cls->has_constructor |= state->method->is_constructor;
1383 state->method->info->return_type = return_type;
1384 function_initvars(state->method, 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 // store inner methods in variables
1393 function_initvars(state->method, 0, 0, 0);
1395 methodstate_list_t*ml = state->method->innerfunctions;
1397 dict_t*xvars = dict_new();
1400 methodstate_t*m = ml->methodstate;
1401 parserassert(m->inner);
1402 if(m->unresolved_variables) {
1403 dict_t*d = m->unresolved_variables;
1405 for(t=0;t<d->hashsize;t++) {
1406 dictentry_t*l = d->slots[t];
1408 /* check parent method's variables */
1410 if((v=find_variable(state, l->key))) {
1411 m->uses_parent_function = 1;
1412 state->method->uses_slots = 1;
1413 dict_put(xvars, l->key, 0);
1420 dict_destroy(m->unresolved_variables);
1421 m->unresolved_variables = 0;
1426 if(state->method->uses_slots) {
1427 state->method->slots = dict_new();
1429 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1430 if(!name) syntaxerror("internal error");
1431 if(v->index && dict_contains(xvars, name)) {
1434 if(v->is_inner_method) {
1435 v->is_inner_method->is_a_slot = 1;
1438 dict_put(state->method->slots, name, v);
1441 state->method->uses_slots = i;
1442 dict_destroy(state->vars);state->vars = 0;
1449 /*if(state->method->uses_parent_function){
1450 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1455 multiname_t*type2 = sig2mname(return_type);
1457 if(state->method->inner) {
1458 f = state->method->abc;
1459 abc_method_init(f, global->file, type2, 1);
1460 } else if(state->method->is_constructor) {
1461 f = abc_class_getconstructor(state->cls->abc, type2);
1462 } else if(!state->method->is_global) {
1463 namespace_t mname_ns = modifiers2access(mod);
1464 multiname_t mname = {QNAME, &mname_ns, 0, name};
1466 if(mod->flags&FLAG_STATIC)
1467 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1469 f = abc_class_method(state->cls->abc, type2, &mname);
1470 slot = f->trait->slot_id;
1472 namespace_t mname_ns = {state->method->info->access, state->package};
1473 multiname_t mname = {QNAME, &mname_ns, 0, name};
1475 f = abc_method_new(global->file, type2, 1);
1476 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1477 //abc_code_t*c = global->init->method->body->code;
1479 //flash doesn't seem to allow us to access function slots
1480 //state->method->info->slot = slot;
1482 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1483 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1484 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1485 if(params->varargs) f->flags |= METHOD_NEED_REST;
1489 for(p=params->list;p;p=p->next) {
1490 if(params->varargs && !p->next) {
1491 break; //varargs: omit last parameter in function signature
1493 multiname_t*m = sig2mname(p->param->type);
1494 list_append(f->parameters, m);
1495 if(p->param->value) {
1496 check_constant_against_type(p->param->type, p->param->value);
1497 opt=1;list_append(f->optional_parameters, p->param->value);
1499 syntaxerror("non-optional parameter not allowed after optional parameters");
1502 if(state->method->slots) {
1503 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1505 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1506 multiname_t*type = sig2mname(v->type);
1507 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1508 t->slot_id = v->index;
1513 check_code_for_break(body);
1515 /* Seems this works now.
1516 if(state->method->exceptions && state->method->uses_slots) {
1517 as3_warning("try/catch and activation not supported yet within the same method");
1521 f->body->code = body;
1522 f->body->exceptions = state->method->exceptions;
1523 } else { //interface
1525 syntaxerror("interface methods can't have a method body");
1535 void breakjumpsto(code_t*c, char*name, code_t*jump)
1538 if(c->opcode == OPCODE___BREAK__) {
1539 string_t*name2 = c->data[0];
1540 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1541 c->opcode = OPCODE_JUMP;
1548 void continuejumpsto(code_t*c, char*name, code_t*jump)
1551 if(c->opcode == OPCODE___CONTINUE__) {
1552 string_t*name2 = c->data[0];
1553 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1554 c->opcode = OPCODE_JUMP;
1562 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1564 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1569 return abc_coerce_a(c);
1573 // cast an "any" type to a specific type. subject to
1574 // runtime exceptions
1575 return abc_coerce2(c, &m);
1578 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1579 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1580 // allow conversion between number types
1581 if(TYPE_IS_UINT(to))
1582 return abc_convert_u(c);
1583 else if(TYPE_IS_INT(to))
1584 return abc_convert_i(c);
1585 else if(TYPE_IS_NUMBER(to))
1586 return abc_convert_d(c);
1587 return abc_coerce2(c, &m);
1590 if(TYPE_IS_BOOLEAN(to))
1591 return abc_convert_b(c);
1592 if(TYPE_IS_STRING(to))
1593 return abc_convert_s(c);
1594 if(TYPE_IS_OBJECT(to))
1595 return abc_convert_o(c);
1597 classinfo_t*supertype = from;
1599 if(supertype == to) {
1600 // target type is one of from's superclasses
1601 return abc_coerce2(c, &m);
1604 while(supertype->interfaces[t]) {
1605 if(supertype->interfaces[t]==to) {
1606 // target type is one of from's interfaces
1607 return abc_coerce2(c, &m);
1611 supertype = supertype->superclass;
1613 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1615 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1617 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1620 as3_error("can't convert type %s%s%s to %s%s%s",
1621 from->package, from->package[0]?".":"", from->name,
1622 to->package, to->package[0]?".":"", to->name);
1626 /* move to ast.c todo end */
1628 char is_pushundefined(code_t*c)
1630 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1633 static const char* get_package_from_name(const char*name)
1635 /* try explicit imports */
1636 dictentry_t* e = dict_get_slot(state->imports, name);
1638 if(!strcmp(e->key, name)) {
1639 slotinfo_t*c = (slotinfo_t*)e->data;
1640 if(c) return c->package;
1646 static namespace_list_t*get_current_imports()
1648 namespace_list_t*searchlist = 0;
1650 list_append(searchlist, namespace_new_package(state->package));
1652 import_list_t*l = state->wildcard_imports;
1654 namespace_t*ns = namespace_new_package(l->import->package);
1655 list_append(searchlist, ns);
1658 list_append(searchlist, namespace_new_package(""));
1659 list_append(searchlist, namespace_new_package(internal_filename_package));
1663 static slotinfo_t* find_class(const char*name)
1667 c = registry_find(state->package, name);
1670 /* try explicit imports */
1671 dictentry_t* e = dict_get_slot(state->imports, name);
1674 if(!strcmp(e->key, name)) {
1675 c = (slotinfo_t*)e->data;
1681 /* try package.* imports */
1682 import_list_t*l = state->wildcard_imports;
1684 //printf("does package %s contain a class %s?\n", l->import->package, name);
1685 c = registry_find(l->import->package, name);
1690 /* try global package */
1691 c = registry_find("", name);
1694 /* try local "filename" package */
1695 c = registry_find(internal_filename_package, name);
1700 typedcode_t push_class(slotinfo_t*a)
1705 if(a->access == ACCESS_PACKAGEINTERNAL &&
1706 strcmp(a->package, state->package) &&
1707 strcmp(a->package, internal_filename_package)
1709 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1710 infotypename(a), a->name, a->package, state->package);
1713 if(a->kind != INFOTYPE_CLASS) {
1715 x.c = abc_findpropstrict2(x.c, &m);
1716 x.c = abc_getproperty2(x.c, &m);
1717 if(a->kind == INFOTYPE_METHOD) {
1718 methodinfo_t*f = (methodinfo_t*)a;
1719 x.t = TYPE_FUNCTION(f);
1721 varinfo_t*v = (varinfo_t*)a;
1725 classinfo_t*c = (classinfo_t*)a;
1727 x.c = abc_getglobalscope(x.c);
1728 x.c = abc_getslot(x.c, c->slot);
1731 x.c = abc_getlex2(x.c, &m);
1733 x.t = TYPE_CLASS(c);
1739 char is_break_or_jump(code_t*c)
1743 if(c->opcode == OPCODE_JUMP ||
1744 c->opcode == OPCODE___BREAK__ ||
1745 c->opcode == OPCODE___CONTINUE__ ||
1746 c->opcode == OPCODE_THROW ||
1747 c->opcode == OPCODE_RETURNVOID ||
1748 c->opcode == OPCODE_RETURNVALUE) {
1754 #define IS_FINALLY_TARGET(op) \
1755 ((op) == OPCODE___CONTINUE__ || \
1756 (op) == OPCODE___BREAK__ || \
1757 (op) == OPCODE_RETURNVOID || \
1758 (op) == OPCODE_RETURNVALUE || \
1759 (op) == OPCODE___RETHROW__)
1761 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1763 #define NEED_EXTRA_STACK_ARG
1764 code_t*finally_label = abc_nop(0);
1765 NEW(lookupswitch_t, l);
1771 code_t*prev = i->prev;
1772 if(IS_FINALLY_TARGET(i->opcode)) {
1775 if(i->opcode == OPCODE___RETHROW__ ||
1776 i->opcode == OPCODE_RETURNVALUE) {
1777 if(i->opcode == OPCODE___RETHROW__)
1778 i->opcode = OPCODE_THROW;
1780 p = abc_coerce_a(p);
1781 p = abc_setlocal(p, tempvar);
1783 p = abc_pushbyte(p, count++);
1784 p = abc_jump(p, finally_label);
1785 code_t*target = p = abc_label(p);
1786 #ifdef NEED_EXTRA_STACK_ARG
1790 p = abc_getlocal(p, tempvar);
1793 p->next = i;i->prev = p;
1794 list_append(l->targets, target);
1800 c = abc_pushbyte(c, -1);
1801 c = code_append(c, finally_label);
1802 c = code_append(c, finally);
1804 #ifdef NEED_EXTRA_STACK_ARG
1807 c = abc_lookupswitch(c, l);
1808 c = l->def = abc_label(c);
1809 #ifdef NEED_EXTRA_STACK_ARG
1816 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1820 code_t*prev = i->prev;
1821 if(IS_FINALLY_TARGET(i->opcode)) {
1822 if(i->opcode == OPCODE___RETHROW__)
1823 i->opcode = OPCODE_THROW;
1824 code_t*end = code_dup(finally);
1825 code_t*start = code_start(end);
1826 if(prev) prev->next = start;
1833 return code_append(c, finally);
1836 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1842 int num_insertion_points=0;
1844 if(IS_FINALLY_TARGET(i->opcode))
1845 num_insertion_points++;
1852 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1857 int simple_version_cost = (1+num_insertion_points)*code_size;
1858 int lookup_version_cost = 4*num_insertion_points + 5;
1860 if(cantdup || simple_version_cost > lookup_version_cost) {
1861 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1862 return insert_finally_lookup(c, finally, tempvar);
1864 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1865 return insert_finally_simple(c, finally, tempvar);
1869 #define PASS1 }} if(as3_pass == 1) {{
1870 #define PASS1END }} if(as3_pass == 2) {{
1871 #define PASS2 }} if(as3_pass == 2) {{
1872 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1873 #define PASS12END }} if(as3_pass == 2) {{
1874 #define PASS_ALWAYS }} {{
1880 /* ------------ code blocks / statements ---------------- */
1882 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1884 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1885 PROGRAM_CODE_LIST: PROGRAM_CODE
1886 | PROGRAM_CODE_LIST PROGRAM_CODE
1888 PROGRAM_CODE: PACKAGE_DECLARATION
1889 | INTERFACE_DECLARATION
1891 | FUNCTION_DECLARATION
1894 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1897 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1898 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1899 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1901 INPACKAGE_CODE: INTERFACE_DECLARATION
1903 | FUNCTION_DECLARATION
1906 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1909 MAYBECODE: CODE {$$=$1;}
1910 MAYBECODE: {$$=code_new();}
1912 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1913 CODE: CODEPIECE {$$=$1;}
1915 // code which may appear outside of methods
1916 CODE_STATEMENT: IMPORT
1918 CODE_STATEMENT: FOR_IN
1919 CODE_STATEMENT: WHILE
1920 CODE_STATEMENT: DO_WHILE
1921 CODE_STATEMENT: SWITCH
1923 CODE_STATEMENT: WITH
1925 CODE_STATEMENT: VOIDEXPRESSION
1926 CODE_STATEMENT: USE_NAMESPACE
1927 CODE_STATEMENT: NAMESPACE_DECLARATION
1928 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1929 CODE_STATEMENT: '{' '}' {$$=0;}
1931 // code which may appear in methods
1932 CODEPIECE: ';' {$$=0;}
1933 CODEPIECE: CODE_STATEMENT
1934 CODEPIECE: VARIABLE_DECLARATION
1939 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {PASS_ALWAYS as3_pass=$1;}
1941 //CODEBLOCK : '{' CODE '}' {$$=$2;}
1942 //CODEBLOCK : '{' '}' {$$=0;}
1943 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1944 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1946 /* ------------ package init code ------------------- */
1948 PACKAGE_INITCODE: CODE_STATEMENT {
1949 code_t**cc = &global->init->method->body->code;
1950 *cc = code_append(*cc, $1);
1953 /* ------------ conditional compilation ------------- */
1955 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
1958 char*key = concat3($1,"::",$3);
1959 if(!definitions || !dict_contains(definitions, key)) {
1965 /* ------------ variables --------------------------- */
1968 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1974 MAYBEEXPRESSION : '=' E {$$=$2;}
1975 | {$$=mkdummynode();}
1977 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1978 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1980 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1981 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1983 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1986 if(variable_exists($1))
1987 syntaxerror("Variable %s already defined", $1);
1989 new_variable($1, 0, 1, 0);
1994 if(state->method->uses_slots) {
1995 variable_t* v = find_slot(state, $1);
1997 // this variable is stored in a slot
2005 index = new_variable($1, $2, 1, 0);
2008 $$ = slot?abc_getscopeobject(0, 1):0;
2010 typedcode_t v = node_read($3);
2011 if(!is_subtype_of(v.t, $2)) {
2012 syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
2015 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2016 $$ = code_append($$, v.c);
2017 $$ = converttype($$, v.t, $2);
2020 $$ = defaultvalue($$, $2);
2023 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2024 $$ = code_append($$, v.c);
2025 $$ = abc_coerce_a($$);
2027 // don't do anything
2035 $$ = abc_setslot($$, index);
2037 $$ = abc_setlocal($$, index);
2041 /* ------------ control flow ------------------------- */
2043 MAYBEELSE: %prec below_else {$$ = code_new();}
2044 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2045 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2047 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2050 $$ = code_append($$, $4.c);
2051 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2053 $$ = code_append($$, $6);
2055 myjmp = $$ = abc_jump($$, 0);
2057 myif->branch = $$ = abc_nop($$);
2059 $$ = code_append($$, $7);
2060 myjmp->branch = $$ = abc_nop($$);
2066 FOR_INIT : {$$=code_new();}
2067 FOR_INIT : VARIABLE_DECLARATION
2068 FOR_INIT : VOIDEXPRESSION
2070 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2071 // (I don't see any easy way to revolve this conflict otherwise, as we
2072 // can't touch VAR_READ without upsetting the precedence about "return")
2073 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2074 PASS1 $$=$2;new_variable($2,0,1,0);
2075 PASS2 $$=$2;new_variable($2,$3,1,0);
2077 FOR_IN_INIT : T_IDENTIFIER {
2082 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2083 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2085 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2086 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2088 $$ = code_append($$, $2);
2089 code_t*loopstart = $$ = abc_label($$);
2090 $$ = code_append($$, $4.c);
2091 code_t*myif = $$ = abc_iffalse($$, 0);
2092 $$ = code_append($$, $8);
2093 code_t*cont = $$ = abc_nop($$);
2094 $$ = code_append($$, $6);
2095 $$ = abc_jump($$, loopstart);
2096 code_t*out = $$ = abc_nop($$);
2097 breakjumpsto($$, $1.name, out);
2098 continuejumpsto($$, $1.name, cont);
2105 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2106 variable_t*var = find_variable(state, $2);
2108 syntaxerror("variable %s not known in this scope", $2);
2111 char*tmp1name = concat2($2, "__tmp1__");
2112 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2113 char*tmp2name = concat2($2, "__array__");
2114 int array = new_variable(tmp1name, 0, 0, 0);
2117 $$ = code_append($$, $4.c);
2118 $$ = abc_coerce_a($$);
2119 $$ = abc_setlocal($$, array);
2120 $$ = abc_pushbyte($$, 0);
2121 $$ = abc_setlocal($$, it);
2123 code_t*loopstart = $$ = abc_label($$);
2125 $$ = abc_hasnext2($$, array, it);
2126 code_t*myif = $$ = abc_iffalse($$, 0);
2127 $$ = abc_getlocal($$, array);
2128 $$ = abc_getlocal($$, it);
2130 $$ = abc_nextname($$);
2132 $$ = abc_nextvalue($$);
2133 $$ = converttype($$, 0, var->type);
2134 $$ = abc_setlocal($$, var->index);
2136 $$ = code_append($$, $6);
2137 $$ = abc_jump($$, loopstart);
2139 code_t*out = $$ = abc_nop($$);
2140 breakjumpsto($$, $1.name, out);
2141 continuejumpsto($$, $1.name, loopstart);
2153 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2157 code_t*myjmp = $$ = abc_jump($$, 0);
2158 code_t*loopstart = $$ = abc_label($$);
2159 $$ = code_append($$, $6);
2160 code_t*cont = $$ = abc_nop($$);
2161 myjmp->branch = cont;
2162 $$ = code_append($$, $4.c);
2163 $$ = abc_iftrue($$, loopstart);
2164 code_t*out = $$ = abc_nop($$);
2165 breakjumpsto($$, $1, out);
2166 continuejumpsto($$, $1, cont);
2172 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2174 code_t*loopstart = $$ = abc_label($$);
2175 $$ = code_append($$, $3);
2176 code_t*cont = $$ = abc_nop($$);
2177 $$ = code_append($$, $6.c);
2178 $$ = abc_iftrue($$, loopstart);
2179 code_t*out = $$ = abc_nop($$);
2180 breakjumpsto($$, $1, out);
2181 continuejumpsto($$, $1, cont);
2187 BREAK : "break" %prec prec_none {
2188 $$ = abc___break__(0, "");
2190 BREAK : "break" T_IDENTIFIER {
2191 $$ = abc___break__(0, $2);
2193 CONTINUE : "continue" %prec prec_none {
2194 $$ = abc___continue__(0, "");
2196 CONTINUE : "continue" T_IDENTIFIER {
2197 $$ = abc___continue__(0, $2);
2200 MAYBE_CASE_LIST : {$$=0;}
2201 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2202 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2203 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2204 CASE_LIST: CASE {$$=$1;}
2205 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2207 CASE: "case" E ':' MAYBECODE {
2208 $$ = abc_getlocal(0, state->switch_var);
2209 $$ = code_append($$, node_read($2).c);
2210 code_t*j = $$ = abc_ifne($$, 0);
2211 $$ = code_append($$, $4);
2212 if($$->opcode != OPCODE___BREAK__) {
2213 $$ = abc___fallthrough__($$, "");
2215 code_t*e = $$ = abc_nop($$);
2218 DEFAULT: "default" ':' MAYBECODE {
2221 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2222 $$ = node_read($4).c;
2223 $$ = abc_setlocal($$, state->switch_var);
2224 $$ = code_append($$, $7);
2226 code_t*out = $$ = abc_kill($$, state->switch_var);
2227 breakjumpsto($$, $1, out);
2229 code_t*c = $$,*lastblock=0;
2231 if(c->opcode == OPCODE_IFNE) {
2232 if(!c->next) syntaxerror("internal error in fallthrough handling");
2234 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2236 c->opcode = OPCODE_JUMP;
2237 c->branch = lastblock;
2239 /* fall through end of switch */
2240 c->opcode = OPCODE_NOP;
2250 /* ------------ try / catch /finally ---------------- */
2252 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2253 state->exception_name=$3;
2254 PASS1 new_variable($3, 0, 0, 0);
2255 PASS2 new_variable($3, $4, 0, 0);
2258 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2259 multiname_t name = {QNAME, &name_ns, 0, $3};
2261 NEW(abc_exception_t, e)
2262 e->exc_type = sig2mname($4);
2263 e->var_name = multiname_clone(&name);
2267 int i = find_variable_safe(state, $3)->index;
2268 e->target = c = abc_nop(0);
2269 c = abc_setlocal(c, i);
2270 c = code_append(c, code_dup(state->method->scope_code));
2271 c = code_append(c, $8);
2277 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2282 NEW(abc_exception_t, e)
2283 e->exc_type = 0; //all exceptions
2284 e->var_name = 0; //no name
2287 e->to = code_append(e->to, $4);
2293 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2294 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2295 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2296 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2300 list_append($$.l,$2);
2301 $$.finally = $2->to;$2->to=0;
2304 CATCH_FINALLY_LIST: FINALLY {
2308 list_append($$.l,$1);
2309 $$.finally = $1->to;$1->to=0;
2313 TRY : "try" '{' {PASS12 new_state();
2314 state->method->has_exceptions=1;
2315 state->method->late_binding=1;//for invariant scope_code
2316 } MAYBECODE '}' CATCH_FINALLY_LIST {
2317 code_t*out = abc_nop(0);
2319 code_t*start = abc_nop(0);
2320 $$ = code_append(start, $4);
2321 if(!is_break_or_jump($4)) {
2322 $$ = abc_jump($$, out);
2324 code_t*end = $$ = abc_nop($$);
2328 tmp = new_variable("__finally__", 0, 0, 0);
2330 abc_exception_list_t*l = $6.l;
2333 abc_exception_t*e = l->abc_exception;
2335 $$ = code_append($$, e->target);
2336 $$ = abc_jump($$, out);
2338 parserassert((ptroff_t)$6.finally);
2340 e->target = $$ = abc_nop($$);
2341 $$ = code_append($$, code_dup(state->method->scope_code));
2342 $$ = abc___rethrow__($$);
2350 $$ = code_append($$, out);
2352 $$ = insert_finally($$, $6.finally, tmp);
2354 list_concat(state->method->exceptions, $6.l);
2360 /* ------------ throw ------------------------------- */
2362 THROW : "throw" EXPRESSION {
2366 THROW : "throw" %prec prec_none {
2367 if(!state->exception_name)
2368 syntaxerror("re-throw only possible within a catch block");
2369 variable_t*v = find_variable(state, state->exception_name);
2371 $$=abc_getlocal($$, v->index);
2375 /* ------------ with -------------------------------- */
2377 WITH_HEAD : "with" '(' EXPRESSION ')' {
2379 if(state->method->has_exceptions) {
2380 int v = alloc_local();
2381 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2382 state->method->scope_code = abc_pushwith(state->method->scope_code);
2387 WITH : WITH_HEAD CODEBLOCK {
2388 /* remove getlocal;pushwith from scope code again */
2389 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2392 if(state->method->has_exceptions) {
2394 $$ = abc_setlocal($$, $1.number);
2396 $$ = abc_pushwith($$);
2397 $$ = code_append($$, $2);
2398 $$ = abc_popscope($$);
2402 /* ------------ packages and imports ---------------- */
2404 X_IDENTIFIER: T_IDENTIFIER
2405 | "package" {PASS12 $$="package";}
2406 | T_NAMESPACE {PASS12 $$=$1;}
2408 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2409 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2411 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2412 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2413 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2414 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2417 static void state_has_imports()
2419 state->wildcard_imports = list_clone(state->wildcard_imports);
2420 state->imports = dict_clone(state->imports);
2421 state->has_own_imports = 1;
2423 static void import_toplevel(const char*package)
2425 char* s = strdup(package);
2427 dict_put(state->import_toplevel_packages, s, 0);
2428 char*x = strrchr(s, '.');
2436 IMPORT : "import" PACKAGEANDCLASS {
2438 slotinfo_t*s = registry_find($2->package, $2->name);
2439 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2440 as3_schedule_class($2->package, $2->name);
2444 syntaxerror("Couldn't import class\n");
2445 state_has_imports();
2446 dict_put(state->imports, c->name, c);
2447 import_toplevel(c->package);
2450 IMPORT : "import" PACKAGE '.' '*' {
2452 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2453 as3_schedule_package($2);
2458 state_has_imports();
2459 list_append(state->wildcard_imports, i);
2460 import_toplevel(i->package);
2464 /* ------------ classes and interfaces (header) -------------- */
2466 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2467 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2468 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2469 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2471 $$.flags=$1.flags|$2.flags;
2472 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2473 $$.ns=$1.ns?$1.ns:$2.ns;
2476 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2477 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2478 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2479 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2480 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2481 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2482 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2483 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2484 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2485 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2489 EXTENDS : {PASS12 $$=0;}
2490 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2492 EXTENDS_LIST : {PASS12 $$=list_new();}
2493 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2495 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2496 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2498 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2499 EXTENDS IMPLEMENTS_LIST
2500 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2502 '}' {PASS12 endclass();$$=0;}
2504 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2506 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2507 startclass(&$1,$3,0,$4);}
2508 MAYBE_INTERFACE_BODY
2509 '}' {PASS12 endclass();$$=0;}
2511 /* ------------ classes and interfaces (body) -------------- */
2514 MAYBE_CLASS_BODY : CLASS_BODY
2515 CLASS_BODY : CLASS_BODY_ITEM
2516 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2517 CLASS_BODY_ITEM : ';'
2518 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2519 CLASS_BODY_ITEM : SLOT_DECLARATION
2520 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2522 CLASS_BODY_ITEM : CODE_STATEMENT {
2523 code_t*c = state->cls->static_init->header;
2524 c = code_append(c, $1);
2525 state->cls->static_init->header = c;
2528 MAYBE_INTERFACE_BODY :
2529 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2530 INTERFACE_BODY : IDECLARATION
2531 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2533 IDECLARATION : "var" T_IDENTIFIER {
2534 syntaxerror("variable declarations not allowed in interfaces");
2536 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2538 $1.flags |= FLAG_PUBLIC;
2539 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2540 syntaxerror("invalid method modifiers: interface methods always need to be public");
2542 startfunction(&$1,$3,$4,&$6,$8);
2543 endfunction(&$1,$3,$4,&$6,$8, 0);
2544 list_deep_free($6.list);
2547 /* ------------ classes and interfaces (body, slots ) ------- */
2550 static int slotstate_varconst = 0;
2551 static modifiers_t*slotstate_flags = 0;
2552 static void setslotstate(modifiers_t* flags, int varconst)
2554 slotstate_varconst = varconst;
2555 slotstate_flags = flags;
2557 if(flags && flags->flags&FLAG_STATIC) {
2558 state->method = state->cls->static_init;
2560 state->method = state->cls->init;
2563 parserassert(state->method);
2568 VARCONST: "var" | "const"
2570 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2572 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2573 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2575 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2578 int flags = slotstate_flags->flags;
2579 namespace_t ns = modifiers2access(slotstate_flags);
2583 varinfo_t* info = 0;
2585 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2587 check_override(i, flags);
2589 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2591 slotinfo_t*i = registry_find(state->package, $1);
2593 syntaxerror("package %s already contains '%s'", state->package, $1);
2595 if(ns.name && ns.name[0]) {
2596 syntaxerror("namespaces not allowed on package-level variables");
2598 info = varinfo_register_global(ns.access, state->package, $1);
2602 info->flags = flags;
2604 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2608 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2611 multiname_t mname = {QNAME, &ns, 0, $1};
2613 trait_list_t**traits;
2617 ns.name = state->package;
2618 traits = &global->init->traits;
2619 code = &global->init->method->body->code;
2620 } else if(flags&FLAG_STATIC) {
2622 traits = &state->cls->abc->static_traits;
2623 code = &state->cls->static_init->header;
2625 // instance variable
2626 traits = &state->cls->abc->traits;
2627 code = &state->cls->init->header;
2633 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2635 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2637 info->slot = t->slot_id;
2639 constant_t cval = $3->type->eval($3);
2640 if(cval.type!=CONSTANT_UNKNOWN) {
2641 /* compile time constant */
2642 t->value = malloc(sizeof(constant_t));
2643 memcpy(t->value, &cval, sizeof(constant_t));
2644 info->value = constant_clone(t->value);
2646 typedcode_t v = node_read($3);
2647 /* initalization code (if needed) */
2649 if(v.c && !is_pushundefined(v.c)) {
2650 c = abc_getlocal_0(c);
2651 c = code_append(c, v.c);
2652 c = converttype(c, v.t, $2);
2653 c = abc_setslot(c, t->slot_id);
2655 *code = code_append(*code, c);
2658 if(slotstate_varconst==KW_CONST) {
2659 t->kind= TRAIT_CONST;
2660 info->flags |= FLAG_CONST;
2667 /* ------------ constants -------------------------------------- */
2669 MAYBECONSTANT: {$$=0;}
2670 MAYBECONSTANT: '=' E {
2671 $$ = malloc(sizeof(constant_t));
2672 *$$ = node_eval($2);
2673 if($$->type == CONSTANT_UNKNOWN)
2674 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2677 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2678 CONSTANT : T_INT {$$ = constant_new_int($1);}
2680 $$ = constant_new_uint($1);
2682 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2683 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2684 CONSTANT : "true" {$$ = constant_new_true($1);}
2685 CONSTANT : "false" {$$ = constant_new_false($1);}
2686 CONSTANT : "null" {$$ = constant_new_null($1);}
2687 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2688 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2691 CONSTANT : T_IDENTIFIER {
2692 if(!strcmp($1, "NaN")) {
2693 $$ = constant_new_float(__builtin_nan(""));
2695 as3_warning("Couldn't evaluate constant value of %s", $1);
2696 $$ = constant_new_null($1);
2700 /* ------------ classes and interfaces (body, functions) ------- */
2702 // non-vararg version
2705 memset(&$$,0,sizeof($$));
2707 MAYBE_PARAM_LIST: PARAM_LIST {
2713 MAYBE_PARAM_LIST: "..." PARAM {
2715 memset(&$$,0,sizeof($$));
2717 list_append($$.list, $2);
2719 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2723 list_append($$.list, $4);
2727 PARAM_LIST: PARAM_LIST ',' PARAM {
2730 list_append($$.list, $3);
2734 memset(&$$,0,sizeof($$));
2735 list_append($$.list, $1);
2738 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2740 $$ = rfx_calloc(sizeof(param_t));
2746 PARAM: T_IDENTIFIER MAYBECONSTANT {
2748 $$ = rfx_calloc(sizeof(param_t));
2750 $$->type = TYPE_ANY;
2758 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2759 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2762 endfunction(&$1,$3,$4,&$6,0,0);
2764 if(!state->method->info) syntaxerror("internal error");
2766 code_t*c = method_header(state->method);
2767 c = wrap_function(c, 0, $11);
2769 endfunction(&$1,$3,$4,&$6,$8,c);
2771 list_deep_free($6.list);
2775 MAYBE_IDENTIFIER: T_IDENTIFIER
2776 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2777 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2778 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2781 endfunction(0,0,$2,&$4,0,0);
2783 methodinfo_t*f = state->method->info;
2784 if(!f || !f->kind) syntaxerror("internal error");
2786 code_t*c = method_header(state->method);
2787 c = wrap_function(c, 0, $9);
2789 int index = state->method->var_index;
2790 endfunction(0,0,$2,&$4,$6,c);
2792 $$.c = abc_getlocal(0, index);
2793 $$.t = TYPE_FUNCTION(f);
2795 PASS12 list_deep_free($4.list);
2799 /* ------------- package + class ids --------------- */
2801 CLASS: X_IDENTIFIER {
2802 PASS1 NEW(unresolvedinfo_t,c);
2803 memset(c, 0, sizeof(*c));
2804 c->kind = INFOTYPE_UNRESOLVED;
2806 c->package = get_package_from_name($1);
2808 c->nsset = get_current_imports();
2809 /* make the compiler look for this class in the current directory,
2811 as3_schedule_class_noerror(state->package, $1);
2813 $$ = (classinfo_t*)c;
2815 slotinfo_t*s = find_class($1);
2816 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2817 $$ = (classinfo_t*)s;
2820 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2821 PASS1 NEW(unresolvedinfo_t,c);
2822 memset(c, 0, sizeof(*c));
2823 c->kind = INFOTYPE_UNRESOLVED;
2826 $$ = (classinfo_t*)c;
2828 slotinfo_t*s = registry_find($1, $3);
2829 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2831 $$ = (classinfo_t*)s;
2834 CLASS_SPEC: PACKAGEANDCLASS
2837 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2838 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2840 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2841 | '*' {PASS12 $$=TYPE_ANY;}
2842 | "void" {PASS12 $$=TYPE_ANY;}
2844 | "String" {$$=registry_getstringclass();}
2845 | "int" {$$=registry_getintclass();}
2846 | "uint" {$$=registry_getuintclass();}
2847 | "Boolean" {$$=registry_getbooleanclass();}
2848 | "Number" {$$=registry_getnumberclass();}
2851 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2852 MAYBETYPE: {PASS12 $$=0;}
2854 /* ----------function calls, delete, constructor calls ------ */
2856 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
2857 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2859 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
2860 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2861 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2863 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
2867 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
2868 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
2869 $$.number= $1.number+1;
2870 $$.cc = code_append($1.cc, $2.c);
2874 NEW : "new" E XX MAYBE_PARAM_VALUES {
2875 typedcode_t v = node_read($2);
2877 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2879 code_t*paramcode = $4.cc;
2880 if($$.c->opcode == OPCODE_GETPROPERTY) {
2881 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2882 $$.c = code_cutlast($$.c);
2883 $$.c = code_append($$.c, paramcode);
2884 $$.c = abc_constructprop2($$.c, name, $4.number);
2885 multiname_destroy(name);
2886 } else if($$.c->opcode == OPCODE_GETSLOT) {
2887 int slot = (int)(ptroff_t)$$.c->data[0];
2888 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
2889 multiname_t*name = t->name;
2890 $$.c = code_cutlast($$.c);
2891 $$.c = code_append($$.c, paramcode);
2892 $$.c = abc_constructprop2($$.c, name, $4.number);
2894 $$.c = code_append($$.c, paramcode);
2895 $$.c = abc_construct($$.c, $4.number);
2899 if(TYPE_IS_CLASS(v.t) && v.t->data) {
2902 $$.c = abc_coerce_a($$.c);
2907 /* TODO: use abc_call (for calling local variables),
2908 abc_callstatic (for calling own methods)
2911 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2913 typedcode_t v = node_read($1);
2915 if($$.c->opcode == OPCODE_COERCE_A) {
2916 $$.c = code_cutlast($$.c);
2918 code_t*paramcode = $3.cc;
2921 if($$.c->opcode == OPCODE_GETPROPERTY) {
2922 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2923 $$.c = code_cutlast($$.c);
2924 $$.c = code_append($$.c, paramcode);
2925 $$.c = abc_callproperty2($$.c, name, $3.number);
2926 multiname_destroy(name);
2927 } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
2928 int slot = (int)(ptroff_t)$$.c->data[0];
2929 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
2930 if(t->kind!=TRAIT_METHOD) {
2931 //ok: flash allows to assign closures to members.
2933 multiname_t*name = t->name;
2934 $$.c = code_cutlast($$.c);
2935 $$.c = code_append($$.c, paramcode);
2936 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2937 $$.c = abc_callproperty2($$.c, name, $3.number);
2938 } else if($$.c->opcode == OPCODE_GETSUPER) {
2939 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2940 $$.c = code_cutlast($$.c);
2941 $$.c = code_append($$.c, paramcode);
2942 $$.c = abc_callsuper2($$.c, name, $3.number);
2943 multiname_destroy(name);
2945 $$.c = abc_getglobalscope($$.c);
2946 $$.c = code_append($$.c, paramcode);
2947 $$.c = abc_call($$.c, $3.number);
2950 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
2951 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
2953 $$.c = abc_coerce_a($$.c);
2958 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2959 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2960 if(!state->method) syntaxerror("super() not allowed outside of a function");
2961 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2964 $$.c = abc_getlocal_0($$.c);
2966 $$.c = code_append($$.c, $3.cc);
2968 this is dependent on the control path, check this somewhere else
2969 if(state->method->has_super)
2970 syntaxerror("constructor may call super() only once");
2972 state->method->has_super = 1;
2974 $$.c = abc_constructsuper($$.c, $3.number);
2975 $$.c = abc_pushundefined($$.c);
2979 DELETE: "delete" E {
2980 typedcode_t v = node_read($2);
2982 if($$.c->opcode == OPCODE_COERCE_A) {
2983 $$.c = code_cutlast($$.c);
2985 multiname_t*name = 0;
2986 if($$.c->opcode == OPCODE_GETPROPERTY) {
2987 $$.c->opcode = OPCODE_DELETEPROPERTY;
2988 } else if($$.c->opcode == OPCODE_GETSLOT) {
2989 int slot = (int)(ptroff_t)$$.c->data[0];
2990 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
2991 $$.c = code_cutlast($$.c);
2992 $$.c = abc_deleteproperty2($$.c, name);
2994 $$.c = abc_getlocal_0($$.c);
2995 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
2996 $$.c = abc_deleteproperty2($$.c, &m);
2998 $$.t = TYPE_BOOLEAN;
3001 RETURN: "return" %prec prec_none {
3002 $$ = abc_returnvoid(0);
3004 RETURN: "return" EXPRESSION {
3006 $$ = abc_returnvalue($$);
3009 // ----------------------- expression types -------------------------------------
3011 NONCOMMAEXPRESSION : E %prec below_minus {
3014 EXPRESSION : COMMA_EXPRESSION {
3017 COMMA_EXPRESSION : E %prec below_minus {
3018 $$ = mkmultinode(&node_comma, $1);
3020 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_minus {
3021 $$ = multinode_extend($1, $3);
3023 VOIDEXPRESSION : E %prec below_minus {
3026 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_minus {
3028 $$ = code_append($$, node_exec($3));
3031 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3032 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
3034 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3036 $$.cc = code_append($$.cc, $1.c);
3037 $$.cc = code_append($$.cc, $3.c);
3040 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3042 $$.number = $1.number+2;
3043 $$.cc = code_append($$.cc, $3.c);
3044 $$.cc = code_append($$.cc, $5.c);
3047 // ----------------------- expression evaluation -------------------------------------
3049 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3050 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3051 E : NEW {$$ = mkcodenode($1);}
3052 E : DELETE {$$ = mkcodenode($1);}
3053 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3054 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3057 $$ = mkconstnode($1);
3064 namespace_t ns = {ACCESS_PACKAGE, ""};
3065 multiname_t m = {QNAME, &ns, 0, "RegExp"};
3067 v.c = abc_getlex2(v.c, &m);
3068 v.c = abc_pushstring(v.c, $1.pattern);
3069 v.c = abc_construct(v.c, 1);
3071 v.c = abc_getlex2(v.c, &m);
3072 v.c = abc_pushstring(v.c, $1.pattern);
3073 v.c = abc_pushstring(v.c, $1.options);
3074 v.c = abc_construct(v.c, 2);
3081 E : '[' MAYBE_EXPRESSION_LIST ']' {
3084 v.c = code_append(v.c, $2.cc);
3085 v.c = abc_newarray(v.c, $2.number);
3086 v.t = registry_getarrayclass();
3091 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
3094 v.c = code_append(v.c, $2.cc);
3095 v.c = abc_newobject(v.c, $2.number/2);
3096 v.t = registry_getobjectclass();
3100 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3101 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3102 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3103 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3104 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3105 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3106 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3107 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3108 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3109 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3110 E : '!' E {$$ = mknode1(&node_not, $2);}
3111 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3112 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3113 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3114 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3115 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3116 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3117 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3118 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3119 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3120 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3121 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3122 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3123 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3124 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3125 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3126 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3127 E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
3128 E : "void" E {$$ = mknode1(&node_void, $2);}
3129 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3130 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3131 E : '-' E {$$ = mknode1(&node_neg, $2);}
3132 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3133 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3134 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3135 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3136 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3137 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3138 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3139 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3140 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3141 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3142 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3143 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3144 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3145 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3147 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3148 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3149 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3150 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3152 E : "super" '.' T_IDENTIFIER
3153 { if(!state->cls->info)
3154 syntaxerror("super keyword not allowed outside a class");
3155 classinfo_t*t = state->cls->info->superclass;
3156 if(!t) t = TYPE_OBJECT;
3157 memberinfo_t*f = findmember_nsset(t, $3, 1);
3158 MEMBER_MULTINAME(m, f, $3);
3161 v.c = abc_getlocal_0(v.c);
3162 v.c = abc_getsuper2(v.c, &m);
3163 v.t = slotinfo_gettype((slotinfo_t*)f);
3167 E : '@' T_IDENTIFIER {
3170 as3_warning("ignored @ operator");
3173 E : E '.' '@' T_IDENTIFIER {
3174 // child attribute TODO
3176 as3_warning("ignored .@ operator");
3179 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3180 // namespace declaration TODO
3182 as3_warning("ignored :: operator");
3185 E : E ".." T_IDENTIFIER {
3188 as3_warning("ignored .. operator");
3191 E : E '.' '(' E ')' {
3194 as3_warning("ignored .() operator");
3197 //E : E "::" '[' E ']' {
3198 // // qualified expression TODO
3199 // $$.c = abc_pushundefined(0);
3201 // as3_warning("ignored ::[] operator");
3204 MEMBER : E '.' T_IDENTIFIER {
3205 typedcode_t v1 = node_read($1);
3207 classinfo_t*t = v1.t;
3209 if(TYPE_IS_CLASS(t) && t->data) {
3214 if(t->subtype==INFOTYPE_UNRESOLVED) {
3215 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3217 memberinfo_t*f = findmember_nsset(t, $3, 1);
3219 if(f && !is_static != !(f->flags&FLAG_STATIC))
3221 if(f && f->slot && !noslot) {
3222 $$.c = abc_getslot($$.c, f->slot);
3225 as3_warning("Access of undefined property '%s' in %s", $3, t->name);
3228 MEMBER_MULTINAME(m, f, $3);
3229 $$.c = abc_getproperty2($$.c, &m);
3231 /* determine type */
3232 $$.t = slotinfo_gettype((slotinfo_t*)f);
3234 $$.c = abc_coerce_a($$.c);
3235 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3236 string_t*package = v1.c->data[0];
3237 char*package2 = concat3(package->str, ".", $3);
3239 slotinfo_t*a = registry_find(package->str, $3);
3242 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3243 registry_ispackage(package2)) {
3245 $$.c->data[0] = string_new4(package2);
3248 syntaxerror("couldn't resolve %s", package2);
3251 /* when resolving a property on an unknown type, we do know the
3252 name of the property (and don't seem to need the package), but
3253 we need to make avm2 try out all access modes */
3254 as3_warning("Resolving %s on unknown type", $3);
3255 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3256 $$.c = abc_getproperty2($$.c, &m);
3257 $$.c = abc_coerce_a($$.c);
3262 VAR_READ : T_IDENTIFIER {
3264 /* Queue unresolved identifiers for checking against the parent
3265 function's variables.
3266 We consider everything which is not a local variable "unresolved".
3267 This encompasses class names, members of the surrounding class
3268 etc. which is *correct* because local variables of the parent function
3271 if(state->method->inner && !find_variable(state, $1)) {
3272 unknown_variable($1);
3275 /* let the compiler know that it might want to check the current directory/package
3276 for this identifier- maybe there's a file $1.as defining $1. */
3277 as3_schedule_class_noerror(state->package, $1);
3289 /* look at variables */
3290 if((v = find_variable(state, $1))) {
3291 // $1 is a local variable
3292 o.c = abc_getlocal(o.c, v->index);
3297 if((v = find_slot(state, $1))) {
3298 o.c = abc_getscopeobject(o.c, 1);
3299 o.c = abc_getslot(o.c, v->index);
3305 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3307 /* look at current class' members */
3308 if(!state->method->inner &&
3310 (f = findmember_nsset(state->cls->info, $1, 1)))
3312 // $1 is a member or attribute in this class
3313 int var_is_static = (f->flags&FLAG_STATIC);
3315 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3316 /* if the variable is a constant (and we know what is evaluates to), we
3317 can just use the value itself */
3318 varinfo_t*v = (varinfo_t*)f;
3320 $$ = mkconstnode(v->value);
3325 if(var_is_static >= i_am_static) {
3326 if(f->kind == INFOTYPE_METHOD) {
3327 o.t = TYPE_FUNCTION(f);
3332 if(var_is_static && !i_am_static) {
3333 /* access to a static member from a non-static location.
3334 do this via findpropstrict:
3335 there doesn't seem to be any non-lookup way to access
3336 static properties of a class */
3337 state->method->late_binding = 1;
3339 namespace_t ns = {f->access, f->package};
3340 multiname_t m = {QNAME, &ns, 0, $1};
3341 o.c = abc_findpropstrict2(o.c, &m);
3342 o.c = abc_getproperty2(o.c, &m);
3345 } else if(f->slot>0) {
3346 o.c = abc_getlocal_0(o.c);
3347 o.c = abc_getslot(o.c, f->slot);
3351 namespace_t ns = {f->access, f->package};
3352 multiname_t m = {QNAME, &ns, 0, $1};
3353 o.c = abc_getlocal_0(o.c);
3354 o.c = abc_getproperty2(o.c, &m);
3361 /* look at actual classes, in the current package and imported */
3362 if((a = find_class($1))) {
3368 /* look through package prefixes */
3369 if(dict_contains(state->import_toplevel_packages, $1) ||
3370 registry_ispackage($1)) {
3371 o.c = abc___pushpackage__(o.c, $1);
3373 $$ = mkcodenode(o); //?
3377 /* unknown object, let the avm2 resolve it */
3379 //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3380 as3_warning("Couldn't resolve '%s', doing late binding", $1);
3381 state->method->late_binding = 1;
3383 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3386 o.c = abc_findpropstrict2(o.c, &m);
3387 o.c = abc_getproperty2(o.c, &m);
3393 // ----------------- namespaces -------------------------------------------------
3395 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3397 NEW(namespace_decl_t,n);
3402 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3404 NEW(namespace_decl_t,n);
3409 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3411 NEW(namespace_decl_t,n);
3416 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3418 trie_put(active_namespaces, $2->name, (void*)$2->url);
3420 namespace_t access = modifiers2access(&$1);
3421 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3422 var->type = TYPE_NAMESPACE;
3424 ns.access = ACCESS_NAMESPACE;
3426 var->value = constant_new_namespace(&ns);
3432 void add_active_url(const char*url)
3436 list_append(state->active_namespace_urls, n);
3440 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3442 const char*url = $3->name;
3444 varinfo_t*s = (varinfo_t*)$3;
3445 if(s->kind == INFOTYPE_UNRESOLVED) {
3446 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3448 syntaxerror("Couldn't resolve namespace %s", $3->name);
3451 if(!s || s->kind != INFOTYPE_VAR)
3452 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3453 if(!s->value || !NS_TYPE(s->value->type))
3454 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3455 url = s->value->ns->name;
3457 trie_put(active_namespaces, $3->name, (void*)url);
3458 add_active_url(url);