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 <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
198 %type <value> INNERFUNCTION
199 %type <code> USE_NAMESPACE
200 %type <code> FOR_INIT
202 %type <classinfo> MAYBETYPE
205 %type <params> PARAM_LIST
206 %type <params> MAYBE_PARAM_LIST
207 %type <flags> MAYBE_MODIFIERS
208 %type <flags> MODIFIER_LIST
209 %type <flags> MODIFIER
210 %type <constant> CONSTANT MAYBECONSTANT
211 %type <classinfo_list> IMPLEMENTS_LIST
212 %type <classinfo> EXTENDS CLASS_SPEC
213 %type <classinfo_list> EXTENDS_LIST
215 %type <classinfo> CLASS PACKAGEANDCLASS
216 %type <classinfo_list> CLASS_SPEC_LIST
218 %type <classinfo> TYPE
219 //%type <token> VARIABLE
220 %type <value> VAR_READ MEMBER
222 //%type <token> T_IDENTIFIER
223 %type <value> FUNCTIONCALL
224 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST WITH_HEAD
226 // precedence: from low to high
230 %left below_semicolon
233 %nonassoc below_assignment // for ?:, contrary to spec
234 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
241 %nonassoc "==" "!=" "===" "!=="
242 %nonassoc "is" "as" "in"
243 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
244 %left "<<" ">>" ">>>"
248 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
250 %nonassoc below_curly
254 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
257 %left above_identifier
261 // needed for "return" precedence:
262 %nonassoc T_STRING T_REGEXP
263 %nonassoc T_INT T_UINT T_FLOAT KW_NAN
264 %nonassoc "false" "true" "null" "undefined" "super" "function"
271 static int a3_error(char*s)
273 syntaxerror("%s", s);
274 return 0; //make gcc happy
277 static void parsererror(const char*file, int line, const char*f)
279 syntaxerror("internal error in %s, %s:%d", f, file, line);
282 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
285 static char* concat2(const char* t1, const char* t2)
289 char*text = malloc(l1+l2+1);
290 memcpy(text , t1, l1);
291 memcpy(text+l1, t2, l2);
295 static char* concat3(const char* t1, const char* t2, const char* t3)
300 char*text = malloc(l1+l2+l3+1);
301 memcpy(text , t1, l1);
302 memcpy(text+l1, t2, l2);
303 memcpy(text+l1+l2, t3, l3);
308 typedef struct _import {
311 DECLARE_LIST(import);
313 DECLARE(methodstate);
314 DECLARE_LIST(methodstate);
316 typedef struct _classstate {
322 methodstate_t*static_init;
324 //code_t*static_init;
326 char has_constructor;
329 struct _methodstate {
339 dict_t*unresolved_variables;
342 char uses_parent_function;
348 int var_index; // for inner methods
349 int slot_index; // for inner methods
350 char is_a_slot; // for inner methods
355 abc_exception_list_t*exceptions;
357 methodstate_list_t*innerfunctions;
360 typedef struct _state {
365 import_list_t*wildcard_imports;
366 dict_t*import_toplevel_packages;
369 namespace_list_t*active_namespace_urls;
371 char has_own_imports;
372 char new_vars; // e.g. transition between two functions
375 methodstate_t*method;
384 typedef struct _global {
388 dict_t*file2token2info;
391 static global_t*global = 0;
392 static state_t* state = 0;
396 #define MULTINAME(m,x) \
400 registry_fill_multiname(&m, &m##_ns, (slotinfo_t*)(x));
402 #define MEMBER_MULTINAME(m,f,n) \
406 if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
407 m##_ns.name = ((slotinfo_t*)(f))->package; \
412 m.namespace_set = 0; \
413 m.name = ((slotinfo_t*)(f))->name; \
415 m.type = MULTINAME; \
417 m.namespace_set = &nopackage_namespace_set; \
421 /* warning: list length of namespace set is undefined */
422 #define MULTINAME_LATE(m, access, package) \
423 namespace_t m##_ns = {access, package}; \
424 namespace_set_t m##_nsset; \
425 namespace_list_t m##_l;m##_l.next = 0; \
426 m##_nsset.namespaces = &m##_l; \
427 m##_nsset = m##_nsset; \
428 m##_l.namespace = &m##_ns; \
429 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
431 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
432 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
433 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
434 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
435 static namespace_list_t nl4 = {&ns4,0};
436 static namespace_list_t nl3 = {&ns3,&nl4};
437 static namespace_list_t nl2 = {&ns2,&nl3};
438 static namespace_list_t nl1 = {&ns1,&nl2};
439 static namespace_set_t nopackage_namespace_set = {&nl1};
441 static dict_t*definitions=0;
442 void as3_set_define(const char*c)
445 definitions = dict_new();
446 if(!dict_contains(definitions,c))
447 dict_put(definitions,c,0);
450 static void new_state()
453 state_t*oldstate = state;
455 memcpy(s, state, sizeof(state_t)); //shallow copy
457 s->imports = dict_new();
459 if(!s->import_toplevel_packages) {
460 s->import_toplevel_packages = dict_new();
464 state->has_own_imports = 0;
465 state->vars = dict_new();
466 state->old = oldstate;
469 trie_remember(active_namespaces);
472 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
475 static void state_destroy(state_t*state)
477 if(state->has_own_imports) {
478 list_free(state->wildcard_imports);
479 dict_destroy(state->imports);state->imports=0;
481 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
482 dict_destroy(state->imports);state->imports=0;
486 for(t=0;t<state->vars->hashsize;t++) {
487 dictentry_t*e =state->vars->slots[t];
489 free(e->data);e->data=0;
493 dict_destroy(state->vars);state->vars=0;
496 list_free(state->active_namespace_urls)
497 state->active_namespace_urls = 0;
502 static void old_state()
504 trie_rollback(active_namespaces);
506 if(!state || !state->old)
507 syntaxerror("invalid nesting");
508 state_t*leaving = state;
512 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
513 free(leaving->method);
516 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
521 state_destroy(leaving);
524 static code_t* method_header(methodstate_t*m);
525 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
526 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
529 static char* internal_filename_package = 0;
530 void initialize_file(char*filename)
533 syntaxerror("invalid call to initialize_file during parsing of another file");
536 active_namespaces = trie_new();
539 state->package = internal_filename_package = strdup(filename);
541 global->token2info = dict_lookup(global->file2token2info,
542 current_filename // use long version
544 if(!global->token2info) {
545 global->token2info = dict_new2(&ptr_type);
546 dict_put(global->file2token2info, current_filename, global->token2info);
550 state->method = rfx_calloc(sizeof(methodstate_t));
551 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
552 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
554 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
556 syntaxerror("internal error: skewed tokencount");
557 function_initvars(state->method, 0, 0, 1);
558 global->init = abc_initscript(global->file);
564 if(!state || state->level!=1) {
565 syntaxerror("unexpected end of file in pass %d", as3_pass);
569 dict_del(global->file2token2info, current_filename);
571 code_t*header = method_header(state->method);
572 code_t*c = wrap_function(header, 0, global->init->method->body->code);
573 global->init->method->body->code = c;
574 free(state->method);state->method=0;
577 //free(state->package);state->package=0; // used in registry
578 state_destroy(state);state=0;
581 void initialize_parser()
583 global = rfx_calloc(sizeof(global_t));
584 global->file = abc_file_new();
585 global->file->flags &= ~ABCFILE_LAZY;
586 global->file2token2info = dict_new();
587 global->token2info = 0;
590 void* finish_parser()
592 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
593 global->token2info=0;
597 typedef struct _variable {
602 methodstate_t*is_inner_method;
605 static variable_t* find_variable(state_t*s, char*name)
609 v = dict_lookup(s->vars, name);
611 if(s->new_vars) break;
616 static variable_t* find_slot(state_t*s, const char*name)
618 if(s->method && s->method->slots)
619 return dict_lookup(s->method->slots, name);
623 static variable_t* find_variable_safe(state_t*s, char*name)
625 variable_t* v = find_variable(s, name);
627 syntaxerror("undefined variable: %s", name);
631 static char variable_exists(char*name)
633 return dict_contains(state->vars, name);
636 static code_t*defaultvalue(code_t*c, classinfo_t*type)
638 if(TYPE_IS_INT(type)) {
639 c = abc_pushbyte(c, 0);
640 } else if(TYPE_IS_UINT(type)) {
641 c = abc_pushuint(c, 0);
642 } else if(TYPE_IS_FLOAT(type)) {
644 } else if(TYPE_IS_BOOLEAN(type)) {
645 c = abc_pushfalse(c);
647 //c = abc_pushundefined(c);
648 syntaxerror("internal error: can't generate default value for * type");
652 c = abc_coerce2(c, &m);
657 static int alloc_local()
659 return state->method->variable_count++;
662 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
665 variable_t*v = find_slot(state, name);
671 v->index = alloc_local();
676 dict_put(state->vars, name, v);
680 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
682 return new_variable2(name, type, init, maybeslot)->index;
685 #define TEMPVARNAME "__as3_temp__"
688 variable_t*v = find_variable(state, TEMPVARNAME);
693 i = new_variable(TEMPVARNAME, 0, 0, 0);
698 static code_t* var_block(code_t*body)
704 for(t=0;t<state->vars->hashsize;t++) {
705 dictentry_t*e = state->vars->slots[t];
707 variable_t*v = (variable_t*)e->data;
708 if(v->type && v->init) {
709 c = defaultvalue(c, v->type);
710 c = abc_setlocal(c, v->index);
711 k = abc_kill(k, v->index);
721 if(x->opcode== OPCODE___BREAK__ ||
722 x->opcode== OPCODE___CONTINUE__) {
723 /* link kill code before break/continue */
724 code_t*e = code_dup(k);
725 code_t*s = code_start(e);
737 c = code_append(c, body);
738 c = code_append(c, k);
742 static void unknown_variable(char*name)
744 if(!state->method->unresolved_variables)
745 state->method->unresolved_variables = dict_new();
746 if(!dict_contains(state->method->unresolved_variables, name))
747 dict_put(state->method->unresolved_variables, name, 0);
750 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
752 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
753 c = abc_getlocal_0(c);
754 c = abc_pushscope(c);
757 /* FIXME: this alloc_local() causes variable indexes to be
758 different in pass2 than in pass1 */
759 if(!m->activation_var)
760 m->activation_var = alloc_local();
762 c = abc_newactivation(c);
764 c = abc_pushscope(c);
765 c = abc_setlocal(c, m->activation_var);
767 c = abc_getlocal(c, m->activation_var);
768 c = abc_pushscope(c);
774 static code_t* method_header(methodstate_t*m)
778 c = add_scope_code(c, m, 1);
780 methodstate_list_t*l = m->innerfunctions;
782 parserassert(l->methodstate->abc);
783 if(m->uses_slots && l->methodstate->is_a_slot) {
784 c = abc_getscopeobject(c, 1);
785 c = abc_newfunction(c, l->methodstate->abc);
787 c = abc_setlocal(c, l->methodstate->var_index);
788 c = abc_setslot(c, l->methodstate->slot_index);
790 c = abc_newfunction(c, l->methodstate->abc);
791 c = abc_setlocal(c, l->methodstate->var_index);
793 free(l->methodstate);l->methodstate=0;
797 c = code_append(c, m->header);
800 if(m->is_constructor && !m->has_super) {
801 // call default constructor
802 c = abc_getlocal_0(c);
803 c = abc_constructsuper(c, 0);
807 /* all parameters that are used by inner functions
808 need to be copied from local to slot */
809 parserassert(m->activation_var);
810 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
811 if(v->is_parameter) {
812 c = abc_getlocal(c, m->activation_var);
813 c = abc_getlocal(c, v->index);
814 c = abc_setslot(c, v->index);
818 list_free(m->innerfunctions);
819 m->innerfunctions = 0;
824 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
826 c = code_append(c, header);
827 c = code_append(c, var_block(body));
828 /* append return if necessary */
829 if(!c || (c->opcode != OPCODE_RETURNVOID &&
830 c->opcode != OPCODE_RETURNVALUE)) {
831 c = abc_returnvoid(c);
836 static void startpackage(char*name)
839 state->package = strdup(name);
841 static void endpackage()
843 //used e.g. in classinfo_register:
844 //free(state->package);state->package=0;
848 #define FLAG_PUBLIC 256
849 #define FLAG_PROTECTED 512
850 #define FLAG_PRIVATE 1024
851 #define FLAG_PACKAGEINTERNAL 2048
852 #define FLAG_NAMESPACE 4096
854 static namespace_t modifiers2access(modifiers_t*mod)
859 if(mod->flags&FLAG_NAMESPACE) {
860 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
861 syntaxerror("invalid combination of access levels and namespaces");
862 ns.access = ACCESS_NAMESPACE;
864 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
866 /* shouldn't happen- the tokenizer only reports something as a namespace
867 if it was already registered */
868 trie_dump(active_namespaces);
869 syntaxerror("unknown namespace: %s", mod->ns);
872 } else if(mod->flags&FLAG_PUBLIC) {
873 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
874 syntaxerror("invalid combination of access levels");
875 ns.access = ACCESS_PACKAGE;
876 } else if(mod->flags&FLAG_PRIVATE) {
877 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
878 syntaxerror("invalid combination of access levels");
879 ns.access = ACCESS_PRIVATE;
880 } else if(mod->flags&FLAG_PROTECTED) {
881 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
882 syntaxerror("invalid combination of access levels");
883 ns.access = ACCESS_PROTECTED;
885 ns.access = ACCESS_PACKAGEINTERNAL;
889 static slotinfo_t* find_class(const char*name);
891 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
893 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
896 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
901 index = new_variable("this", 0, 0, 0);
902 else if(!m->is_global)
903 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
905 index = new_variable("globalscope", 0, 0, 0);
906 parserassert(!index);
910 /* as variables and slots share the same number, make sure
911 that those variable indices are reserved. It's up to the
912 optimizer to later shuffle the variables down to lower
914 m->variable_count = m->uses_slots;
919 for(p=params->list;p;p=p->next) {
920 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
925 methodstate_list_t*l = m->innerfunctions;
927 methodstate_t*m = l->methodstate;
929 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
930 m->var_index = v->index;
931 m->slot_index = v->index;
932 v->is_inner_method = m;
938 m->scope_code = add_scope_code(m->scope_code, m, 0);
941 if(as3_pass==2 && m->slots) {
942 /* exchange unresolved identifiers with the actual objects */
943 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
944 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
945 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
946 if(!type || type->kind != INFOTYPE_CLASS) {
947 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
956 char*as3_globalclass=0;
957 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
960 syntaxerror("inner classes now allowed");
965 classinfo_list_t*mlist=0;
967 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
968 syntaxerror("invalid modifier(s)");
970 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
971 syntaxerror("public and internal not supported at the same time.");
973 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
974 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
975 // all classes extend object
976 extends = registry_getobjectclass();
979 /* create the class name, together with the proper attributes */
983 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
984 access = ACCESS_PRIVATE; package = internal_filename_package;
985 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
986 access = ACCESS_PACKAGEINTERNAL; package = state->package;
987 } else if(state->package!=internal_filename_package) {
988 access = ACCESS_PACKAGE; package = state->package;
990 syntaxerror("public classes only allowed inside a package");
994 state->cls = rfx_calloc(sizeof(classstate_t));
995 state->cls->init = rfx_calloc(sizeof(methodstate_t));
996 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
997 state->cls->static_init->variable_count=1;
998 /* notice: we make no effort to initialize the top variable (local0) here,
999 even though it has special meaning. We just rely on the facat
1000 that pass 1 won't do anything with variables */
1002 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1004 /* set current method to constructor- all code within the class-level (except
1005 static variable initializations) will be executed during construction time */
1006 state->method = state->cls->init;
1008 if(registry_find(package, classname)) {
1009 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1011 /* build info struct */
1012 int num_interfaces = (list_length(implements));
1013 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1014 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1017 classinfo_list_t*l = implements;
1018 for(l=implements;l;l=l->next) {
1019 state->cls->info->interfaces[pos++] = l->classinfo;
1024 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1026 state->method = state->cls->init;
1027 parserassert(state->cls && state->cls->info);
1029 function_initvars(state->cls->init, 0, 0, 1);
1030 function_initvars(state->cls->static_init, 0, 0, 0);
1032 if(extends && (extends->flags & FLAG_FINAL))
1033 syntaxerror("Can't extend final class '%s'", extends->name);
1036 while(state->cls->info->interfaces[pos]) {
1037 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1038 syntaxerror("'%s' is not an interface",
1039 state->cls->info->interfaces[pos]->name);
1043 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
1044 state->cls->info->superclass = extends;
1046 /* generate the abc code for this class */
1047 MULTINAME(classname2,state->cls->info);
1048 multiname_t*extends2 = sig2mname(extends);
1050 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
1051 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1052 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1053 if(state->cls->info->flags&FLAG_INTERFACE) {
1054 abc_class_interface(state->cls->abc);
1057 abc_class_protectedNS(state->cls->abc, classname);
1059 for(mlist=implements;mlist;mlist=mlist->next) {
1060 MULTINAME(m, mlist->classinfo);
1061 abc_class_add_interface(state->cls->abc, &m);
1064 /* write the construction code for this class to the global init
1066 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
1068 abc_method_body_t*m = global->init->method->body;
1069 __ getglobalscope(m);
1070 classinfo_t*s = extends;
1075 //TODO: take a look at the current scope stack, maybe
1076 // we can re-use something
1081 multiname_t*s2 = sig2mname(s);
1083 multiname_destroy(s2);
1085 __ pushscope(m); count++;
1086 m->code = m->code->prev->prev; // invert
1088 /* continue appending after last op end */
1089 while(m->code && m->code->next) m->code = m->code->next;
1091 /* TODO: if this is one of *our* classes, we can also
1092 do a getglobalscope/getslot <nr> (which references
1093 the init function's slots) */
1095 __ getlex2(m, extends2);
1097 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
1098 stack is not the superclass */
1099 __ pushscope(m);count++;
1102 /* notice: we get a verify error #1107 if the top element on the scope
1103 stack is not the global object */
1105 __ pushscope(m);count++;
1107 __ newclass(m,state->cls->abc);
1111 __ setslot(m, slotindex);
1112 multiname_destroy(extends2);
1114 /* flash.display.MovieClip handling */
1116 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1117 if(state->package && state->package[0]) {
1118 as3_globalclass = concat3(state->package, ".", classname);
1120 as3_globalclass = strdup(classname);
1126 static void endclass()
1129 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1131 c = abc_getlocal_0(c);
1132 c = abc_constructsuper(c, 0);
1133 state->cls->init->header = code_append(state->cls->init->header, c);
1134 state->cls->has_constructor=1;
1136 if(state->cls->init) {
1137 if(state->cls->info->flags&FLAG_INTERFACE) {
1138 if(state->cls->init->header)
1139 syntaxerror("interface can not have class-level code");
1141 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1142 code_t*c = method_header(state->cls->init);
1143 m->body->code = wrap_function(c, 0, m->body->code);
1146 if(state->cls->static_init) {
1147 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1148 code_t*c = method_header(state->cls->static_init);
1149 m->body->code = wrap_function(c, 0, m->body->code);
1156 void check_code_for_break(code_t*c)
1159 if(c->opcode == OPCODE___BREAK__) {
1160 char*name = string_cstr(c->data[0]);
1161 syntaxerror("Unresolved \"break %s\"", name);
1163 if(c->opcode == OPCODE___CONTINUE__) {
1164 char*name = string_cstr(c->data[0]);
1165 syntaxerror("Unresolved \"continue %s\"", name);
1167 if(c->opcode == OPCODE___RETHROW__) {
1168 syntaxerror("Unresolved \"rethrow\"");
1170 if(c->opcode == OPCODE___FALLTHROUGH__) {
1171 syntaxerror("Unresolved \"fallthrough\"");
1173 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1174 char*name = string_cstr(c->data[0]);
1175 syntaxerror("Can't reference a package (%s) as such", name);
1181 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1183 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1184 if(TYPE_IS_NUMBER(t)) {
1185 xassert(c->type == CONSTANT_FLOAT
1186 || c->type == CONSTANT_INT
1187 || c->type == CONSTANT_UINT);
1188 } else if(TYPE_IS_UINT(t)) {
1189 xassert(c->type == CONSTANT_UINT ||
1190 (c->type == CONSTANT_INT && c->i>=0));
1191 } else if(TYPE_IS_INT(t)) {
1192 xassert(c->type == CONSTANT_INT);
1193 } else if(TYPE_IS_BOOLEAN(t)) {
1194 xassert(c->type == CONSTANT_TRUE
1195 || c->type == CONSTANT_FALSE);
1199 static void check_override(memberinfo_t*m, int flags)
1203 if(m->parent == state->cls->info)
1204 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1206 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1207 if(m->access==ACCESS_PRIVATE)
1209 if(m->flags & FLAG_FINAL)
1210 syntaxerror("can't override final member %s", m->name);
1212 /* allow this. it's no issue.
1213 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1214 syntaxerror("can't override static member %s", m->name);*/
1216 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1217 syntaxerror("can't override non-static member %s with static declaration", m->name);
1219 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1220 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1221 if(m->kind == INFOTYPE_METHOD)
1222 syntaxerror("can't override without explicit 'override' declaration");
1224 syntaxerror("can't override '%s'", m->name);
1229 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1231 methodinfo_t*minfo = 0;
1232 namespace_t ns = modifiers2access(mod);
1235 minfo = methodinfo_register_global(ns.access, state->package, name);
1236 minfo->return_type = 0; // save this for pass 2
1237 } else if(getset != KW_GET && getset != KW_SET) {
1239 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1241 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1243 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1244 minfo->return_type = 0; // save this for pass 2
1245 // getslot on a member slot only returns "undefined", so no need
1246 // to actually store these
1247 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1249 //class getter/setter
1250 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1252 if(getset == KW_GET) {
1254 } else if(params->list && params->list->param && !params->list->next) {
1255 type = params->list->param->type;
1257 syntaxerror("setter function needs to take exactly one argument");
1258 // not sure wether to look into superclasses here, too
1259 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1261 if(minfo->kind!=INFOTYPE_SLOT)
1262 syntaxerror("class already contains a method called '%s'", name);
1263 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1264 syntaxerror("class already contains a field called '%s'", name);
1265 if(minfo->subtype & gs)
1266 syntaxerror("getter/setter for '%s' already defined", name);
1267 /* make a setter or getter into a getset */
1268 minfo->subtype |= gs;
1271 FIXME: this check needs to be done in pass 2
1273 if((!minfo->return_type != !type) ||
1274 (minfo->return_type && type &&
1275 !strcmp(minfo->return_type->name, type->name))) {
1276 syntaxerror("different type in getter and setter: %s and %s",
1277 minfo->return_type?minfo->return_type->name:"*",
1278 type?type->name:"*");
1281 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1282 minfo->kind = INFOTYPE_SLOT; //hack
1283 minfo->subtype = gs;
1284 minfo->return_type = 0;
1286 /* can't assign a slot as getter and setter might have different slots */
1287 //minfo->slot = slot;
1289 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1290 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1291 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1296 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1298 //parserassert(state->method && state->method->info);
1300 methodstate_t*parent_method = state->method;
1303 return_type = 0; // not valid in pass 1
1307 state->new_vars = 1;
1310 state->method = rfx_calloc(sizeof(methodstate_t));
1311 state->method->inner = 1;
1312 state->method->variable_count = 0;
1313 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1315 NEW(methodinfo_t,minfo);
1316 minfo->kind = INFOTYPE_METHOD;
1317 minfo->access = ACCESS_PACKAGEINTERNAL;
1319 state->method->info = minfo;
1322 list_append(parent_method->innerfunctions, state->method);
1324 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1326 function_initvars(state->method, params, 0, 1);
1330 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1331 state->method->variable_count = 0;
1332 parserassert(state->method);
1334 state->method->info->return_type = return_type;
1335 function_initvars(state->method, params, 0, 1);
1339 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1340 params_t*params, classinfo_t*return_type)
1342 if(state->method && state->method->info) {
1343 syntaxerror("not able to start another method scope");
1346 state->new_vars = 1;
1349 state->method = rfx_calloc(sizeof(methodstate_t));
1350 state->method->has_super = 0;
1353 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1355 state->method->is_global = 1;
1356 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1358 if(state->method->is_constructor)
1359 name = "__as3_constructor__";
1361 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1363 function_initvars(state->method, params, mod->flags, 1);
1365 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1369 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1370 state->method->variable_count = 0;
1371 parserassert(state->method);
1374 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1375 check_override(m, mod->flags);
1379 state->cls->has_constructor |= state->method->is_constructor;
1382 state->method->info->return_type = return_type;
1383 function_initvars(state->method, params, mod->flags, 1);
1387 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1388 params_t*params, classinfo_t*return_type, code_t*body)
1391 // store inner methods in variables
1392 function_initvars(state->method, 0, 0, 0);
1394 methodstate_list_t*ml = state->method->innerfunctions;
1396 dict_t*xvars = dict_new();
1399 methodstate_t*m = ml->methodstate;
1400 parserassert(m->inner);
1401 if(m->unresolved_variables) {
1402 dict_t*d = m->unresolved_variables;
1404 for(t=0;t<d->hashsize;t++) {
1405 dictentry_t*l = d->slots[t];
1407 /* check parent method's variables */
1409 if((v=find_variable(state, l->key))) {
1410 m->uses_parent_function = 1;
1411 state->method->uses_slots = 1;
1412 dict_put(xvars, l->key, 0);
1419 dict_destroy(m->unresolved_variables);
1420 m->unresolved_variables = 0;
1425 if(state->method->uses_slots) {
1426 state->method->slots = dict_new();
1428 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1429 if(!name) syntaxerror("internal error");
1430 if(v->index && dict_contains(xvars, name)) {
1433 if(v->is_inner_method) {
1434 v->is_inner_method->is_a_slot = 1;
1437 dict_put(state->method->slots, name, v);
1440 state->method->uses_slots = i;
1441 dict_destroy(state->vars);state->vars = 0;
1448 /*if(state->method->uses_parent_function){
1449 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1454 multiname_t*type2 = sig2mname(return_type);
1456 if(state->method->inner) {
1457 f = state->method->abc;
1458 abc_method_init(f, global->file, type2, 1);
1459 } else if(state->method->is_constructor) {
1460 f = abc_class_getconstructor(state->cls->abc, type2);
1461 } else if(!state->method->is_global) {
1462 namespace_t mname_ns = modifiers2access(mod);
1463 multiname_t mname = {QNAME, &mname_ns, 0, name};
1465 if(mod->flags&FLAG_STATIC)
1466 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1468 f = abc_class_method(state->cls->abc, type2, &mname);
1469 slot = f->trait->slot_id;
1471 namespace_t mname_ns = {state->method->info->access, state->package};
1472 multiname_t mname = {QNAME, &mname_ns, 0, name};
1474 f = abc_method_new(global->file, type2, 1);
1475 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1476 //abc_code_t*c = global->init->method->body->code;
1478 //flash doesn't seem to allow us to access function slots
1479 //state->method->info->slot = slot;
1481 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1482 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1483 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1484 if(params->varargs) f->flags |= METHOD_NEED_REST;
1488 for(p=params->list;p;p=p->next) {
1489 if(params->varargs && !p->next) {
1490 break; //varargs: omit last parameter in function signature
1492 multiname_t*m = sig2mname(p->param->type);
1493 list_append(f->parameters, m);
1494 if(p->param->value) {
1495 check_constant_against_type(p->param->type, p->param->value);
1496 opt=1;list_append(f->optional_parameters, p->param->value);
1498 syntaxerror("non-optional parameter not allowed after optional parameters");
1501 if(state->method->slots) {
1502 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1504 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1505 multiname_t*type = sig2mname(v->type);
1506 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1507 t->slot_id = v->index;
1512 check_code_for_break(body);
1514 /* Seems this works now.
1515 if(state->method->exceptions && state->method->uses_slots) {
1516 as3_warning("try/catch and activation not supported yet within the same method");
1520 f->body->code = body;
1521 f->body->exceptions = state->method->exceptions;
1522 } else { //interface
1524 syntaxerror("interface methods can't have a method body");
1534 void breakjumpsto(code_t*c, char*name, code_t*jump)
1537 if(c->opcode == OPCODE___BREAK__) {
1538 string_t*name2 = c->data[0];
1539 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1540 c->opcode = OPCODE_JUMP;
1547 void continuejumpsto(code_t*c, char*name, code_t*jump)
1550 if(c->opcode == OPCODE___CONTINUE__) {
1551 string_t*name2 = c->data[0];
1552 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1553 c->opcode = OPCODE_JUMP;
1561 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1563 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1568 return abc_coerce_a(c);
1572 // cast an "any" type to a specific type. subject to
1573 // runtime exceptions
1574 return abc_coerce2(c, &m);
1577 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1578 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1579 // allow conversion between number types
1580 if(TYPE_IS_UINT(to))
1581 return abc_convert_u(c);
1582 else if(TYPE_IS_INT(to))
1583 return abc_convert_i(c);
1584 else if(TYPE_IS_NUMBER(to))
1585 return abc_convert_d(c);
1586 return abc_coerce2(c, &m);
1589 if(TYPE_IS_BOOLEAN(to))
1590 return abc_convert_b(c);
1591 if(TYPE_IS_STRING(to))
1592 return abc_convert_s(c);
1593 if(TYPE_IS_OBJECT(to))
1594 return abc_convert_o(c);
1596 classinfo_t*supertype = from;
1598 if(supertype == to) {
1599 // target type is one of from's superclasses
1600 return abc_coerce2(c, &m);
1603 while(supertype->interfaces[t]) {
1604 if(supertype->interfaces[t]==to) {
1605 // target type is one of from's interfaces
1606 return abc_coerce2(c, &m);
1610 supertype = supertype->superclass;
1612 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1614 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1616 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1619 as3_error("can't convert type %s%s%s to %s%s%s",
1620 from->package, from->package[0]?".":"", from->name,
1621 to->package, to->package[0]?".":"", to->name);
1625 /* move to ast.c todo end */
1627 char is_pushundefined(code_t*c)
1629 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1632 static const char* get_package_from_name(const char*name)
1634 /* try explicit imports */
1635 dictentry_t* e = dict_get_slot(state->imports, name);
1637 if(!strcmp(e->key, name)) {
1638 slotinfo_t*c = (slotinfo_t*)e->data;
1639 if(c) return c->package;
1645 static namespace_list_t*get_current_imports()
1647 namespace_list_t*searchlist = 0;
1649 list_append(searchlist, namespace_new_package(state->package));
1651 import_list_t*l = state->wildcard_imports;
1653 namespace_t*ns = namespace_new_package(l->import->package);
1654 list_append(searchlist, ns);
1657 list_append(searchlist, namespace_new_package(""));
1658 list_append(searchlist, namespace_new_package(internal_filename_package));
1662 static slotinfo_t* find_class(const char*name)
1666 c = registry_find(state->package, name);
1669 /* try explicit imports */
1670 dictentry_t* e = dict_get_slot(state->imports, name);
1673 if(!strcmp(e->key, name)) {
1674 c = (slotinfo_t*)e->data;
1680 /* try package.* imports */
1681 import_list_t*l = state->wildcard_imports;
1683 //printf("does package %s contain a class %s?\n", l->import->package, name);
1684 c = registry_find(l->import->package, name);
1689 /* try global package */
1690 c = registry_find("", name);
1693 /* try local "filename" package */
1694 c = registry_find(internal_filename_package, name);
1699 typedcode_t push_class(slotinfo_t*a)
1704 if(a->access == ACCESS_PACKAGEINTERNAL &&
1705 strcmp(a->package, state->package) &&
1706 strcmp(a->package, internal_filename_package)
1708 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1709 infotypename(a), a->name, a->package, state->package);
1712 if(a->kind != INFOTYPE_CLASS) {
1714 x.c = abc_findpropstrict2(x.c, &m);
1715 x.c = abc_getproperty2(x.c, &m);
1716 if(a->kind == INFOTYPE_METHOD) {
1717 methodinfo_t*f = (methodinfo_t*)a;
1718 x.t = TYPE_FUNCTION(f);
1720 varinfo_t*v = (varinfo_t*)a;
1724 classinfo_t*c = (classinfo_t*)a;
1726 x.c = abc_getglobalscope(x.c);
1727 x.c = abc_getslot(x.c, c->slot);
1730 x.c = abc_getlex2(x.c, &m);
1732 x.t = TYPE_CLASS(c);
1738 char is_break_or_jump(code_t*c)
1742 if(c->opcode == OPCODE_JUMP ||
1743 c->opcode == OPCODE___BREAK__ ||
1744 c->opcode == OPCODE___CONTINUE__ ||
1745 c->opcode == OPCODE_THROW ||
1746 c->opcode == OPCODE_RETURNVOID ||
1747 c->opcode == OPCODE_RETURNVALUE) {
1753 #define IS_FINALLY_TARGET(op) \
1754 ((op) == OPCODE___CONTINUE__ || \
1755 (op) == OPCODE___BREAK__ || \
1756 (op) == OPCODE_RETURNVOID || \
1757 (op) == OPCODE_RETURNVALUE || \
1758 (op) == OPCODE___RETHROW__)
1760 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1762 #define NEED_EXTRA_STACK_ARG
1763 code_t*finally_label = abc_nop(0);
1764 NEW(lookupswitch_t, l);
1770 code_t*prev = i->prev;
1771 if(IS_FINALLY_TARGET(i->opcode)) {
1774 if(i->opcode == OPCODE___RETHROW__ ||
1775 i->opcode == OPCODE_RETURNVALUE) {
1776 if(i->opcode == OPCODE___RETHROW__)
1777 i->opcode = OPCODE_THROW;
1779 p = abc_coerce_a(p);
1780 p = abc_setlocal(p, tempvar);
1782 p = abc_pushbyte(p, count++);
1783 p = abc_jump(p, finally_label);
1784 code_t*target = p = abc_label(p);
1785 #ifdef NEED_EXTRA_STACK_ARG
1789 p = abc_getlocal(p, tempvar);
1792 p->next = i;i->prev = p;
1793 list_append(l->targets, target);
1799 c = abc_pushbyte(c, -1);
1800 c = code_append(c, finally_label);
1801 c = code_append(c, finally);
1803 #ifdef NEED_EXTRA_STACK_ARG
1806 c = abc_lookupswitch(c, l);
1807 c = l->def = abc_label(c);
1808 #ifdef NEED_EXTRA_STACK_ARG
1815 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1819 code_t*prev = i->prev;
1820 if(IS_FINALLY_TARGET(i->opcode)) {
1821 if(i->opcode == OPCODE___RETHROW__)
1822 i->opcode = OPCODE_THROW;
1823 code_t*end = code_dup(finally);
1824 code_t*start = code_start(end);
1825 if(prev) prev->next = start;
1832 return code_append(c, finally);
1835 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1841 int num_insertion_points=0;
1843 if(IS_FINALLY_TARGET(i->opcode))
1844 num_insertion_points++;
1851 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1856 int simple_version_cost = (1+num_insertion_points)*code_size;
1857 int lookup_version_cost = 4*num_insertion_points + 5;
1859 if(cantdup || simple_version_cost > lookup_version_cost) {
1860 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1861 return insert_finally_lookup(c, finally, tempvar);
1863 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1864 return insert_finally_simple(c, finally, tempvar);
1868 #define PASS1 }} if(as3_pass == 1) {{
1869 #define PASS1END }} if(as3_pass == 2) {{
1870 #define PASS2 }} if(as3_pass == 2) {{
1871 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1872 #define PASS12END }} if(as3_pass == 2) {{
1873 #define PASS_ALWAYS }} {{
1879 /* ------------ code blocks / statements ---------------- */
1881 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1883 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1884 PROGRAM_CODE_LIST: PROGRAM_CODE
1885 | PROGRAM_CODE_LIST PROGRAM_CODE
1887 PROGRAM_CODE: PACKAGE_DECLARATION
1888 | INTERFACE_DECLARATION
1890 | FUNCTION_DECLARATION
1893 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1896 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1897 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1898 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1900 INPACKAGE_CODE: INTERFACE_DECLARATION
1902 | FUNCTION_DECLARATION
1905 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1908 MAYBECODE: CODE {$$=$1;}
1909 MAYBECODE: {$$=code_new();}
1911 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1912 CODE: CODEPIECE {$$=$1;}
1914 // code which may appear outside of methods
1915 CODE_STATEMENT: IMPORT
1917 CODE_STATEMENT: FOR_IN
1918 CODE_STATEMENT: WHILE
1919 CODE_STATEMENT: DO_WHILE
1920 CODE_STATEMENT: SWITCH
1922 CODE_STATEMENT: WITH
1924 CODE_STATEMENT: VOIDEXPRESSION
1925 CODE_STATEMENT: USE_NAMESPACE
1926 CODE_STATEMENT: NAMESPACE_DECLARATION
1927 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1928 CODE_STATEMENT: '{' '}' {$$=0;}
1930 // code which may appear in methods
1931 CODEPIECE: ';' {$$=0;}
1932 CODEPIECE: CODE_STATEMENT
1933 CODEPIECE: VARIABLE_DECLARATION
1938 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {PASS_ALWAYS as3_pass=$1;}
1940 //CODEBLOCK : '{' CODE '}' {$$=$2;}
1941 //CODEBLOCK : '{' '}' {$$=0;}
1942 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1943 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1945 /* ------------ package init code ------------------- */
1947 PACKAGE_INITCODE: CODE_STATEMENT {
1948 code_t**cc = &global->init->method->body->code;
1949 *cc = code_append(*cc, $1);
1952 /* ------------ conditional compilation ------------- */
1954 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
1957 char*key = concat3($1,"::",$3);
1958 if(!definitions || !dict_contains(definitions, key)) {
1964 /* ------------ variables --------------------------- */
1967 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1973 MAYBEEXPRESSION : '=' E {$$=$2;}
1974 | {$$=mkdummynode();}
1976 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1977 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1979 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1980 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1982 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1985 if(variable_exists($1))
1986 syntaxerror("Variable %s already defined", $1);
1988 new_variable($1, 0, 1, 0);
1993 if(state->method->uses_slots) {
1994 variable_t* v = find_slot(state, $1);
1996 // this variable is stored in a slot
2004 index = new_variable($1, $2, 1, 0);
2007 $$ = slot?abc_getscopeobject(0, 1):0;
2009 typedcode_t v = node_read($3);
2010 if(!is_subtype_of(v.t, $2)) {
2011 syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
2014 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2015 $$ = code_append($$, v.c);
2016 $$ = converttype($$, v.t, $2);
2019 $$ = defaultvalue($$, $2);
2022 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2023 $$ = code_append($$, v.c);
2024 $$ = abc_coerce_a($$);
2026 // don't do anything
2034 $$ = abc_setslot($$, index);
2036 $$ = abc_setlocal($$, index);
2040 /* ------------ control flow ------------------------- */
2042 MAYBEELSE: %prec below_else {$$ = code_new();}
2043 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2044 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2046 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2049 $$ = code_append($$, $4.c);
2050 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2052 $$ = code_append($$, $6);
2054 myjmp = $$ = abc_jump($$, 0);
2056 myif->branch = $$ = abc_nop($$);
2058 $$ = code_append($$, $7);
2059 myjmp->branch = $$ = abc_nop($$);
2065 FOR_INIT : {$$=code_new();}
2066 FOR_INIT : VARIABLE_DECLARATION
2067 FOR_INIT : VOIDEXPRESSION
2069 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2070 // (I don't see any easy way to revolve this conflict otherwise, as we
2071 // can't touch VAR_READ without upsetting the precedence about "return")
2072 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2073 PASS1 $$=$2;new_variable($2,0,1,0);
2074 PASS2 $$=$2;new_variable($2,$3,1,0);
2076 FOR_IN_INIT : T_IDENTIFIER {
2081 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2082 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2084 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2085 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2087 $$ = code_append($$, $2);
2088 code_t*loopstart = $$ = abc_label($$);
2089 $$ = code_append($$, $4.c);
2090 code_t*myif = $$ = abc_iffalse($$, 0);
2091 $$ = code_append($$, $8);
2092 code_t*cont = $$ = abc_nop($$);
2093 $$ = code_append($$, $6);
2094 $$ = abc_jump($$, loopstart);
2095 code_t*out = $$ = abc_nop($$);
2096 breakjumpsto($$, $1.name, out);
2097 continuejumpsto($$, $1.name, cont);
2104 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2105 variable_t*var = find_variable(state, $2);
2107 syntaxerror("variable %s not known in this scope", $2);
2110 char*tmp1name = concat2($2, "__tmp1__");
2111 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2112 char*tmp2name = concat2($2, "__array__");
2113 int array = new_variable(tmp1name, 0, 0, 0);
2116 $$ = code_append($$, $4.c);
2117 $$ = abc_coerce_a($$);
2118 $$ = abc_setlocal($$, array);
2119 $$ = abc_pushbyte($$, 0);
2120 $$ = abc_setlocal($$, it);
2122 code_t*loopstart = $$ = abc_label($$);
2124 $$ = abc_hasnext2($$, array, it);
2125 code_t*myif = $$ = abc_iffalse($$, 0);
2126 $$ = abc_getlocal($$, array);
2127 $$ = abc_getlocal($$, it);
2129 $$ = abc_nextname($$);
2131 $$ = abc_nextvalue($$);
2132 $$ = converttype($$, 0, var->type);
2133 $$ = abc_setlocal($$, var->index);
2135 $$ = code_append($$, $6);
2136 $$ = abc_jump($$, loopstart);
2138 code_t*out = $$ = abc_nop($$);
2139 breakjumpsto($$, $1.name, out);
2140 continuejumpsto($$, $1.name, loopstart);
2152 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2156 code_t*myjmp = $$ = abc_jump($$, 0);
2157 code_t*loopstart = $$ = abc_label($$);
2158 $$ = code_append($$, $6);
2159 code_t*cont = $$ = abc_nop($$);
2160 myjmp->branch = cont;
2161 $$ = code_append($$, $4.c);
2162 $$ = abc_iftrue($$, loopstart);
2163 code_t*out = $$ = abc_nop($$);
2164 breakjumpsto($$, $1, out);
2165 continuejumpsto($$, $1, cont);
2171 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2173 code_t*loopstart = $$ = abc_label($$);
2174 $$ = code_append($$, $3);
2175 code_t*cont = $$ = abc_nop($$);
2176 $$ = code_append($$, $6.c);
2177 $$ = abc_iftrue($$, loopstart);
2178 code_t*out = $$ = abc_nop($$);
2179 breakjumpsto($$, $1, out);
2180 continuejumpsto($$, $1, cont);
2186 BREAK : "break" %prec prec_none {
2187 $$ = abc___break__(0, "");
2189 BREAK : "break" T_IDENTIFIER {
2190 $$ = abc___break__(0, $2);
2192 CONTINUE : "continue" %prec prec_none {
2193 $$ = abc___continue__(0, "");
2195 CONTINUE : "continue" T_IDENTIFIER {
2196 $$ = abc___continue__(0, $2);
2199 MAYBE_CASE_LIST : {$$=0;}
2200 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2201 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2202 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2203 CASE_LIST: CASE {$$=$1;}
2204 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2206 CASE: "case" E ':' MAYBECODE {
2207 $$ = abc_getlocal(0, state->switch_var);
2208 $$ = code_append($$, node_read($2).c);
2209 code_t*j = $$ = abc_ifne($$, 0);
2210 $$ = code_append($$, $4);
2211 if($$->opcode != OPCODE___BREAK__) {
2212 $$ = abc___fallthrough__($$, "");
2214 code_t*e = $$ = abc_nop($$);
2217 DEFAULT: "default" ':' MAYBECODE {
2220 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2221 $$ = node_read($4).c;
2222 $$ = abc_setlocal($$, state->switch_var);
2223 $$ = code_append($$, $7);
2225 code_t*out = $$ = abc_kill($$, state->switch_var);
2226 breakjumpsto($$, $1, out);
2228 code_t*c = $$,*lastblock=0;
2230 if(c->opcode == OPCODE_IFNE) {
2231 if(!c->next) syntaxerror("internal error in fallthrough handling");
2233 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2235 c->opcode = OPCODE_JUMP;
2236 c->branch = lastblock;
2238 /* fall through end of switch */
2239 c->opcode = OPCODE_NOP;
2249 /* ------------ try / catch /finally ---------------- */
2251 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2252 state->exception_name=$3;
2253 PASS1 new_variable($3, 0, 0, 0);
2254 PASS2 new_variable($3, $4, 0, 0);
2257 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2258 multiname_t name = {QNAME, &name_ns, 0, $3};
2260 NEW(abc_exception_t, e)
2261 e->exc_type = sig2mname($4);
2262 e->var_name = multiname_clone(&name);
2266 int i = find_variable_safe(state, $3)->index;
2267 e->target = c = abc_nop(0);
2268 c = abc_setlocal(c, i);
2269 c = code_append(c, code_dup(state->method->scope_code));
2270 c = code_append(c, $8);
2276 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2281 NEW(abc_exception_t, e)
2282 e->exc_type = 0; //all exceptions
2283 e->var_name = 0; //no name
2286 e->to = code_append(e->to, $4);
2292 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2293 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2294 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2295 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2299 list_append($$.l,$2);
2300 $$.finally = $2->to;$2->to=0;
2303 CATCH_FINALLY_LIST: FINALLY {
2307 list_append($$.l,$1);
2308 $$.finally = $1->to;$1->to=0;
2312 TRY : "try" '{' {PASS12 new_state();
2313 state->method->has_exceptions=1;
2314 state->method->late_binding=1;//for invariant scope_code
2315 } MAYBECODE '}' CATCH_FINALLY_LIST {
2316 code_t*out = abc_nop(0);
2318 code_t*start = abc_nop(0);
2319 $$ = code_append(start, $4);
2320 if(!is_break_or_jump($4)) {
2321 $$ = abc_jump($$, out);
2323 code_t*end = $$ = abc_nop($$);
2327 tmp = new_variable("__finally__", 0, 0, 0);
2329 abc_exception_list_t*l = $6.l;
2332 abc_exception_t*e = l->abc_exception;
2334 $$ = code_append($$, e->target);
2335 $$ = abc_jump($$, out);
2337 parserassert((ptroff_t)$6.finally);
2339 e->target = $$ = abc_nop($$);
2340 $$ = code_append($$, code_dup(state->method->scope_code));
2341 $$ = abc___rethrow__($$);
2349 $$ = code_append($$, out);
2351 $$ = insert_finally($$, $6.finally, tmp);
2353 list_concat(state->method->exceptions, $6.l);
2359 /* ------------ throw ------------------------------- */
2361 THROW : "throw" EXPRESSION {
2365 THROW : "throw" %prec prec_none {
2366 if(!state->exception_name)
2367 syntaxerror("re-throw only possible within a catch block");
2368 variable_t*v = find_variable(state, state->exception_name);
2370 $$=abc_getlocal($$, v->index);
2374 /* ------------ with -------------------------------- */
2376 WITH_HEAD : "with" '(' EXPRESSION ')' {
2378 if(state->method->has_exceptions) {
2379 int v = alloc_local();
2380 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2381 state->method->scope_code = abc_pushwith(state->method->scope_code);
2386 WITH : WITH_HEAD CODEBLOCK {
2387 /* remove getlocal;pushwith from scope code again */
2388 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2391 if(state->method->has_exceptions) {
2393 $$ = abc_setlocal($$, $1.number);
2395 $$ = abc_pushwith($$);
2396 $$ = code_append($$, $2);
2397 $$ = abc_popscope($$);
2401 /* ------------ packages and imports ---------------- */
2403 X_IDENTIFIER: T_IDENTIFIER
2404 | "package" {PASS12 $$="package";}
2405 | T_NAMESPACE {PASS12 $$=$1;}
2407 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2408 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2410 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2411 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2412 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2413 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2416 static void state_has_imports()
2418 state->wildcard_imports = list_clone(state->wildcard_imports);
2419 state->imports = dict_clone(state->imports);
2420 state->has_own_imports = 1;
2422 static void import_toplevel(const char*package)
2424 char* s = strdup(package);
2426 dict_put(state->import_toplevel_packages, s, 0);
2427 char*x = strrchr(s, '.');
2435 IMPORT : "import" PACKAGEANDCLASS {
2437 slotinfo_t*s = registry_find($2->package, $2->name);
2438 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2439 as3_schedule_class($2->package, $2->name);
2443 syntaxerror("Couldn't import class\n");
2444 state_has_imports();
2445 dict_put(state->imports, c->name, c);
2446 import_toplevel(c->package);
2449 IMPORT : "import" PACKAGE '.' '*' {
2451 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2452 as3_schedule_package($2);
2457 state_has_imports();
2458 list_append(state->wildcard_imports, i);
2459 import_toplevel(i->package);
2463 /* ------------ classes and interfaces (header) -------------- */
2465 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2466 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2467 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2468 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2470 $$.flags=$1.flags|$2.flags;
2471 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2472 $$.ns=$1.ns?$1.ns:$2.ns;
2475 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2476 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2477 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2478 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2479 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2480 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2481 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2482 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2483 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2484 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2488 EXTENDS : {PASS12 $$=0;}
2489 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2491 EXTENDS_LIST : {PASS12 $$=list_new();}
2492 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2494 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2495 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2497 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2498 EXTENDS IMPLEMENTS_LIST
2499 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2501 '}' {PASS12 endclass();$$=0;}
2503 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2505 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2506 startclass(&$1,$3,0,$4);}
2507 MAYBE_INTERFACE_BODY
2508 '}' {PASS12 endclass();$$=0;}
2510 /* ------------ classes and interfaces (body) -------------- */
2513 MAYBE_CLASS_BODY : CLASS_BODY
2514 CLASS_BODY : CLASS_BODY_ITEM
2515 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2516 CLASS_BODY_ITEM : ';'
2517 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2518 CLASS_BODY_ITEM : SLOT_DECLARATION
2519 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2521 CLASS_BODY_ITEM : CODE_STATEMENT {
2522 code_t*c = state->cls->static_init->header;
2523 c = code_append(c, $1);
2524 state->cls->static_init->header = c;
2527 MAYBE_INTERFACE_BODY :
2528 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2529 INTERFACE_BODY : IDECLARATION
2530 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2532 IDECLARATION : "var" T_IDENTIFIER {
2533 syntaxerror("variable declarations not allowed in interfaces");
2535 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2537 $1.flags |= FLAG_PUBLIC;
2538 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2539 syntaxerror("invalid method modifiers: interface methods always need to be public");
2541 startfunction(&$1,$3,$4,&$6,$8);
2542 endfunction(&$1,$3,$4,&$6,$8, 0);
2543 list_deep_free($6.list);
2546 /* ------------ classes and interfaces (body, slots ) ------- */
2549 static int slotstate_varconst = 0;
2550 static modifiers_t*slotstate_flags = 0;
2551 static void setslotstate(modifiers_t* flags, int varconst)
2553 slotstate_varconst = varconst;
2554 slotstate_flags = flags;
2556 if(flags && flags->flags&FLAG_STATIC) {
2557 state->method = state->cls->static_init;
2559 state->method = state->cls->init;
2562 parserassert(state->method);
2567 VARCONST: "var" | "const"
2569 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2571 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2572 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2574 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2577 int flags = slotstate_flags->flags;
2578 namespace_t ns = modifiers2access(slotstate_flags);
2582 varinfo_t* info = 0;
2584 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2586 check_override(i, flags);
2588 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2590 slotinfo_t*i = registry_find(state->package, $1);
2592 syntaxerror("package %s already contains '%s'", state->package, $1);
2594 if(ns.name && ns.name[0]) {
2595 syntaxerror("namespaces not allowed on package-level variables");
2597 info = varinfo_register_global(ns.access, state->package, $1);
2601 info->flags = flags;
2603 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2607 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2610 multiname_t mname = {QNAME, &ns, 0, $1};
2612 trait_list_t**traits;
2616 ns.name = state->package;
2617 traits = &global->init->traits;
2618 code = &global->init->method->body->code;
2619 } else if(flags&FLAG_STATIC) {
2621 traits = &state->cls->abc->static_traits;
2622 code = &state->cls->static_init->header;
2624 // instance variable
2625 traits = &state->cls->abc->traits;
2626 code = &state->cls->init->header;
2632 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2634 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2636 info->slot = t->slot_id;
2638 constant_t cval = $3->type->eval($3);
2639 if(cval.type!=CONSTANT_UNKNOWN) {
2640 /* compile time constant */
2641 t->value = malloc(sizeof(constant_t));
2642 memcpy(t->value, &cval, sizeof(constant_t));
2644 typedcode_t v = node_read($3);
2645 /* initalization code (if needed) */
2647 if(v.c && !is_pushundefined(v.c)) {
2648 c = abc_getlocal_0(c);
2649 c = code_append(c, v.c);
2650 c = converttype(c, v.t, $2);
2651 c = abc_setslot(c, t->slot_id);
2653 *code = code_append(*code, c);
2656 if(slotstate_varconst==KW_CONST) {
2657 t->kind= TRAIT_CONST;
2664 /* ------------ constants -------------------------------------- */
2666 MAYBECONSTANT: {$$=0;}
2667 MAYBECONSTANT: '=' CONSTANT {$$=$2;}
2669 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2670 CONSTANT : T_INT {$$ = constant_new_int($1);}
2672 $$ = constant_new_uint($1);
2674 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2675 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2676 CONSTANT : "true" {$$ = constant_new_true($1);}
2677 CONSTANT : "false" {$$ = constant_new_false($1);}
2678 CONSTANT : "null" {$$ = constant_new_null($1);}
2679 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2680 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2683 CONSTANT : T_IDENTIFIER {
2684 if(!strcmp($1, "NaN")) {
2685 $$ = constant_new_float(__builtin_nan(""));
2687 as3_warning("Couldn't evaluate constant value of %s", $1);
2688 $$ = constant_new_null($1);
2692 /* ------------ classes and interfaces (body, functions) ------- */
2694 // non-vararg version
2697 memset(&$$,0,sizeof($$));
2699 MAYBE_PARAM_LIST: PARAM_LIST {
2705 MAYBE_PARAM_LIST: "..." PARAM {
2707 memset(&$$,0,sizeof($$));
2709 list_append($$.list, $2);
2711 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2715 list_append($$.list, $4);
2719 PARAM_LIST: PARAM_LIST ',' PARAM {
2722 list_append($$.list, $3);
2726 memset(&$$,0,sizeof($$));
2727 list_append($$.list, $1);
2730 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2732 $$ = rfx_calloc(sizeof(param_t));
2738 PARAM: T_IDENTIFIER MAYBECONSTANT {
2740 $$ = rfx_calloc(sizeof(param_t));
2742 $$->type = TYPE_ANY;
2750 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2751 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2754 endfunction(&$1,$3,$4,&$6,0,0);
2756 if(!state->method->info) syntaxerror("internal error");
2758 code_t*c = method_header(state->method);
2759 c = wrap_function(c, 0, $11);
2761 endfunction(&$1,$3,$4,&$6,$8,c);
2763 list_deep_free($6.list);
2767 MAYBE_IDENTIFIER: T_IDENTIFIER
2768 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2769 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2770 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2773 endfunction(0,0,$2,&$4,0,0);
2775 methodinfo_t*f = state->method->info;
2776 if(!f || !f->kind) syntaxerror("internal error");
2778 code_t*c = method_header(state->method);
2779 c = wrap_function(c, 0, $9);
2781 int index = state->method->var_index;
2782 endfunction(0,0,$2,&$4,$6,c);
2784 $$.c = abc_getlocal(0, index);
2785 $$.t = TYPE_FUNCTION(f);
2787 PASS12 list_deep_free($4.list);
2791 /* ------------- package + class ids --------------- */
2793 CLASS: X_IDENTIFIER {
2794 PASS1 NEW(unresolvedinfo_t,c);
2795 memset(c, 0, sizeof(*c));
2796 c->kind = INFOTYPE_UNRESOLVED;
2798 c->package = get_package_from_name($1);
2800 c->nsset = get_current_imports();
2801 /* make the compiler look for this class in the current directory,
2803 as3_schedule_class_noerror(state->package, $1);
2805 $$ = (classinfo_t*)c;
2807 slotinfo_t*s = find_class($1);
2808 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2809 $$ = (classinfo_t*)s;
2812 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2813 PASS1 NEW(unresolvedinfo_t,c);
2814 memset(c, 0, sizeof(*c));
2815 c->kind = INFOTYPE_UNRESOLVED;
2818 $$ = (classinfo_t*)c;
2820 slotinfo_t*s = registry_find($1, $3);
2821 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2823 $$ = (classinfo_t*)s;
2826 CLASS_SPEC: PACKAGEANDCLASS
2829 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2830 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2832 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2833 | '*' {PASS12 $$=TYPE_ANY;}
2834 | "void" {PASS12 $$=TYPE_ANY;}
2836 | "String" {$$=registry_getstringclass();}
2837 | "int" {$$=registry_getintclass();}
2838 | "uint" {$$=registry_getuintclass();}
2839 | "Boolean" {$$=registry_getbooleanclass();}
2840 | "Number" {$$=registry_getnumberclass();}
2843 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2844 MAYBETYPE: {PASS12 $$=0;}
2846 /* ----------function calls, delete, constructor calls ------ */
2848 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
2849 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2851 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
2852 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2853 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2855 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
2859 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
2860 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
2861 $$.number= $1.number+1;
2862 $$.cc = code_append($1.cc, $2.c);
2866 NEW : "new" E XX MAYBE_PARAM_VALUES {
2867 typedcode_t v = node_read($2);
2869 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2871 code_t*paramcode = $4.cc;
2872 if($$.c->opcode == OPCODE_GETPROPERTY) {
2873 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2874 $$.c = code_cutlast($$.c);
2875 $$.c = code_append($$.c, paramcode);
2876 $$.c = abc_constructprop2($$.c, name, $4.number);
2877 multiname_destroy(name);
2878 } else if($$.c->opcode == OPCODE_GETSLOT) {
2879 int slot = (int)(ptroff_t)$$.c->data[0];
2880 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
2881 multiname_t*name = t->name;
2882 $$.c = code_cutlast($$.c);
2883 $$.c = code_append($$.c, paramcode);
2884 $$.c = abc_constructprop2($$.c, name, $4.number);
2886 $$.c = code_append($$.c, paramcode);
2887 $$.c = abc_construct($$.c, $4.number);
2891 if(TYPE_IS_CLASS(v.t) && v.t->data) {
2894 $$.c = abc_coerce_a($$.c);
2899 /* TODO: use abc_call (for calling local variables),
2900 abc_callstatic (for calling own methods)
2903 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2905 typedcode_t v = node_read($1);
2907 if($$.c->opcode == OPCODE_COERCE_A) {
2908 $$.c = code_cutlast($$.c);
2910 code_t*paramcode = $3.cc;
2913 if($$.c->opcode == OPCODE_GETPROPERTY) {
2914 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2915 $$.c = code_cutlast($$.c);
2916 $$.c = code_append($$.c, paramcode);
2917 $$.c = abc_callproperty2($$.c, name, $3.number);
2918 multiname_destroy(name);
2919 } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
2920 int slot = (int)(ptroff_t)$$.c->data[0];
2921 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
2922 if(t->kind!=TRAIT_METHOD) {
2923 //ok: flash allows to assign closures to members.
2925 multiname_t*name = t->name;
2926 $$.c = code_cutlast($$.c);
2927 $$.c = code_append($$.c, paramcode);
2928 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2929 $$.c = abc_callproperty2($$.c, name, $3.number);
2930 } else if($$.c->opcode == OPCODE_GETSUPER) {
2931 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2932 $$.c = code_cutlast($$.c);
2933 $$.c = code_append($$.c, paramcode);
2934 $$.c = abc_callsuper2($$.c, name, $3.number);
2935 multiname_destroy(name);
2937 $$.c = abc_getglobalscope($$.c);
2938 $$.c = code_append($$.c, paramcode);
2939 $$.c = abc_call($$.c, $3.number);
2942 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
2943 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
2945 $$.c = abc_coerce_a($$.c);
2950 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2951 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2952 if(!state->method) syntaxerror("super() not allowed outside of a function");
2953 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2956 $$.c = abc_getlocal_0($$.c);
2958 $$.c = code_append($$.c, $3.cc);
2960 this is dependent on the control path, check this somewhere else
2961 if(state->method->has_super)
2962 syntaxerror("constructor may call super() only once");
2964 state->method->has_super = 1;
2966 $$.c = abc_constructsuper($$.c, $3.number);
2967 $$.c = abc_pushundefined($$.c);
2971 DELETE: "delete" E {
2972 typedcode_t v = node_read($2);
2974 if($$.c->opcode == OPCODE_COERCE_A) {
2975 $$.c = code_cutlast($$.c);
2977 multiname_t*name = 0;
2978 if($$.c->opcode == OPCODE_GETPROPERTY) {
2979 $$.c->opcode = OPCODE_DELETEPROPERTY;
2980 } else if($$.c->opcode == OPCODE_GETSLOT) {
2981 int slot = (int)(ptroff_t)$$.c->data[0];
2982 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
2983 $$.c = code_cutlast($$.c);
2984 $$.c = abc_deleteproperty2($$.c, name);
2986 $$.c = abc_getlocal_0($$.c);
2987 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
2988 $$.c = abc_deleteproperty2($$.c, &m);
2990 $$.t = TYPE_BOOLEAN;
2993 RETURN: "return" %prec prec_none {
2994 $$ = abc_returnvoid(0);
2996 RETURN: "return" EXPRESSION {
2998 $$ = abc_returnvalue($$);
3001 // ----------------------- expression types -------------------------------------
3003 NONCOMMAEXPRESSION : E %prec below_minus {
3006 EXPRESSION : COMMA_EXPRESSION {
3009 COMMA_EXPRESSION : E %prec below_minus {
3010 $$ = mkmultinode(&node_comma, $1);
3012 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_minus {
3013 $$ = multinode_extend($1, $3);
3015 VOIDEXPRESSION : E %prec below_minus {
3018 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_minus {
3020 $$ = code_append($$, node_exec($3));
3023 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3024 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
3026 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3028 $$.cc = code_append($$.cc, $1.c);
3029 $$.cc = code_append($$.cc, $3.c);
3032 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3034 $$.number = $1.number+2;
3035 $$.cc = code_append($$.cc, $3.c);
3036 $$.cc = code_append($$.cc, $5.c);
3039 // ----------------------- expression evaluation -------------------------------------
3041 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3042 E : VAR_READ %prec T_IDENTIFIER {$$ = mkcodenode($1);}
3043 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3044 E : NEW {$$ = mkcodenode($1);}
3045 E : DELETE {$$ = mkcodenode($1);}
3046 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3049 $$ = mkconstnode($1);
3056 namespace_t ns = {ACCESS_PACKAGE, ""};
3057 multiname_t m = {QNAME, &ns, 0, "RegExp"};
3059 v.c = abc_getlex2(v.c, &m);
3060 v.c = abc_pushstring(v.c, $1.pattern);
3061 v.c = abc_construct(v.c, 1);
3063 v.c = abc_getlex2(v.c, &m);
3064 v.c = abc_pushstring(v.c, $1.pattern);
3065 v.c = abc_pushstring(v.c, $1.options);
3066 v.c = abc_construct(v.c, 2);
3073 E : '[' MAYBE_EXPRESSION_LIST ']' {
3076 v.c = code_append(v.c, $2.cc);
3077 v.c = abc_newarray(v.c, $2.number);
3078 v.t = registry_getarrayclass();
3083 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
3086 v.c = code_append(v.c, $2.cc);
3087 v.c = abc_newobject(v.c, $2.number/2);
3088 v.t = registry_getobjectclass();
3092 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3093 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3094 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3095 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3096 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3097 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3098 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3099 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3100 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3101 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3102 E : '!' E {$$ = mknode1(&node_not, $2);}
3103 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3104 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3105 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3106 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3107 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3108 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3109 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3110 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3111 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3112 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3113 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3114 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3115 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3116 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3117 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3118 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3119 E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
3120 E : "void" E {$$ = mknode1(&node_void, $2);}
3121 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3122 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3123 E : '-' E {$$ = mknode1(&node_neg, $2);}
3124 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3125 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3126 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3127 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3128 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3129 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3130 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3131 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3132 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3133 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3134 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3135 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3136 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3137 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3139 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3140 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3141 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3142 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3144 E : "super" '.' T_IDENTIFIER
3145 { if(!state->cls->info)
3146 syntaxerror("super keyword not allowed outside a class");
3147 classinfo_t*t = state->cls->info->superclass;
3148 if(!t) t = TYPE_OBJECT;
3149 memberinfo_t*f = findmember_nsset(t, $3, 1);
3150 MEMBER_MULTINAME(m, f, $3);
3153 v.c = abc_getlocal_0(v.c);
3154 v.c = abc_getsuper2(v.c, &m);
3155 v.t = slotinfo_gettype((slotinfo_t*)f);
3159 E : '@' T_IDENTIFIER {
3162 as3_warning("ignored @ operator");
3165 E : E '.' '@' T_IDENTIFIER {
3166 // child attribute TODO
3168 as3_warning("ignored .@ operator");
3171 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3172 // namespace declaration TODO
3174 as3_warning("ignored :: operator");
3177 E : E ".." T_IDENTIFIER {
3180 as3_warning("ignored .. operator");
3183 E : E '.' '(' E ')' {
3186 as3_warning("ignored .() operator");
3189 //E : E "::" '[' E ']' {
3190 // // qualified expression TODO
3191 // $$.c = abc_pushundefined(0);
3193 // as3_warning("ignored ::[] operator");
3196 MEMBER : E '.' T_IDENTIFIER {
3197 typedcode_t v1 = node_read($1);
3199 classinfo_t*t = v1.t;
3201 if(TYPE_IS_CLASS(t) && t->data) {
3206 if(t->subtype==INFOTYPE_UNRESOLVED) {
3207 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3209 memberinfo_t*f = findmember_nsset(t, $3, 1);
3211 if(f && !is_static != !(f->flags&FLAG_STATIC))
3213 if(f && f->slot && !noslot) {
3214 $$.c = abc_getslot($$.c, f->slot);
3217 as3_warning("Access of undefined property '%s' in %s", $3, t->name);
3220 MEMBER_MULTINAME(m, f, $3);
3221 $$.c = abc_getproperty2($$.c, &m);
3223 /* determine type */
3224 $$.t = slotinfo_gettype((slotinfo_t*)f);
3226 $$.c = abc_coerce_a($$.c);
3227 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3228 string_t*package = v1.c->data[0];
3229 char*package2 = concat3(package->str, ".", $3);
3231 slotinfo_t*a = registry_find(package->str, $3);
3234 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3235 registry_ispackage(package2)) {
3237 $$.c->data[0] = string_new4(package2);
3240 syntaxerror("couldn't resolve %s", package2);
3243 /* when resolving a property on an unknown type, we do know the
3244 name of the property (and don't seem to need the package), but
3245 we need to make avm2 try out all access modes */
3246 as3_warning("Resolving %s on unknown type", $3);
3247 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3248 $$.c = abc_getproperty2($$.c, &m);
3249 $$.c = abc_coerce_a($$.c);
3254 VAR_READ : T_IDENTIFIER {
3256 /* Queue unresolved identifiers for checking against the parent
3257 function's variables.
3258 We consider everything which is not a local variable "unresolved".
3259 This encompasses class names, members of the surrounding class
3260 etc. which is *correct* because local variables of the parent function
3263 if(state->method->inner && !find_variable(state, $1)) {
3264 unknown_variable($1);
3267 /* let the compiler know that it might want to check the current directory/package
3268 for this identifier- maybe there's a file $1.as defining $1. */
3269 as3_schedule_class_noerror(state->package, $1);
3278 /* look at variables */
3279 if((v = find_variable(state, $1))) {
3280 // $1 is a local variable
3281 $$.c = abc_getlocal($$.c, v->index);
3285 if((v = find_slot(state, $1))) {
3286 $$.c = abc_getscopeobject($$.c, 1);
3287 $$.c = abc_getslot($$.c, v->index);
3292 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3294 /* look at current class' members */
3295 if(!state->method->inner &&
3297 (f = findmember_nsset(state->cls->info, $1, 1)) &&
3298 (f->flags&FLAG_STATIC) >= i_am_static)
3300 // $1 is a function in this class
3301 int var_is_static = (f->flags&FLAG_STATIC);
3303 if(f->kind == INFOTYPE_METHOD) {
3304 $$.t = TYPE_FUNCTION(f);
3308 if(var_is_static && !i_am_static) {
3309 /* access to a static member from a non-static location.
3310 do this via findpropstrict:
3311 there doesn't seem to be any non-lookup way to access
3312 static properties of a class */
3313 state->method->late_binding = 1;
3315 namespace_t ns = {f->access, f->package};
3316 multiname_t m = {QNAME, &ns, 0, $1};
3317 $$.c = abc_findpropstrict2($$.c, &m);
3318 $$.c = abc_getproperty2($$.c, &m);
3320 } else if(f->slot>0) {
3321 $$.c = abc_getlocal_0($$.c);
3322 $$.c = abc_getslot($$.c, f->slot);
3325 namespace_t ns = {f->access, f->package};
3326 multiname_t m = {QNAME, &ns, 0, $1};
3327 $$.c = abc_getlocal_0($$.c);
3328 $$.c = abc_getproperty2($$.c, &m);
3333 /* look at actual classes, in the current package and imported */
3334 if((a = find_class($1))) {
3339 /* look through package prefixes */
3340 if(dict_contains(state->import_toplevel_packages, $1) ||
3341 registry_ispackage($1)) {
3342 $$.c = abc___pushpackage__($$.c, $1);
3347 /* unknown object, let the avm2 resolve it */
3349 //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3350 as3_warning("Couldn't resolve '%s', doing late binding", $1);
3351 state->method->late_binding = 1;
3353 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3356 $$.c = abc_findpropstrict2($$.c, &m);
3357 $$.c = abc_getproperty2($$.c, &m);
3361 // ----------------- namespaces -------------------------------------------------
3363 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3365 NEW(namespace_decl_t,n);
3370 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3372 NEW(namespace_decl_t,n);
3377 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3379 NEW(namespace_decl_t,n);
3384 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3386 trie_put(active_namespaces, $2->name, (void*)$2->url);
3388 namespace_t access = modifiers2access(&$1);
3389 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3390 var->type = TYPE_NAMESPACE;
3392 ns.access = ACCESS_NAMESPACE;
3394 var->value = constant_new_namespace(&ns);
3400 void add_active_url(const char*url)
3404 list_append(state->active_namespace_urls, n);
3408 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3410 const char*url = $3->name;
3412 varinfo_t*s = (varinfo_t*)$3;
3413 if(s->kind == INFOTYPE_UNRESOLVED) {
3414 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3416 syntaxerror("Couldn't resolve namespace %s", $3->name);
3419 if(!s || s->kind != INFOTYPE_SLOT)
3420 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3421 if(!s->value || !NS_TYPE(s->value->type))
3422 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3423 url = s->value->ns->name;
3425 trie_put(active_namespaces, $3->name, (void*)url);
3426 add_active_url(url);