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 */
30 #include "tokenizer.h"
45 enum yytokentype token;
47 classinfo_t*classinfo;
48 classinfo_list_t*classinfo_list;
50 slotinfo_list_t*slotinfo_list;
53 unsigned int number_uint;
57 //typedcode_list_t*value_list;
58 codeandnumber_t value_list;
64 for_start_t for_start;
65 abc_exception_t *exception;
68 namespace_decl_t* namespace_decl;
70 abc_exception_list_t *l;
76 %token<id> T_IDENTIFIER T_NAMESPACE
78 %token<regexp> T_REGEXP
80 %token<number_int> T_INT
81 %token<number_uint> T_UINT
82 %token<number_uint> T_BYTE
83 %token<number_uint> T_SHORT
84 %token<number_float> T_FLOAT
86 %token<id> T_FOR "for"
87 %token<id> T_WHILE "while"
89 %token<id> T_SWITCH "switch"
91 %token<token> KW_IMPLEMENTS "implements"
92 %token<token> KW_NAMESPACE "namespace"
93 %token<token> KW_PACKAGE "package"
94 %token<token> KW_PROTECTED "protected"
95 %token<token> KW_PUBLIC "public"
96 %token<token> KW_PRIVATE "private"
97 %token<token> KW_USE "use"
98 %token<token> KW_INTERNAL "internal"
99 %token<token> KW_NEW "new"
100 %token<token> KW_NATIVE "native"
101 %token<token> KW_FUNCTION "function"
102 %token<token> KW_FINALLY "finally"
103 %token<token> KW_UNDEFINED "undefined"
104 %token<token> KW_CONTINUE "continue"
105 %token<token> KW_CLASS "class"
106 %token<token> KW_CONST "const"
107 %token<token> KW_CATCH "catch"
108 %token<token> KW_CASE "case"
109 %token<token> KW_SET "set"
110 %token<token> KW_VOID "void"
111 %token<token> KW_THROW "throw"
112 %token<token> KW_STATIC "static"
113 %token<token> KW_WITH "with"
114 %token<token> KW_INSTANCEOF "instanceof"
115 %token<token> KW_IMPORT "import"
116 %token<token> KW_RETURN "return"
117 %token<token> KW_TYPEOF "typeof"
118 %token<token> KW_INTERFACE "interface"
119 %token<token> KW_NULL "null"
120 %token<token> KW_VAR "var"
121 %token<token> KW_DYNAMIC "dynamic"
122 %token<token> KW_OVERRIDE "override"
123 %token<token> KW_FINAL "final"
124 %token<token> KW_EACH "each"
125 %token<token> KW_GET "get"
126 %token<token> KW_TRY "try"
127 %token<token> KW_SUPER "super"
128 %token<token> KW_EXTENDS "extends"
129 %token<token> KW_FALSE "false"
130 %token<token> KW_TRUE "true"
131 %token<token> KW_BOOLEAN "Boolean"
132 %token<token> KW_UINT "uint"
133 %token<token> KW_INT "int"
134 %token<token> KW_NUMBER "Number"
135 %token<token> KW_STRING "String"
136 %token<token> KW_DEFAULT "default"
137 %token<token> KW_DELETE "delete"
138 %token<token> KW_IF "if"
139 %token<token> KW_ELSE "else"
140 %token<token> KW_BREAK "break"
141 %token<token> KW_IS "is"
142 %token<token> KW_IN "in"
143 %token<token> KW_AS "as"
145 %token<token> T_DICTSTART "{ (dictionary)"
146 %token<token> T_EQEQ "=="
147 %token<token> T_EQEQEQ "==="
148 %token<token> T_NE "!="
149 %token<token> T_NEE "!=="
150 %token<token> T_LE "<="
151 %token<token> T_GE ">="
152 %token<token> T_ORBY "|="
153 %token<token> T_DIVBY "/="
154 %token<token> T_MODBY "%="
155 %token<token> T_MULBY "*="
156 %token<token> T_PLUSBY "+="
157 %token<token> T_MINUSBY "-="
158 %token<token> T_XORBY "^="
159 %token<token> T_SHRBY ">>="
160 %token<token> T_SHLBY "<<="
161 %token<token> T_USHRBY ">>>="
162 %token<token> T_OROR "||"
163 %token<token> T_ANDAND "&&"
164 %token<token> T_COLONCOLON "::"
165 %token<token> T_MINUSMINUS "--"
166 %token<token> T_PLUSPLUS "++"
167 %token<token> T_DOTDOT ".."
168 %token<token> T_DOTDOTDOT "..."
169 %token<token> T_SHL "<<"
170 %token<token> T_USHR ">>>"
171 %token<token> T_SHR ">>"
173 %type <for_start> FOR_START
174 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
175 %type <namespace_decl> NAMESPACE_ID
176 %type <token> VARCONST
178 %type <code> CODEPIECE CODE_STATEMENT
179 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
180 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
181 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
182 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
183 %type <exception> CATCH FINALLY
184 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
185 %type <code> CLASS_DECLARATION
186 %type <code> NAMESPACE_DECLARATION
187 %type <code> INTERFACE_DECLARATION
188 %type <code> VOIDEXPRESSION
189 %type <value> EXPRESSION NONCOMMAEXPRESSION
190 %type <value> MAYBEEXPRESSION
191 %type <value> E DELETE
192 %type <value> CONSTANT
193 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
194 %type <value> INNERFUNCTION
195 %type <code> USE_NAMESPACE
196 %type <code> FOR_INIT
198 %type <classinfo> MAYBETYPE
201 %type <params> PARAM_LIST
202 %type <params> MAYBE_PARAM_LIST
203 %type <flags> MAYBE_MODIFIERS
204 %type <flags> MODIFIER_LIST
205 %type <flags> MODIFIER
206 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
207 %type <classinfo_list> IMPLEMENTS_LIST
208 %type <classinfo> EXTENDS CLASS_SPEC
209 %type <classinfo_list> EXTENDS_LIST
211 %type <classinfo> CLASS PACKAGEANDCLASS
212 %type <classinfo_list> CLASS_SPEC_LIST
214 %type <classinfo> TYPE
215 //%type <token> VARIABLE
216 %type <value> VAR_READ
218 //%type <token> T_IDENTIFIER
219 %type <value> FUNCTIONCALL
220 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST WITH_HEAD
222 // precedence: from low to high
226 %left below_semicolon
229 %nonassoc below_assignment // for ?:, contrary to spec
230 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
237 %nonassoc "==" "!=" "===" "!=="
238 %nonassoc "is" "as" "in"
239 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
240 %left "<<" ">>" ">>>"
244 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
246 %nonassoc below_curly
250 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
253 %left above_identifier
257 // needed for "return" precedence:
258 %nonassoc T_STRING T_REGEXP
259 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
260 %nonassoc "false" "true" "null" "undefined" "super" "function"
267 static int a3_error(char*s)
269 syntaxerror("%s", s);
270 return 0; //make gcc happy
274 static char* concat2(const char* t1, const char* t2)
278 char*text = malloc(l1+l2+1);
279 memcpy(text , t1, l1);
280 memcpy(text+l1, t2, l2);
284 static char* concat3(const char* t1, const char* t2, const char* t3)
289 char*text = malloc(l1+l2+l3+1);
290 memcpy(text , t1, l1);
291 memcpy(text+l1, t2, l2);
292 memcpy(text+l1+l2, t3, l3);
297 typedef struct _import {
301 DECLARE_LIST(import);
303 DECLARE(methodstate);
304 DECLARE_LIST(methodstate);
306 typedef struct _classstate {
312 methodstate_t*static_init;
314 //code_t*static_init;
316 char has_constructor;
319 struct _methodstate {
329 dict_t*unresolved_variables;
332 char uses_parent_function;
338 int var_index; // for inner methods
339 int slot_index; // for inner methods
340 char is_a_slot; // for inner methods
345 abc_exception_list_t*exceptions;
347 methodstate_list_t*innerfunctions;
350 typedef struct _state {
355 import_list_t*wildcard_imports;
356 dict_t*import_toplevel_packages;
359 namespace_list_t*active_namespace_urls;
361 char has_own_imports;
362 char new_vars; // e.g. transition between two functions
365 methodstate_t*method;
374 typedef struct _global {
378 dict_t*file2token2info;
381 static global_t*global = 0;
382 static state_t* state = 0;
386 #define MULTINAME(m,x) \
390 registry_fill_multiname(&m, &m##_ns, (slotinfo_t*)(x));
392 #define MEMBER_MULTINAME(m,f,n) \
396 if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
397 m##_ns.name = ((slotinfo_t*)(f))->package; \
402 m.namespace_set = 0; \
403 m.name = ((slotinfo_t*)(f))->name; \
405 m.type = MULTINAME; \
407 m.namespace_set = &nopackage_namespace_set; \
411 /* warning: list length of namespace set is undefined */
412 #define MULTINAME_LATE(m, access, package) \
413 namespace_t m##_ns = {access, package}; \
414 namespace_set_t m##_nsset; \
415 namespace_list_t m##_l;m##_l.next = 0; \
416 m##_nsset.namespaces = &m##_l; \
417 m##_nsset = m##_nsset; \
418 m##_l.namespace = &m##_ns; \
419 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
421 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
422 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
423 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
424 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
425 static namespace_list_t nl4 = {&ns4,0};
426 static namespace_list_t nl3 = {&ns3,&nl4};
427 static namespace_list_t nl2 = {&ns2,&nl3};
428 static namespace_list_t nl1 = {&ns1,&nl2};
429 static namespace_set_t nopackage_namespace_set = {&nl1};
431 static void new_state()
434 state_t*oldstate = state;
436 memcpy(s, state, sizeof(state_t)); //shallow copy
438 s->imports = dict_new();
440 if(!s->import_toplevel_packages) {
441 s->import_toplevel_packages = dict_new();
445 state->has_own_imports = 0;
446 state->vars = dict_new();
447 state->old = oldstate;
450 trie_remember(active_namespaces);
453 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
455 static void state_has_imports()
457 state->wildcard_imports = list_clone(state->wildcard_imports);
458 state->imports = dict_clone(state->imports);
459 state->has_own_imports = 1;
461 static void import_toplevel(const char*package)
463 char* s = strdup(package);
465 dict_put(state->import_toplevel_packages, s, 0);
466 char*x = strrchr(s, '.');
474 static void state_destroy(state_t*state)
476 if(state->has_own_imports) {
477 list_free(state->wildcard_imports);
478 dict_destroy(state->imports);state->imports=0;
480 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
481 dict_destroy(state->imports);state->imports=0;
485 for(t=0;t<state->vars->hashsize;t++) {
486 dictentry_t*e =state->vars->slots[t];
488 free(e->data);e->data=0;
492 dict_destroy(state->vars);state->vars=0;
495 list_free(state->active_namespace_urls)
496 state->active_namespace_urls = 0;
501 static void old_state()
503 trie_rollback(active_namespaces);
505 if(!state || !state->old)
506 syntaxerror("invalid nesting");
507 state_t*leaving = state;
511 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
512 free(leaving->method);
515 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
520 state_destroy(leaving);
523 static code_t* method_header(methodstate_t*m);
524 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
525 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
528 static char* internal_filename_package = 0;
529 void initialize_file(char*filename)
532 syntaxerror("invalid call to initialize_file during parsing of another file");
535 active_namespaces = trie_new();
538 state->package = internal_filename_package = strdup(filename);
540 global->token2info = dict_lookup(global->file2token2info,
541 current_filename // use long version
543 if(!global->token2info) {
544 global->token2info = dict_new2(&ptr_type);
545 dict_put(global->file2token2info, current_filename, global->token2info);
549 state->method = rfx_calloc(sizeof(methodstate_t));
550 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
551 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
553 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
554 function_initvars(state->method, 0, 0, 1);
555 global->init = abc_initscript(global->file);
561 if(!state || state->level!=1) {
562 syntaxerror("unexpected end of file in pass %d", as3_pass);
566 code_t*header = method_header(state->method);
567 code_t*c = wrap_function(header, 0, global->init->method->body->code);
568 global->init->method->body->code = c;
569 free(state->method);state->method=0;
572 //free(state->package);state->package=0; // used in registry
573 state_destroy(state);state=0;
576 void initialize_parser()
578 global = rfx_calloc(sizeof(global_t));
579 global->file = abc_file_new();
580 global->file->flags &= ~ABCFILE_LAZY;
581 global->file2token2info = dict_new();
582 global->token2info = 0;
585 void* finish_parser()
587 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
589 global->token2info=0;
595 static void xx_scopetest()
597 /* findpropstrict doesn't just return a scope object- it
598 also makes it "active" somehow. Push local_0 on the
599 scope stack and read it back with findpropstrict, it'll
600 contain properties like "trace". Trying to find the same
601 property on a "vanilla" local_0 yields only a "undefined" */
602 //c = abc_findpropstrict(c, "[package]::trace");
604 /*c = abc_getlocal_0(c);
605 c = abc_findpropstrict(c, "[package]::trace");
607 c = abc_setlocal_1(c);
609 c = abc_pushbyte(c, 0);
610 c = abc_setlocal_2(c);
612 code_t*xx = c = abc_label(c);
613 c = abc_findpropstrict(c, "[package]::trace");
614 c = abc_pushstring(c, "prop:");
615 c = abc_hasnext2(c, 1, 2);
617 c = abc_setlocal_3(c);
618 c = abc_callpropvoid(c, "[package]::trace", 2);
619 c = abc_getlocal_3(c);
621 c = abc_iftrue(c,xx);*/
624 typedef struct _variable {
628 methodstate_t*is_inner_method;
631 static variable_t* find_variable(state_t*s, char*name)
635 v = dict_lookup(s->vars, name);
637 if(s->new_vars) break;
642 static variable_t* find_slot(state_t*s, const char*name)
644 if(s->method && s->method->slots)
645 return dict_lookup(s->method->slots, name);
649 static variable_t* find_variable_safe(state_t*s, char*name)
651 variable_t* v = find_variable(s, name);
653 syntaxerror("undefined variable: %s", name);
656 static char variable_exists(char*name)
658 return dict_contains(state->vars, name);
660 code_t*defaultvalue(code_t*c, classinfo_t*type);
662 static int alloc_local()
664 return state->method->variable_count++;
667 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
670 variable_t*v = find_slot(state, name);
676 v->index = alloc_local();
681 dict_put(state->vars, name, v);
685 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
687 return new_variable2(name, type, init, maybeslot)->index;
690 #define TEMPVARNAME "__as3_temp__"
691 static int gettempvar()
693 variable_t*v = find_variable(state, TEMPVARNAME);
696 return new_variable(TEMPVARNAME, 0, 0, 0);
699 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 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 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
753 static void parsererror(const char*file, int line, const char*f)
755 syntaxerror("internal error in %s, %s:%d", f, file, line);
759 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
761 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
762 c = abc_getlocal_0(c);
763 c = abc_pushscope(c);
766 /* FIXME: this alloc_local() causes variable indexes to be
767 different in pass2 than in pass1 */
768 if(!m->activation_var)
769 m->activation_var = alloc_local();
771 c = abc_newactivation(c);
773 c = abc_pushscope(c);
774 c = abc_setlocal(c, m->activation_var);
776 c = abc_getlocal(c, m->activation_var);
777 c = abc_pushscope(c);
783 static code_t* method_header(methodstate_t*m)
787 c = add_scope_code(c, m, 1);
789 methodstate_list_t*l = m->innerfunctions;
791 parserassert(l->methodstate->abc);
792 if(m->uses_slots && l->methodstate->is_a_slot) {
793 c = abc_getscopeobject(c, 1);
794 c = abc_newfunction(c, l->methodstate->abc);
796 c = abc_setlocal(c, l->methodstate->var_index);
797 c = abc_setslot(c, l->methodstate->slot_index);
799 c = abc_newfunction(c, l->methodstate->abc);
800 c = abc_setlocal(c, l->methodstate->var_index);
802 free(l->methodstate);l->methodstate=0;
806 c = code_append(c, m->header);
809 if(m->is_constructor && !m->has_super) {
810 // call default constructor
811 c = abc_getlocal_0(c);
812 c = abc_constructsuper(c, 0);
814 list_free(m->innerfunctions);
815 m->innerfunctions = 0;
820 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
822 c = code_append(c, header);
823 c = code_append(c, var_block(body));
824 /* append return if necessary */
825 if(!c || (c->opcode != OPCODE_RETURNVOID &&
826 c->opcode != OPCODE_RETURNVALUE)) {
827 c = abc_returnvoid(c);
833 static void startpackage(char*name)
836 /*printf("entering package \"%s\"\n", name);*/
837 state->package = strdup(name);
839 static void endpackage()
841 /*printf("leaving package \"%s\"\n", state->package);*/
843 //used e.g. in classinfo_register:
844 //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 void add_active_url(const char*url)
901 list_append(state->active_namespace_urls, n);
904 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
909 index = new_variable("this", 0, 0, 0);
910 else if(!m->is_global)
911 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
913 index = new_variable("globalscope", 0, 0, 0);
916 parserassert(!index);
920 /* as variables and slots share the same number, make sure
921 that those variable indices are reserved. It's up to the
922 optimizer to later shuffle the variables down to lower
924 m->variable_count = m->uses_slots;
929 for(p=params->list;p;p=p->next) {
930 new_variable(p->param->name, p->param->type, 0, 1);
934 methodstate_list_t*l = m->innerfunctions;
936 methodstate_t*m = l->methodstate;
938 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
939 m->var_index = v->index;
940 m->slot_index = v->index;
941 v->is_inner_method = m;
947 m->scope_code = add_scope_code(m->scope_code, m, 0);
950 if(as3_pass==2 && m->slots) {
951 /* exchange unresolved identifiers with the actual objects */
952 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
953 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
954 v->type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
955 if(!v->type || v->type->kind != INFOTYPE_CLASS) {
956 syntaxerror("Couldn't find class %s", v->type->name);
964 char*as3_globalclass=0;
965 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
968 syntaxerror("inner classes now allowed");
973 classinfo_list_t*mlist=0;
975 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
976 syntaxerror("invalid modifier(s)");
978 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
979 syntaxerror("public and internal not supported at the same time.");
981 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
982 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
983 // all classes extend object
984 extends = registry_getobjectclass();
987 /* create the class name, together with the proper attributes */
991 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
992 access = ACCESS_PRIVATE; package = internal_filename_package;
993 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
994 access = ACCESS_PACKAGEINTERNAL; package = state->package;
995 } else if(state->package!=internal_filename_package) {
996 access = ACCESS_PACKAGE; package = state->package;
998 syntaxerror("public classes only allowed inside a package");
1002 state->cls = rfx_calloc(sizeof(classstate_t));
1003 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1004 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1005 /* notice: we make no effort to initialize the top variable (local0) here,
1006 even though it has special meaning. We just rely on the facat
1007 that pass 1 won't do anything with variables */
1009 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1011 /* set current method to constructor- all code within the class-level (except
1012 static variable initializations) will be executed during construction time */
1013 state->method = state->cls->init;
1015 if(registry_find(package, classname)) {
1016 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1018 /* build info struct */
1019 int num_interfaces = (list_length(implements));
1020 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1021 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1024 classinfo_list_t*l = implements;
1025 for(l=implements;l;l=l->next) {
1026 state->cls->info->interfaces[pos++] = l->classinfo;
1031 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1033 state->method = state->cls->init;
1034 parserassert(state->cls && state->cls->info);
1036 function_initvars(state->cls->init, 0, 0, 1);
1037 function_initvars(state->cls->static_init, 0, 0, 0);
1039 if(extends && (extends->flags & FLAG_FINAL))
1040 syntaxerror("Can't extend final class '%s'", extends->name);
1043 while(state->cls->info->interfaces[pos]) {
1044 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1045 syntaxerror("'%s' is not an interface",
1046 state->cls->info->interfaces[pos]->name);
1050 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
1051 state->cls->info->superclass = extends;
1053 /* generate the abc code for this class */
1054 MULTINAME(classname2,state->cls->info);
1055 multiname_t*extends2 = sig2mname(extends);
1057 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
1058 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1059 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1060 if(state->cls->info->flags&FLAG_INTERFACE) {
1061 abc_class_interface(state->cls->abc);
1064 abc_class_protectedNS(state->cls->abc, classname);
1066 for(mlist=implements;mlist;mlist=mlist->next) {
1067 MULTINAME(m, mlist->classinfo);
1068 abc_class_add_interface(state->cls->abc, &m);
1071 /* write the construction code for this class to the global init
1073 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
1075 abc_method_body_t*m = global->init->method->body;
1076 __ getglobalscope(m);
1077 classinfo_t*s = extends;
1082 //TODO: take a look at the current scope stack, maybe
1083 // we can re-use something
1088 multiname_t*s2 = sig2mname(s);
1090 multiname_destroy(s2);
1092 __ pushscope(m); count++;
1093 m->code = m->code->prev->prev; // invert
1095 /* continue appending after last op end */
1096 while(m->code && m->code->next) m->code = m->code->next;
1098 /* TODO: if this is one of *our* classes, we can also
1099 do a getglobalscope/getslot <nr> (which references
1100 the init function's slots) */
1102 __ getlex2(m, extends2);
1104 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
1105 stack is not the superclass */
1106 __ pushscope(m);count++;
1109 /* notice: we get a verify error #1107 if the top element on the scope
1110 stack is not the global object */
1112 __ pushscope(m);count++;
1114 __ newclass(m,state->cls->abc);
1118 __ setslot(m, slotindex);
1119 multiname_destroy(extends2);
1121 /* flash.display.MovieClip handling */
1123 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1124 if(state->package && state->package[0]) {
1125 as3_globalclass = concat3(state->package, ".", classname);
1127 as3_globalclass = strdup(classname);
1133 static int slotstate_varconst = 0;
1134 static modifiers_t*slotstate_flags = 0;
1135 static void setslotstate(modifiers_t* flags, int varconst)
1137 slotstate_varconst = varconst;
1138 slotstate_flags = flags;
1140 if(flags && flags->flags&FLAG_STATIC) {
1141 state->method = state->cls->static_init;
1143 state->method = state->cls->init;
1146 parserassert(state->method);
1150 static void endclass()
1153 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1155 c = abc_getlocal_0(c);
1156 c = abc_constructsuper(c, 0);
1157 state->cls->init->header = code_append(state->cls->init->header, c);
1158 state->cls->has_constructor=1;
1160 if(state->cls->init) {
1161 if(state->cls->info->flags&FLAG_INTERFACE) {
1162 if(state->cls->init->header)
1163 syntaxerror("interface can not have class-level code");
1165 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1166 code_t*c = method_header(state->cls->init);
1167 m->body->code = wrap_function(c, 0, m->body->code);
1170 if(state->cls->static_init) {
1171 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1172 code_t*c = method_header(state->cls->static_init);
1173 m->body->code = wrap_function(c, 0, m->body->code);
1180 void check_code_for_break(code_t*c)
1183 if(c->opcode == OPCODE___BREAK__) {
1184 char*name = string_cstr(c->data[0]);
1185 syntaxerror("Unresolved \"break %s\"", name);
1187 if(c->opcode == OPCODE___CONTINUE__) {
1188 char*name = string_cstr(c->data[0]);
1189 syntaxerror("Unresolved \"continue %s\"", name);
1191 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1192 char*name = string_cstr(c->data[0]);
1193 syntaxerror("Can't reference a package (%s) as such", name);
1200 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1203 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1204 if(TYPE_IS_NUMBER(t)) {
1205 xassert(c->type == CONSTANT_FLOAT
1206 || c->type == CONSTANT_INT
1207 || c->type == CONSTANT_UINT);
1208 } else if(TYPE_IS_UINT(t)) {
1209 xassert(c->type == CONSTANT_UINT ||
1210 (c->type == CONSTANT_INT && c->i>=0));
1211 } else if(TYPE_IS_INT(t)) {
1212 xassert(c->type == CONSTANT_INT);
1213 } else if(TYPE_IS_BOOLEAN(t)) {
1214 xassert(c->type == CONSTANT_TRUE
1215 || c->type == CONSTANT_FALSE);
1219 static void check_override(memberinfo_t*m, int flags)
1223 if(m->parent == state->cls->info)
1224 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1226 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1227 if(m->access==ACCESS_PRIVATE)
1229 if(m->flags & FLAG_FINAL)
1230 syntaxerror("can't override final member %s", m->name);
1232 /* allow this. it's no issue.
1233 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1234 syntaxerror("can't override static member %s", m->name);*/
1236 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1237 syntaxerror("can't override non-static member %s with static declaration", m->name);
1239 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1240 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1241 if(m->kind == INFOTYPE_METHOD)
1242 syntaxerror("can't override without explicit 'override' declaration");
1244 syntaxerror("can't override '%s'", m->name);
1249 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1251 methodinfo_t*minfo = 0;
1252 namespace_t ns = modifiers2access(mod);
1255 minfo = methodinfo_register_global(ns.access, state->package, name);
1256 minfo->return_type = 0; // save this for pass 2
1257 } else if(getset != KW_GET && getset != KW_SET) {
1259 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1261 printf("%s.%s | %s.%s\n",
1262 m->package, m->name,
1264 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1266 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1267 minfo->return_type = 0; // save this for pass 2
1268 // getslot on a member slot only returns "undefined", so no need
1269 // to actually store these
1270 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1272 //class getter/setter
1273 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1275 if(getset == KW_GET) {
1277 } else if(params->list && params->list->param && !params->list->next) {
1278 type = params->list->param->type;
1280 syntaxerror("setter function needs to take exactly one argument");
1281 // not sure wether to look into superclasses here, too
1282 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1284 if(minfo->kind!=INFOTYPE_SLOT)
1285 syntaxerror("class already contains a method called '%s'", name);
1286 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1287 syntaxerror("class already contains a field called '%s'", name);
1288 if(minfo->subtype & gs)
1289 syntaxerror("getter/setter for '%s' already defined", name);
1290 /* make a setter or getter into a getset */
1291 minfo->subtype |= gs;
1294 FIXME: this check needs to be done in pass 2
1296 if((!minfo->return_type != !type) ||
1297 (minfo->return_type && type &&
1298 !strcmp(minfo->return_type->name, type->name))) {
1299 syntaxerror("different type in getter and setter: %s and %s",
1300 minfo->return_type?minfo->return_type->name:"*",
1301 type?type->name:"*");
1304 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1305 minfo->kind = INFOTYPE_SLOT; //hack
1306 minfo->subtype = gs;
1307 minfo->return_type = 0;
1309 /* can't assign a slot as getter and setter might have different slots */
1310 //minfo->slot = slot;
1312 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1313 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1314 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1319 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1321 //parserassert(state->method && state->method->info);
1323 methodstate_t*parent_method = state->method;
1326 return_type = 0; // not valid in pass 1
1330 state->new_vars = 1;
1333 state->method = rfx_calloc(sizeof(methodstate_t));
1334 state->method->inner = 1;
1335 state->method->variable_count = 0;
1336 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1338 NEW(methodinfo_t,minfo);
1339 minfo->kind = INFOTYPE_METHOD;
1340 minfo->access = ACCESS_PACKAGEINTERNAL;
1342 state->method->info = minfo;
1345 list_append(parent_method->innerfunctions, state->method);
1347 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1349 function_initvars(state->method, params, 0, 1);
1353 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1354 state->method->variable_count = 0;
1355 parserassert(state->method);
1357 state->method->info->return_type = return_type;
1358 function_initvars(state->method, params, 0, 1);
1362 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1363 params_t*params, classinfo_t*return_type)
1365 if(state->method && state->method->info) {
1366 syntaxerror("not able to start another method scope");
1369 state->new_vars = 1;
1372 state->method = rfx_calloc(sizeof(methodstate_t));
1373 state->method->has_super = 0;
1376 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1378 state->method->is_global = 1;
1379 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1381 if(state->method->is_constructor)
1382 name = "__as3_constructor__";
1384 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1386 function_initvars(state->method, params, mod->flags, 1);
1388 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1392 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1393 state->method->variable_count = 0;
1394 parserassert(state->method);
1397 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1398 check_override(m, mod->flags);
1402 state->cls->has_constructor |= state->method->is_constructor;
1405 state->method->info->return_type = return_type;
1406 function_initvars(state->method, params, mod->flags, 1);
1410 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1411 params_t*params, classinfo_t*return_type, code_t*body)
1414 // store inner methods in variables
1415 function_initvars(state->method, 0, 0, 0);
1417 methodstate_list_t*ml = state->method->innerfunctions;
1419 dict_t*xvars = dict_new();
1422 methodstate_t*m = ml->methodstate;
1423 parserassert(m->inner);
1424 if(m->unresolved_variables) {
1425 dict_t*d = m->unresolved_variables;
1427 for(t=0;t<d->hashsize;t++) {
1428 dictentry_t*l = d->slots[t];
1430 /* check parent method's variables */
1432 if((v=find_variable(state, l->key))) {
1433 m->uses_parent_function = 1;
1434 state->method->uses_slots = 1;
1435 dict_put(xvars, l->key, 0);
1442 dict_destroy(m->unresolved_variables);
1443 m->unresolved_variables = 0;
1448 if(state->method->uses_slots) {
1449 state->method->slots = dict_new();
1451 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1452 if(!name) syntaxerror("internal error");
1453 if(v->index && dict_contains(xvars, name)) {
1456 if(v->is_inner_method) {
1457 v->is_inner_method->is_a_slot = 1;
1460 dict_put(state->method->slots, name, v);
1463 state->method->uses_slots = i;
1464 dict_destroy(state->vars);state->vars = 0;
1471 /*if(state->method->uses_parent_function){
1472 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1477 multiname_t*type2 = sig2mname(return_type);
1479 if(state->method->inner) {
1480 f = state->method->abc;
1481 abc_method_init(f, global->file, type2, 1);
1482 } else if(state->method->is_constructor) {
1483 f = abc_class_getconstructor(state->cls->abc, type2);
1484 } else if(!state->method->is_global) {
1485 namespace_t mname_ns = modifiers2access(mod);
1486 multiname_t mname = {QNAME, &mname_ns, 0, name};
1488 if(mod->flags&FLAG_STATIC)
1489 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1491 f = abc_class_method(state->cls->abc, type2, &mname);
1492 slot = f->trait->slot_id;
1494 namespace_t mname_ns = {state->method->info->access, state->package};
1495 multiname_t mname = {QNAME, &mname_ns, 0, name};
1497 f = abc_method_new(global->file, type2, 1);
1498 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1499 //abc_code_t*c = global->init->method->body->code;
1501 //flash doesn't seem to allow us to access function slots
1502 //state->method->info->slot = slot;
1504 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1505 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1506 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1507 if(params->varargs) f->flags |= METHOD_NEED_REST;
1511 for(p=params->list;p;p=p->next) {
1512 if(params->varargs && !p->next) {
1513 break; //varargs: omit last parameter in function signature
1515 multiname_t*m = sig2mname(p->param->type);
1516 list_append(f->parameters, m);
1517 if(p->param->value) {
1518 check_constant_against_type(p->param->type, p->param->value);
1519 opt=1;list_append(f->optional_parameters, p->param->value);
1521 syntaxerror("non-optional parameter not allowed after optional parameters");
1524 if(state->method->slots) {
1525 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1527 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1528 multiname_t*type = sig2mname(v->type);
1529 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1530 t->slot_id = v->index;
1535 check_code_for_break(body);
1537 /* Seems this works now.
1538 if(state->method->exceptions && state->method->uses_slots) {
1539 as3_warning("try/catch and activation not supported yet within the same method");
1543 f->body->code = body;
1544 f->body->exceptions = state->method->exceptions;
1545 } else { //interface
1547 syntaxerror("interface methods can't have a method body");
1557 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1562 void breakjumpsto(code_t*c, char*name, code_t*jump)
1565 if(c->opcode == OPCODE___BREAK__) {
1566 string_t*name2 = c->data[0];
1567 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1568 c->opcode = OPCODE_JUMP;
1575 void continuejumpsto(code_t*c, char*name, code_t*jump)
1578 if(c->opcode == OPCODE___CONTINUE__) {
1579 string_t*name2 = c->data[0];
1580 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1581 c->opcode = OPCODE_JUMP;
1589 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1590 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1591 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1593 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1595 if(!type1 || !type2)
1596 return registry_getanytype();
1597 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1598 return registry_getanytype();
1601 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1610 return registry_getanytype();
1612 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1617 return abc_coerce_a(c);
1621 // cast an "any" type to a specific type. subject to
1622 // runtime exceptions
1623 return abc_coerce2(c, &m);
1626 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1627 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1628 // allow conversion between number types
1629 return abc_coerce2(c, &m);
1631 //printf("%s.%s\n", from.package, from.name);
1632 //printf("%s.%s\n", to.package, to.name);
1634 classinfo_t*supertype = from;
1636 if(supertype == to) {
1637 // target type is one of from's superclasses
1638 return abc_coerce2(c, &m);
1641 while(supertype->interfaces[t]) {
1642 if(supertype->interfaces[t]==to) {
1643 // target type is one of from's interfaces
1644 return abc_coerce2(c, &m);
1648 supertype = supertype->superclass;
1650 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1652 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1654 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1657 as3_error("can't convert type %s%s%s to %s%s%s",
1658 from->package, from->package?".":"", from->name,
1659 to->package, to->package?".":"", to->name);
1663 code_t*defaultvalue(code_t*c, classinfo_t*type)
1665 if(TYPE_IS_INT(type)) {
1666 c = abc_pushbyte(c, 0);
1667 } else if(TYPE_IS_UINT(type)) {
1668 c = abc_pushuint(c, 0);
1669 } else if(TYPE_IS_FLOAT(type)) {
1671 } else if(TYPE_IS_BOOLEAN(type)) {
1672 c = abc_pushfalse(c);
1674 //c = abc_pushundefined(c);
1676 c = abc_pushnull(c);
1678 c = abc_coerce2(c, &m);
1683 char is_pushundefined(code_t*c)
1685 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1688 static const char* get_package_from_name(const char*name)
1690 /* try explicit imports */
1691 dictentry_t* e = dict_get_slot(state->imports, name);
1693 if(!strcmp(e->key, name)) {
1694 slotinfo_t*c = (slotinfo_t*)e->data;
1695 if(c) return c->package;
1701 static namespace_list_t*get_current_imports()
1703 namespace_list_t*searchlist = 0;
1705 list_append(searchlist, namespace_new_package(state->package));
1707 import_list_t*l = state->wildcard_imports;
1709 namespace_t*ns = namespace_new_package(l->import->package);
1710 list_append(searchlist, ns);
1713 list_append(searchlist, namespace_new_package(""));
1714 list_append(searchlist, namespace_new_package(internal_filename_package));
1718 static slotinfo_t* find_class(const char*name)
1722 c = registry_find(state->package, name);
1725 /* try explicit imports */
1726 dictentry_t* e = dict_get_slot(state->imports, name);
1729 if(!strcmp(e->key, name)) {
1730 c = (slotinfo_t*)e->data;
1736 /* try package.* imports */
1737 import_list_t*l = state->wildcard_imports;
1739 //printf("does package %s contain a class %s?\n", l->import->package, name);
1740 c = registry_find(l->import->package, name);
1745 /* try global package */
1746 c = registry_find("", name);
1749 /* try local "filename" package */
1750 c = registry_find(internal_filename_package, name);
1755 typedcode_t push_class(slotinfo_t*a)
1760 if(a->access == ACCESS_PACKAGEINTERNAL &&
1761 strcmp(a->package, state->package) &&
1762 strcmp(a->package, internal_filename_package)
1764 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1765 infotypename(a), a->name, a->package, state->package);
1768 if(a->kind != INFOTYPE_CLASS) {
1770 x.c = abc_findpropstrict2(x.c, &m);
1771 x.c = abc_getproperty2(x.c, &m);
1772 if(a->kind == INFOTYPE_METHOD) {
1773 methodinfo_t*f = (methodinfo_t*)a;
1774 x.t = TYPE_FUNCTION(f);
1776 varinfo_t*v = (varinfo_t*)a;
1780 classinfo_t*c = (classinfo_t*)a;
1782 x.c = abc_getglobalscope(x.c);
1783 x.c = abc_getslot(x.c, c->slot);
1786 x.c = abc_getlex2(x.c, &m);
1788 x.t = TYPE_CLASS(c);
1793 static char is_getlocal(code_t*c)
1795 if(!c || c->prev || c->next)
1797 return(c->opcode == OPCODE_GETLOCAL
1798 || c->opcode == OPCODE_GETLOCAL_0
1799 || c->opcode == OPCODE_GETLOCAL_1
1800 || c->opcode == OPCODE_GETLOCAL_2
1801 || c->opcode == OPCODE_GETLOCAL_3);
1803 static int getlocalnr(code_t*c)
1805 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1806 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1807 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1808 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1809 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1810 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1814 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1818 [prefix code] [read instruction]
1822 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1824 if(in && in->opcode == OPCODE_COERCE_A) {
1825 in = code_cutlast(in);
1828 syntaxerror("internal error");
1830 /* chop off read instruction */
1834 prefix = r->prev;r->prev = 0;
1840 char use_temp_var = readbefore;
1842 /* generate the write instruction, and maybe append a dup to the prefix code */
1843 code_t* write = abc_nop(0);
1844 if(r->opcode == OPCODE_GETPROPERTY) {
1845 write->opcode = OPCODE_SETPROPERTY;
1846 multiname_t*m = (multiname_t*)r->data[0];
1847 write->data[0] = multiname_clone(m);
1848 if(m->type == QNAME || m->type == MULTINAME) {
1850 prefix = abc_dup(prefix); // we need the object, too
1853 } else if(m->type == MULTINAMEL) {
1855 /* dupping two values on the stack requires 5 operations and one register-
1856 couldn't adobe just have given us a dup2? */
1857 int temp = gettempvar();
1858 prefix = abc_setlocal(prefix, temp);
1859 prefix = abc_dup(prefix);
1860 prefix = abc_getlocal(prefix, temp);
1861 prefix = abc_swap(prefix);
1862 prefix = abc_getlocal(prefix, temp);
1864 prefix = abc_kill(prefix, temp);
1868 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1870 } else if(r->opcode == OPCODE_GETSLOT) {
1871 write->opcode = OPCODE_SETSLOT;
1872 write->data[0] = r->data[0];
1874 prefix = abc_dup(prefix); // we need the object, too
1877 } else if(r->opcode == OPCODE_GETLOCAL) {
1878 write->opcode = OPCODE_SETLOCAL;
1879 write->data[0] = r->data[0];
1880 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1881 write->opcode = OPCODE_SETLOCAL_0;
1882 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1883 write->opcode = OPCODE_SETLOCAL_1;
1884 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1885 write->opcode = OPCODE_SETLOCAL_2;
1886 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1887 write->opcode = OPCODE_SETLOCAL_3;
1888 } else if(r->opcode == OPCODE_GETSUPER) {
1889 write->opcode = OPCODE_SETSUPER;
1890 multiname_t*m = (multiname_t*)r->data[0];
1891 write->data[0] = multiname_clone(m);
1894 syntaxerror("illegal lvalue: can't assign a value to this expression");
1901 /* with getproperty/getslot, we have to be extra careful not
1902 to execute the read code twice, as it might have side-effects
1903 (e.g. if the property is in fact a setter/getter combination)
1905 So read the value, modify it, and write it again,
1906 using prefix only once and making sure (by using a temporary
1907 register) that the return value is what we just wrote */
1908 temp = gettempvar();
1909 c = code_append(c, prefix);
1910 c = code_append(c, r);
1913 c = abc_setlocal(c, temp);
1915 c = code_append(c, middlepart);
1918 c = abc_setlocal(c, temp);
1920 c = code_append(c, write);
1921 c = abc_getlocal(c, temp);
1922 c = abc_kill(c, temp);
1924 /* if we're allowed to execute the read code twice *and*
1925 the middlepart doesn't modify the code, things are easier.
1927 code_t* r2 = code_dup(r);
1928 //c = code_append(c, prefix);
1929 parserassert(!prefix);
1930 c = code_append(c, r);
1931 c = code_append(c, middlepart);
1932 c = code_append(c, write);
1933 c = code_append(c, r2);
1936 /* even smaller version: overwrite the value without reading
1940 c = code_append(c, prefix);
1943 c = code_append(c, middlepart);
1944 c = code_append(c, write);
1945 c = code_append(c, r);
1948 temp = gettempvar();
1950 c = code_append(c, prefix);
1952 c = code_append(c, middlepart);
1954 c = abc_setlocal(c, temp);
1955 c = code_append(c, write);
1956 c = abc_getlocal(c, temp);
1957 c = abc_kill(c, temp);
1963 char is_break_or_jump(code_t*c)
1967 if(c->opcode == OPCODE_JUMP ||
1968 c->opcode == OPCODE___BREAK__ ||
1969 c->opcode == OPCODE___CONTINUE__ ||
1970 c->opcode == OPCODE_THROW ||
1971 c->opcode == OPCODE_RETURNVOID ||
1972 c->opcode == OPCODE_RETURNVALUE) {
1978 #define IS_FINALLY_TARGET(op) \
1979 ((op) == OPCODE___CONTINUE__ || \
1980 (op) == OPCODE___BREAK__ || \
1981 (op) == OPCODE_RETURNVOID || \
1982 (op) == OPCODE_RETURNVALUE || \
1983 (op) == OPCODE___RETHROW__)
1985 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1987 #define NEED_EXTRA_STACK_ARG
1988 code_t*finally_label = abc_nop(0);
1989 NEW(lookupswitch_t, l);
1995 code_t*prev = i->prev;
1996 if(IS_FINALLY_TARGET(i->opcode)) {
1999 if(i->opcode == OPCODE___RETHROW__ ||
2000 i->opcode == OPCODE_RETURNVALUE) {
2001 if(i->opcode == OPCODE___RETHROW__)
2002 i->opcode = OPCODE_THROW;
2004 p = abc_coerce_a(p);
2005 p = abc_setlocal(p, tempvar);
2007 p = abc_pushbyte(p, count++);
2008 p = abc_jump(p, finally_label);
2009 code_t*target = p = abc_label(p);
2010 #ifdef NEED_EXTRA_STACK_ARG
2014 p = abc_getlocal(p, tempvar);
2017 p->next = i;i->prev = p;
2018 list_append(l->targets, target);
2024 c = abc_pushbyte(c, -1);
2025 c = code_append(c, finally_label);
2026 c = code_append(c, finally);
2028 #ifdef NEED_EXTRA_STACK_ARG
2031 c = abc_lookupswitch(c, l);
2032 c = l->def = abc_label(c);
2033 #ifdef NEED_EXTRA_STACK_ARG
2040 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
2044 code_t*prev = i->prev;
2045 if(IS_FINALLY_TARGET(i->opcode)) {
2046 if(i->opcode == OPCODE___RETHROW__)
2047 i->opcode = OPCODE_THROW;
2048 code_t*end = code_dup(finally);
2049 code_t*start = code_start(end);
2050 if(prev) prev->next = start;
2057 return code_append(c, finally);
2060 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
2066 int num_insertion_points=0;
2068 if(IS_FINALLY_TARGET(i->opcode))
2069 num_insertion_points++;
2076 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
2081 int simple_version_cost = (1+num_insertion_points)*code_size;
2082 int lookup_version_cost = 4*num_insertion_points + 5;
2084 if(cantdup || simple_version_cost > lookup_version_cost) {
2085 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
2086 return insert_finally_lookup(c, finally, tempvar);
2088 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
2089 return insert_finally_simple(c, finally, tempvar);
2093 #define PASS1 }} if(as3_pass == 1) {{
2094 #define PASS1END }} if(as3_pass == 2) {{
2095 #define PASS2 }} if(as3_pass == 2) {{
2096 #define PASS12 }} {{
2097 #define PASS12END }} if(as3_pass == 2) {{
2103 /* ------------ code blocks / statements ---------------- */
2105 PROGRAM: MAYBE_PROGRAM_CODE_LIST
2107 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
2108 PROGRAM_CODE_LIST: PROGRAM_CODE
2109 | PROGRAM_CODE_LIST PROGRAM_CODE
2111 PROGRAM_CODE: PACKAGE_DECLARATION
2112 | INTERFACE_DECLARATION
2114 | FUNCTION_DECLARATION
2117 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' // conditional compilation
2120 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
2121 INPACKAGE_CODE_LIST: INPACKAGE_CODE
2122 | INPACKAGE_CODE_LIST INPACKAGE_CODE
2124 INPACKAGE_CODE: INTERFACE_DECLARATION
2126 | FUNCTION_DECLARATION
2129 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' // conditional compilation
2132 MAYBECODE: CODE {$$=$1;}
2133 MAYBECODE: {$$=code_new();}
2135 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
2136 CODE: CODEPIECE {$$=$1;}
2138 // code which may appear outside of methods
2139 CODE_STATEMENT: IMPORT
2141 CODE_STATEMENT: FOR_IN
2142 CODE_STATEMENT: WHILE
2143 CODE_STATEMENT: DO_WHILE
2144 CODE_STATEMENT: SWITCH
2146 CODE_STATEMENT: WITH
2148 CODE_STATEMENT: VOIDEXPRESSION
2149 CODE_STATEMENT: USE_NAMESPACE
2150 CODE_STATEMENT: NAMESPACE_DECLARATION
2151 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
2152 CODE_STATEMENT: '{' '}' {$$=0;}
2154 // code which may appear in methods
2155 CODEPIECE: ';' {$$=0;}
2156 CODEPIECE: CODE_STATEMENT
2157 CODEPIECE: VARIABLE_DECLARATION
2162 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
2164 //CODEBLOCK : '{' CODE '}' {$$=$2;}
2165 //CODEBLOCK : '{' '}' {$$=0;}
2166 CODEBLOCK : CODEPIECE ';' {$$=$1;}
2167 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
2169 /* ------------ package init code ------------------- */
2171 PACKAGE_INITCODE: CODE_STATEMENT {
2172 code_t**cc = &global->init->method->body->code;
2173 *cc = code_append(*cc, $1);
2176 /* ------------ conditional compilation ------------- */
2178 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER
2180 /* ------------ variables --------------------------- */
2182 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
2183 | {$$.c=abc_pushundefined(0);
2187 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2188 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2190 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2191 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2193 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2196 if(variable_exists($1))
2197 syntaxerror("Variable %s already defined", $1);
2199 new_variable($1, 0, 1, 0);
2202 if(!is_subtype_of($3.t, $2)) {
2203 syntaxerror("Can't convert %s to %s", $3.t->name,
2209 if(state->method->uses_slots) {
2210 variable_t* v = find_slot(state, $1);
2212 // this variable is stored in a slot
2220 index = new_variable($1, $2, 1, 0);
2223 $$ = slot?abc_getscopeobject(0, 1):0;
2226 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2227 $$ = code_append($$, $3.c);
2228 $$ = converttype($$, $3.t, $2);
2231 $$ = defaultvalue($$, $2);
2234 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2235 $$ = code_append($$, $3.c);
2236 $$ = abc_coerce_a($$);
2238 // don't do anything
2246 $$ = abc_setslot($$, index);
2248 $$ = abc_setlocal($$, index);
2252 /* ------------ control flow ------------------------- */
2254 MAYBEELSE: %prec below_else {$$ = code_new();}
2255 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2256 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2258 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2261 $$ = code_append($$, $4.c);
2262 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2264 $$ = code_append($$, $6);
2266 myjmp = $$ = abc_jump($$, 0);
2268 myif->branch = $$ = abc_nop($$);
2270 $$ = code_append($$, $7);
2271 myjmp->branch = $$ = abc_nop($$);
2277 FOR_INIT : {$$=code_new();}
2278 FOR_INIT : VARIABLE_DECLARATION
2279 FOR_INIT : VOIDEXPRESSION
2281 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2282 // (I don't see any easy way to revolve this conflict otherwise, as we
2283 // can't touch VAR_READ without upsetting the precedence about "return")
2284 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2285 PASS1 $$=$2;new_variable($2,0,1,0);
2286 PASS2 $$=$2;new_variable($2,$3,1,0);
2288 FOR_IN_INIT : T_IDENTIFIER {
2293 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2294 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2296 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2297 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2299 $$ = code_append($$, $2);
2300 code_t*loopstart = $$ = abc_label($$);
2301 $$ = code_append($$, $4.c);
2302 code_t*myif = $$ = abc_iffalse($$, 0);
2303 $$ = code_append($$, $8);
2304 code_t*cont = $$ = abc_nop($$);
2305 $$ = code_append($$, $6);
2306 $$ = abc_jump($$, loopstart);
2307 code_t*out = $$ = abc_nop($$);
2308 breakjumpsto($$, $1.name, out);
2309 continuejumpsto($$, $1.name, cont);
2316 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2317 variable_t*var = find_variable(state, $2);
2319 syntaxerror("variable %s not known in this scope", $2);
2322 char*tmp1name = concat2($2, "__tmp1__");
2323 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2324 char*tmp2name = concat2($2, "__array__");
2325 int array = new_variable(tmp1name, 0, 0, 0);
2328 $$ = code_append($$, $4.c);
2329 $$ = abc_coerce_a($$);
2330 $$ = abc_setlocal($$, array);
2331 $$ = abc_pushbyte($$, 0);
2332 $$ = abc_setlocal($$, it);
2334 code_t*loopstart = $$ = abc_label($$);
2336 $$ = abc_hasnext2($$, array, it);
2337 code_t*myif = $$ = abc_iffalse($$, 0);
2338 $$ = abc_getlocal($$, array);
2339 $$ = abc_getlocal($$, it);
2341 $$ = abc_nextname($$);
2343 $$ = abc_nextvalue($$);
2344 $$ = converttype($$, 0, var->type);
2345 $$ = abc_setlocal($$, var->index);
2347 $$ = code_append($$, $6);
2348 $$ = abc_jump($$, loopstart);
2350 code_t*out = $$ = abc_nop($$);
2351 breakjumpsto($$, $1.name, out);
2352 continuejumpsto($$, $1.name, loopstart);
2364 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2368 code_t*myjmp = $$ = abc_jump($$, 0);
2369 code_t*loopstart = $$ = abc_label($$);
2370 $$ = code_append($$, $6);
2371 code_t*cont = $$ = abc_nop($$);
2372 myjmp->branch = cont;
2373 $$ = code_append($$, $4.c);
2374 $$ = abc_iftrue($$, loopstart);
2375 code_t*out = $$ = abc_nop($$);
2376 breakjumpsto($$, $1, out);
2377 continuejumpsto($$, $1, cont);
2383 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2385 code_t*loopstart = $$ = abc_label($$);
2386 $$ = code_append($$, $3);
2387 code_t*cont = $$ = abc_nop($$);
2388 $$ = code_append($$, $6.c);
2389 $$ = abc_iftrue($$, loopstart);
2390 code_t*out = $$ = abc_nop($$);
2391 breakjumpsto($$, $1, out);
2392 continuejumpsto($$, $1, cont);
2398 BREAK : "break" %prec prec_none {
2399 $$ = abc___break__(0, "");
2401 BREAK : "break" T_IDENTIFIER {
2402 $$ = abc___break__(0, $2);
2404 CONTINUE : "continue" %prec prec_none {
2405 $$ = abc___continue__(0, "");
2407 CONTINUE : "continue" T_IDENTIFIER {
2408 $$ = abc___continue__(0, $2);
2411 MAYBE_CASE_LIST : {$$=0;}
2412 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2413 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2414 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2415 CASE_LIST: CASE {$$=$1;}
2416 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2418 CASE: "case" E ':' MAYBECODE {
2419 $$ = abc_getlocal(0, state->switch_var);
2420 $$ = code_append($$, $2.c);
2421 code_t*j = $$ = abc_ifne($$, 0);
2422 $$ = code_append($$, $4);
2423 if($$->opcode != OPCODE___BREAK__) {
2424 $$ = abc___fallthrough__($$, "");
2426 code_t*e = $$ = abc_nop($$);
2429 DEFAULT: "default" ':' MAYBECODE {
2432 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2434 $$ = abc_setlocal($$, state->switch_var);
2435 $$ = code_append($$, $7);
2437 code_t*out = $$ = abc_kill($$, state->switch_var);
2438 breakjumpsto($$, $1, out);
2440 code_t*c = $$,*lastblock=0;
2442 if(c->opcode == OPCODE_IFNE) {
2443 if(!c->next) syntaxerror("internal error in fallthrough handling");
2445 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2447 c->opcode = OPCODE_JUMP;
2448 c->branch = lastblock;
2450 /* fall through end of switch */
2451 c->opcode = OPCODE_NOP;
2461 /* ------------ try / catch /finally ---------------- */
2463 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2464 state->exception_name=$3;
2465 PASS1 new_variable($3, 0, 0, 0);
2466 PASS2 new_variable($3, $4, 0, 0);
2469 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2470 multiname_t name = {QNAME, &name_ns, 0, $3};
2472 NEW(abc_exception_t, e)
2473 e->exc_type = sig2mname($4);
2474 e->var_name = multiname_clone(&name);
2478 int i = find_variable_safe(state, $3)->index;
2479 e->target = c = abc_nop(0);
2480 c = abc_setlocal(c, i);
2481 c = code_append(c, code_dup(state->method->scope_code));
2482 c = code_append(c, $8);
2488 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2493 NEW(abc_exception_t, e)
2494 e->exc_type = 0; //all exceptions
2495 e->var_name = 0; //no name
2498 e->to = code_append(e->to, $4);
2504 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2505 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2506 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2507 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2511 list_append($$.l,$2);
2512 $$.finally = $2->to;$2->to=0;
2515 CATCH_FINALLY_LIST: FINALLY {
2519 list_append($$.l,$1);
2520 $$.finally = $1->to;$1->to=0;
2524 TRY : "try" '{' {PASS12 new_state();
2525 state->method->has_exceptions=1;
2526 state->method->late_binding=1;//for invariant scope_code
2527 } MAYBECODE '}' CATCH_FINALLY_LIST {
2528 code_t*out = abc_nop(0);
2530 code_t*start = abc_nop(0);
2531 $$ = code_append(start, $4);
2532 if(!is_break_or_jump($4)) {
2533 $$ = abc_jump($$, out);
2535 code_t*end = $$ = abc_nop($$);
2539 tmp = new_variable("__finally__", 0, 0, 0);
2541 abc_exception_list_t*l = $6.l;
2544 abc_exception_t*e = l->abc_exception;
2546 $$ = code_append($$, e->target);
2547 $$ = abc_jump($$, out);
2549 parserassert((ptroff_t)$6.finally);
2551 e->target = $$ = abc_nop($$);
2552 $$ = code_append($$, code_dup(state->method->scope_code));
2553 $$ = abc___rethrow__($$);
2561 $$ = code_append($$, out);
2563 $$ = insert_finally($$, $6.finally, tmp);
2565 list_concat(state->method->exceptions, $6.l);
2571 /* ------------ throw ------------------------------- */
2573 THROW : "throw" EXPRESSION {
2577 THROW : "throw" %prec prec_none {
2578 if(!state->exception_name)
2579 syntaxerror("re-throw only possible within a catch block");
2580 variable_t*v = find_variable(state, state->exception_name);
2582 $$=abc_getlocal($$, v->index);
2586 /* ------------ with -------------------------------- */
2588 WITH_HEAD : "with" '(' EXPRESSION ')' {
2590 if(state->method->has_exceptions) {
2591 int v = alloc_local();
2592 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2593 state->method->scope_code = abc_pushwith(state->method->scope_code);
2598 WITH : WITH_HEAD CODEBLOCK {
2599 /* remove getlocal;pushwith from scope code again */
2600 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2603 if(state->method->has_exceptions) {
2605 $$ = abc_setlocal($$, $1.number);
2607 $$ = abc_pushwith($$);
2608 $$ = code_append($$, $2);
2609 $$ = abc_popscope($$);
2613 /* ------------ packages and imports ---------------- */
2615 X_IDENTIFIER: T_IDENTIFIER
2616 | "package" {PASS12 $$="package";}
2617 | T_NAMESPACE {PASS12 $$=$1;}
2619 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2620 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2622 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2623 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2624 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2625 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2627 IMPORT : "import" PACKAGEANDCLASS {
2629 slotinfo_t*s = registry_find($2->package, $2->name);
2630 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2631 as3_schedule_class($2->package, $2->name);
2637 syntaxerror("Couldn't import class\n");
2638 state_has_imports();
2639 dict_put(state->imports, c->name, c);
2640 import_toplevel(c->package);
2643 IMPORT : "import" PACKAGE '.' '*' {
2645 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2646 as3_schedule_package($2);
2652 state_has_imports();
2653 list_append(state->wildcard_imports, i);
2654 import_toplevel(i->package);
2658 /* ------------ classes and interfaces (header) -------------- */
2660 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2661 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2662 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2663 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2665 $$.flags=$1.flags|$2.flags;
2666 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2667 $$.ns=$1.ns?$1.ns:$2.ns;
2670 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2671 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2672 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2673 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2674 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2675 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2676 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2677 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2678 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2679 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2683 EXTENDS : {PASS12 $$=0;}
2684 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2686 EXTENDS_LIST : {PASS12 $$=list_new();}
2687 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2689 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2690 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2692 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2693 EXTENDS IMPLEMENTS_LIST
2694 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2696 '}' {PASS12 endclass();$$=0;}
2698 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2700 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2701 startclass(&$1,$3,0,$4);}
2702 MAYBE_INTERFACE_BODY
2703 '}' {PASS12 endclass();$$=0;}
2705 /* ------------ classes and interfaces (body) -------------- */
2708 MAYBE_CLASS_BODY : CLASS_BODY
2709 CLASS_BODY : CLASS_BODY_ITEM
2710 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2711 CLASS_BODY_ITEM : ';'
2712 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}'
2713 CLASS_BODY_ITEM : SLOT_DECLARATION
2714 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2716 CLASS_BODY_ITEM : CODE_STATEMENT {
2717 code_t*c = state->cls->static_init->header;
2718 c = code_append(c, $1);
2719 state->cls->static_init->header = c;
2722 MAYBE_INTERFACE_BODY :
2723 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2724 INTERFACE_BODY : IDECLARATION
2725 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2727 IDECLARATION : "var" T_IDENTIFIER {
2728 syntaxerror("variable declarations not allowed in interfaces");
2730 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2732 $1.flags |= FLAG_PUBLIC;
2733 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2734 syntaxerror("invalid method modifiers: interface methods always need to be public");
2736 startfunction(&$1,$3,$4,&$6,$8);
2737 endfunction(&$1,$3,$4,&$6,$8, 0);
2738 list_deep_free($6.list);
2741 /* ------------ classes and interfaces (body, slots ) ------- */
2743 VARCONST: "var" | "const"
2745 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {setslotstate(&$1,$2);} SLOT_LIST {$$=$4;setslotstate(0, 0);}
2747 SLOT_LIST: ONE_SLOT {$$ = $1;}
2748 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {$$ = code_append($1, $3);}
2750 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2752 int flags = slotstate_flags->flags;
2753 namespace_t ns = modifiers2access(slotstate_flags);
2755 varinfo_t* info = 0;
2757 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2759 check_override(i, flags);
2761 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2763 slotinfo_t*i = registry_find(state->package, $1);
2765 syntaxerror("package %s already contains '%s'", state->package, $1);
2767 if(ns.name && ns.name[0]) {
2768 syntaxerror("namespaces not allowed on package-level variables");
2770 info = varinfo_register_global(ns.access, state->package, $1);
2774 info->flags = flags;
2777 multiname_t mname = {QNAME, &ns, 0, $1};
2779 trait_list_t**traits;
2783 ns.name = state->package;
2784 traits = &global->init->traits;
2785 code = &global->init->method->body->code;
2786 } else if(flags&FLAG_STATIC) {
2788 traits = &state->cls->abc->static_traits;
2789 code = &state->cls->static_init->header;
2791 // instance variable
2792 traits = &state->cls->abc->traits;
2793 code = &state->cls->init->header;
2799 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2801 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2803 info->slot = t->slot_id;
2805 /* initalization code (if needed) */
2807 if($3.c && !is_pushundefined($3.c)) {
2808 c = abc_getlocal_0(c);
2809 c = code_append(c, $3.c);
2810 c = converttype(c, $3.t, $2);
2811 c = abc_setslot(c, t->slot_id);
2814 *code = code_append(*code, c);
2816 if(slotstate_varconst==KW_CONST) {
2817 t->kind= TRAIT_CONST;
2823 /* ------------ constants -------------------------------------- */
2825 MAYBESTATICCONSTANT: {$$=0;}
2826 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2828 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2829 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2830 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2831 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2832 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2833 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2834 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2835 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2836 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2837 STATICCONSTANT : T_IDENTIFIER {
2838 if(!strcmp($1, "NaN")) {
2839 $$ = constant_new_float(__builtin_nan(""));
2841 as3_warning("Couldn't evaluate constant value of %s", $1);
2842 $$ = constant_new_null($1);
2846 /* ------------ classes and interfaces (body, functions) ------- */
2848 // non-vararg version
2851 memset(&$$,0,sizeof($$));
2853 MAYBE_PARAM_LIST: PARAM_LIST {
2859 MAYBE_PARAM_LIST: "..." PARAM {
2861 memset(&$$,0,sizeof($$));
2863 list_append($$.list, $2);
2865 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2869 list_append($$.list, $4);
2873 PARAM_LIST: PARAM_LIST ',' PARAM {
2876 list_append($$.list, $3);
2880 memset(&$$,0,sizeof($$));
2881 list_append($$.list, $1);
2884 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2886 $$ = rfx_calloc(sizeof(param_t));
2892 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2894 $$ = rfx_calloc(sizeof(param_t));
2896 $$->type = TYPE_ANY;
2904 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2905 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2908 endfunction(&$1,$3,$4,&$6,0,0);
2910 if(!state->method->info) syntaxerror("internal error");
2912 code_t*c = method_header(state->method);
2913 c = wrap_function(c, 0, $11);
2915 endfunction(&$1,$3,$4,&$6,$8,c);
2917 list_deep_free($6.list);
2921 MAYBE_IDENTIFIER: T_IDENTIFIER
2922 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2923 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2924 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2927 endfunction(0,0,$2,&$4,0,0);
2929 methodinfo_t*f = state->method->info;
2930 if(!f || !f->kind) syntaxerror("internal error");
2932 code_t*c = method_header(state->method);
2933 c = wrap_function(c, 0, $9);
2935 int index = state->method->var_index;
2936 endfunction(0,0,$2,&$4,$6,c);
2938 $$.c = abc_getlocal(0, index);
2939 $$.t = TYPE_FUNCTION(f);
2941 PASS12 list_deep_free($4.list);
2945 /* ------------- package + class ids --------------- */
2947 CLASS: X_IDENTIFIER {
2948 PASS1 NEW(unresolvedinfo_t,c);
2949 memset(c, 0, sizeof(*c));
2950 c->kind = INFOTYPE_UNRESOLVED;
2952 c->package = get_package_from_name($1);
2954 c->nsset = get_current_imports();
2955 /* make the compiler look for this class in the current directory,
2957 //as3_schedule_class_noerror(state->package, $1);
2959 $$ = (classinfo_t*)c;
2961 slotinfo_t*s = find_class($1);
2962 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2963 $$ = (classinfo_t*)s;
2966 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2967 PASS1 NEW(unresolvedinfo_t,c);
2968 memset(c, 0, sizeof(*c));
2969 c->kind = INFOTYPE_UNRESOLVED;
2972 $$ = (classinfo_t*)c;
2974 slotinfo_t*s = registry_find($1, $3);
2975 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2977 $$ = (classinfo_t*)s;
2980 CLASS_SPEC: PACKAGEANDCLASS
2983 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2984 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2986 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2987 | '*' {PASS12 $$=registry_getanytype();}
2988 | "void" {PASS12 $$=registry_getanytype();}
2990 | "String" {$$=registry_getstringclass();}
2991 | "int" {$$=registry_getintclass();}
2992 | "uint" {$$=registry_getuintclass();}
2993 | "Boolean" {$$=registry_getbooleanclass();}
2994 | "Number" {$$=registry_getnumberclass();}
2997 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2998 MAYBETYPE: {PASS12 $$=0;}
3000 /* ----------function calls, delete, constructor calls ------ */
3002 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3003 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3005 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3006 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3007 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3009 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3013 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3014 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3015 $$.number= $1.number+1;
3016 $$.cc = code_append($1.cc, $2.c);
3020 NEW : "new" E XX MAYBE_PARAM_VALUES {
3022 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3024 code_t*paramcode = $4.cc;
3025 if($$.c->opcode == OPCODE_GETPROPERTY) {
3026 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3027 $$.c = code_cutlast($$.c);
3028 $$.c = code_append($$.c, paramcode);
3029 $$.c = abc_constructprop2($$.c, name, $4.number);
3030 multiname_destroy(name);
3031 } else if($$.c->opcode == OPCODE_GETSLOT) {
3032 int slot = (int)(ptroff_t)$$.c->data[0];
3033 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3034 multiname_t*name = t->name;
3035 $$.c = code_cutlast($$.c);
3036 $$.c = code_append($$.c, paramcode);
3037 $$.c = abc_constructprop2($$.c, name, $4.number);
3039 $$.c = code_append($$.c, paramcode);
3040 $$.c = abc_construct($$.c, $4.number);
3044 if(TYPE_IS_CLASS($2.t) && $2.t->data) {
3047 $$.c = abc_coerce_a($$.c);
3052 /* TODO: use abc_call (for calling local variables),
3053 abc_callstatic (for calling own methods)
3056 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3059 if($$.c->opcode == OPCODE_COERCE_A) {
3060 $$.c = code_cutlast($$.c);
3062 code_t*paramcode = $3.cc;
3065 if($$.c->opcode == OPCODE_GETPROPERTY) {
3066 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3067 $$.c = code_cutlast($$.c);
3068 $$.c = code_append($$.c, paramcode);
3069 $$.c = abc_callproperty2($$.c, name, $3.number);
3070 multiname_destroy(name);
3071 } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3072 int slot = (int)(ptroff_t)$$.c->data[0];
3073 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3074 if(t->kind!=TRAIT_METHOD) {
3075 //ok: flash allows to assign closures to members.
3077 multiname_t*name = t->name;
3078 $$.c = code_cutlast($$.c);
3079 $$.c = code_append($$.c, paramcode);
3080 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3081 $$.c = abc_callproperty2($$.c, name, $3.number);
3082 } else if($$.c->opcode == OPCODE_GETSUPER) {
3083 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3084 $$.c = code_cutlast($$.c);
3085 $$.c = code_append($$.c, paramcode);
3086 $$.c = abc_callsuper2($$.c, name, $3.number);
3087 multiname_destroy(name);
3089 $$.c = abc_getglobalscope($$.c);
3090 $$.c = code_append($$.c, paramcode);
3091 $$.c = abc_call($$.c, $3.number);
3094 if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
3095 $$.t = ((methodinfo_t*)($1.t->data))->return_type;
3097 $$.c = abc_coerce_a($$.c);
3102 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3103 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3104 if(!state->method) syntaxerror("super() not allowed outside of a function");
3105 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3108 $$.c = abc_getlocal_0($$.c);
3110 $$.c = code_append($$.c, $3.cc);
3112 this is dependent on the control path, check this somewhere else
3113 if(state->method->has_super)
3114 syntaxerror("constructor may call super() only once");
3116 state->method->has_super = 1;
3118 $$.c = abc_constructsuper($$.c, $3.number);
3119 $$.c = abc_pushundefined($$.c);
3123 DELETE: "delete" E {
3125 if($$.c->opcode == OPCODE_COERCE_A) {
3126 $$.c = code_cutlast($$.c);
3128 multiname_t*name = 0;
3129 if($$.c->opcode == OPCODE_GETPROPERTY) {
3130 $$.c->opcode = OPCODE_DELETEPROPERTY;
3131 } else if($$.c->opcode == OPCODE_GETSLOT) {
3132 int slot = (int)(ptroff_t)$$.c->data[0];
3133 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3134 $$.c = code_cutlast($$.c);
3135 $$.c = abc_deleteproperty2($$.c, name);
3137 $$.c = abc_getlocal_0($$.c);
3138 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
3139 $$.c = abc_deleteproperty2($$.c, &m);
3141 $$.t = TYPE_BOOLEAN;
3144 RETURN: "return" %prec prec_none {
3145 $$ = abc_returnvoid(0);
3147 RETURN: "return" EXPRESSION {
3149 $$ = abc_returnvalue($$);
3152 // ----------------------- expression types -------------------------------------
3154 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
3155 EXPRESSION : E %prec below_minus {$$ = $1;}
3156 EXPRESSION : EXPRESSION ',' E %prec below_minus {
3158 $$.c = cut_last_push($$.c);
3159 $$.c = code_append($$.c,$3.c);
3162 VOIDEXPRESSION : EXPRESSION %prec below_minus {
3163 $$=cut_last_push($1.c);
3166 // ----------------------- expression evaluation -------------------------------------
3168 E : INNERFUNCTION %prec prec_none {$$ = $1;}
3169 //V : CONSTANT {$$ = 0;}
3171 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
3172 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3173 //V : NEW {$$ = $1.c;}
3175 //V : DELETE {$$ = $1.c;}
3176 E : DELETE {$$ = $1;}
3182 namespace_t ns = {ACCESS_PACKAGE, ""};
3183 multiname_t m = {QNAME, &ns, 0, "RegExp"};
3185 $$.c = abc_getlex2($$.c, &m);
3186 $$.c = abc_pushstring($$.c, $1.pattern);
3187 $$.c = abc_construct($$.c, 1);
3189 $$.c = abc_getlex2($$.c, &m);
3190 $$.c = abc_pushstring($$.c, $1.pattern);
3191 $$.c = abc_pushstring($$.c, $1.options);
3192 $$.c = abc_construct($$.c, 2);
3197 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
3198 //MULTINAME(m, registry_getintclass());
3199 //$$.c = abc_coerce2($$.c, &m); // FIXME
3202 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
3205 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
3208 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
3211 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
3214 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
3217 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
3220 CONSTANT : "true" {$$.c = abc_pushtrue(0);
3221 $$.t = TYPE_BOOLEAN;
3223 CONSTANT : "false" {$$.c = abc_pushfalse(0);
3224 $$.t = TYPE_BOOLEAN;
3226 CONSTANT : "null" {$$.c = abc_pushnull(0);
3230 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
3231 $$.t = TYPE_BOOLEAN;
3233 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
3234 $$.t = TYPE_BOOLEAN;
3236 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
3237 $$.t = TYPE_BOOLEAN;
3239 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
3240 $$.t = TYPE_BOOLEAN;
3242 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
3243 $$.t = TYPE_BOOLEAN;
3245 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
3246 $$.t = TYPE_BOOLEAN;
3248 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
3249 $$.t = TYPE_BOOLEAN;
3251 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
3252 $$.t = TYPE_BOOLEAN;
3255 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
3257 $$.c = converttype($$.c, $1.t, $$.t);
3258 $$.c = abc_dup($$.c);
3259 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
3260 $$.c = cut_last_push($$.c);
3261 $$.c = code_append($$.c,$3.c);
3262 $$.c = converttype($$.c, $3.t, $$.t);
3263 code_t*label = $$.c = abc_label($$.c);
3264 jmp->branch = label;
3267 $$.t = join_types($1.t, $3.t, 'A');
3268 /*printf("%08x:\n",$1.t);
3269 code_dump($1.c, 0, 0, "", stdout);
3270 printf("%08x:\n",$3.t);
3271 code_dump($3.c, 0, 0, "", stdout);
3272 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
3274 $$.c = converttype($$.c, $1.t, $$.t);
3275 $$.c = abc_dup($$.c);
3276 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
3277 $$.c = cut_last_push($$.c);
3278 $$.c = code_append($$.c,$3.c);
3279 $$.c = converttype($$.c, $3.t, $$.t);
3280 code_t*label = $$.c = abc_label($$.c);
3281 jmp->branch = label;
3284 E : '!' E {$$.c=$2.c;
3285 $$.c = abc_not($$.c);
3286 $$.t = TYPE_BOOLEAN;
3289 E : '~' E {$$.c=$2.c;
3290 $$.c = abc_bitnot($$.c);
3294 E : E '&' E {$$.c = code_append($1.c,$3.c);
3295 $$.c = abc_bitand($$.c);
3299 E : E '^' E {$$.c = code_append($1.c,$3.c);
3300 $$.c = abc_bitxor($$.c);
3304 E : E '|' E {$$.c = code_append($1.c,$3.c);
3305 $$.c = abc_bitor($$.c);
3309 E : E ">>" E {$$.c = code_append($1.c,$3.c);
3310 $$.c = abc_rshift($$.c);
3313 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
3314 $$.c = abc_urshift($$.c);
3317 E : E "<<" E {$$.c = code_append($1.c,$3.c);
3318 $$.c = abc_lshift($$.c);
3322 E : E '/' E {$$.c = code_append($1.c,$3.c);
3323 $$.c = abc_divide($$.c);
3326 E : E '%' E {$$.c = code_append($1.c,$3.c);
3327 $$.c = abc_modulo($$.c);
3330 E : E '+' E {$$.c = code_append($1.c,$3.c);
3331 if(BOTH_INT($1.t, $3.t)) {
3332 $$.c = abc_add_i($$.c);
3335 $$.c = abc_add($$.c);
3336 $$.t = join_types($1.t,$3.t,'+');
3339 E : E '-' E {$$.c = code_append($1.c,$3.c);
3340 if(BOTH_INT($1.t,$3.t)) {
3341 $$.c = abc_subtract_i($$.c);
3344 $$.c = abc_subtract($$.c);
3348 E : E '*' E {$$.c = code_append($1.c,$3.c);
3349 if(BOTH_INT($1.t,$3.t)) {
3350 $$.c = abc_multiply_i($$.c);
3353 $$.c = abc_multiply($$.c);
3358 E : E "in" E {$$.c = code_append($1.c,$3.c);
3359 $$.c = abc_in($$.c);
3360 $$.t = TYPE_BOOLEAN;
3363 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
3364 if(use_astype && TYPE_IS_CLASS($3.t) && $3.t->data) {
3365 MULTINAME(m, (classinfo_t*)($3.t->data));
3366 $$.c = abc_astype2($1.c, &m);
3369 $$.c = code_append($1.c, $3.c);
3370 $$.c = abc_astypelate($$.c);
3375 E : E "instanceof" E
3376 {$$.c = code_append($1.c, $3.c);
3377 $$.c = abc_instanceof($$.c);
3378 $$.t = TYPE_BOOLEAN;
3381 E : E "is" E {$$.c = code_append($1.c, $3.c);
3382 $$.c = abc_istypelate($$.c);
3383 $$.t = TYPE_BOOLEAN;
3386 E : "typeof" '(' E ')' {
3388 $$.c = abc_typeof($$.c);
3393 $$.c = cut_last_push($2.c);
3394 $$.c = abc_pushundefined($$.c);
3398 E : "void" { $$.c = abc_pushundefined(0);
3402 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
3407 $$.c=abc_negate_i($$.c);
3410 $$.c=abc_negate($$.c);
3417 $$.c = code_append($$.c, $3.c);
3419 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
3420 $$.c = abc_getproperty2($$.c, &m);
3421 $$.t = 0; // array elements have unknown type
3424 E : '[' MAYBE_EXPRESSION_LIST ']' {
3426 $$.c = code_append($$.c, $2.cc);
3427 $$.c = abc_newarray($$.c, $2.number);
3428 $$.t = registry_getarrayclass();
3431 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3432 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
3434 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3436 $$.cc = code_append($$.cc, $1.c);
3437 $$.cc = code_append($$.cc, $3.c);
3440 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3442 $$.number = $1.number+2;
3443 $$.cc = code_append($$.cc, $3.c);
3444 $$.cc = code_append($$.cc, $5.c);
3449 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
3451 $$.c = code_append($$.c, $2.cc);
3452 $$.c = abc_newobject($$.c, $2.number/2);
3453 $$.t = registry_getobjectclass();
3458 if(BOTH_INT($1.t,$3.t)) {
3459 c=abc_multiply_i(c);
3463 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
3464 $$.c = toreadwrite($1.c, c, 0, 0);
3469 code_t*c = abc_modulo($3.c);
3470 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
3471 $$.c = toreadwrite($1.c, c, 0, 0);
3475 code_t*c = abc_lshift($3.c);
3476 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
3477 $$.c = toreadwrite($1.c, c, 0, 0);
3481 code_t*c = abc_rshift($3.c);
3482 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
3483 $$.c = toreadwrite($1.c, c, 0, 0);
3487 code_t*c = abc_urshift($3.c);
3488 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
3489 $$.c = toreadwrite($1.c, c, 0, 0);
3493 code_t*c = abc_divide($3.c);
3494 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
3495 $$.c = toreadwrite($1.c, c, 0, 0);
3499 code_t*c = abc_bitor($3.c);
3500 c=converttype(c, TYPE_INT, $1.t);
3501 $$.c = toreadwrite($1.c, c, 0, 0);
3505 code_t*c = abc_bitxor($3.c);
3506 c=converttype(c, TYPE_INT, $1.t);
3507 $$.c = toreadwrite($1.c, c, 0, 0);
3513 if(TYPE_IS_INT($1.t)) {
3517 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
3520 $$.c = toreadwrite($1.c, c, 0, 0);
3523 E : E "-=" E { code_t*c = $3.c;
3524 if(TYPE_IS_INT($1.t)) {
3525 c=abc_subtract_i(c);
3528 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
3531 $$.c = toreadwrite($1.c, c, 0, 0);
3534 E : E '=' E { code_t*c = 0;
3535 c = code_append(c, $3.c);
3536 c = converttype(c, $3.t, $1.t);
3537 $$.c = toreadwrite($1.c, c, 1, 0);
3541 E : E '?' E ':' E %prec below_assignment {
3542 $$.t = join_types($3.t,$5.t,'?');
3544 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
3545 $$.c = code_append($$.c, $3.c);
3546 $$.c = converttype($$.c, $3.t, $$.t);
3547 code_t*j2 = $$.c = abc_jump($$.c, 0);
3548 $$.c = j1->branch = abc_label($$.c);
3549 $$.c = code_append($$.c, $5.c);
3550 $$.c = converttype($$.c, $5.t, $$.t);
3551 $$.c = j2->branch = abc_label($$.c);
3554 E : E "++" { code_t*c = 0;
3555 classinfo_t*type = $1.t;
3556 if(is_getlocal($1.c) && (TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t))) {
3557 int nr = getlocalnr($1.c);
3558 code_free($1.c);$1.c=0;
3559 if(TYPE_IS_INT($1.t)) {
3560 $$.c = abc_getlocal(0, nr);
3561 $$.c = abc_inclocal_i($$.c, nr);
3562 } else if(TYPE_IS_NUMBER($1.t)) {
3563 $$.c = abc_getlocal(0, nr);
3564 $$.c = abc_inclocal($$.c, nr);
3565 } else syntaxerror("internal error");
3567 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3568 c=abc_increment_i(c);
3574 c=converttype(c, type, $1.t);
3575 $$.c = toreadwrite($1.c, c, 0, 1);
3580 // TODO: use inclocal, like with ++
3581 E : E "--" { code_t*c = 0;
3582 classinfo_t*type = $1.t;
3583 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3584 c=abc_decrement_i(c);
3590 c=converttype(c, type, $1.t);
3591 $$.c = toreadwrite($1.c, c, 0, 1);
3595 E : "++" %prec plusplus_prefix E { code_t*c = 0;
3596 classinfo_t*type = $2.t;
3597 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3598 c=abc_increment_i(c);
3604 c=converttype(c, type, $2.t);
3605 $$.c = toreadwrite($2.c, c, 0, 0);
3609 E : "--" %prec minusminus_prefix E { code_t*c = 0;
3610 classinfo_t*type = $2.t;
3611 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3612 c=abc_decrement_i(c);
3618 c=converttype(c, type, $2.t);
3619 $$.c = toreadwrite($2.c, c, 0, 0);
3623 E : "super" '.' T_IDENTIFIER
3624 { if(!state->cls->info)
3625 syntaxerror("super keyword not allowed outside a class");
3626 classinfo_t*t = state->cls->info->superclass;
3627 if(!t) t = TYPE_OBJECT;
3629 memberinfo_t*f = findmember_nsset(t, $3, 1);
3631 MEMBER_MULTINAME(m, f, $3);
3633 $$.c = abc_getlocal_0($$.c);
3634 $$.c = abc_getsuper2($$.c, &m);
3635 $$.t = slotinfo_gettype((slotinfo_t*)f);
3638 E : '@' T_IDENTIFIER {
3640 $$.c = abc_pushundefined(0);
3642 as3_warning("ignored @ operator");
3645 E : E '.' '@' T_IDENTIFIER {
3646 // child attribute TODO
3647 $$.c = abc_pushundefined(0);
3649 as3_warning("ignored .@ operator");
3652 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3653 // namespace declaration TODO
3654 $$.c = abc_pushundefined(0);
3656 as3_warning("ignored :: operator");
3659 E : E ".." T_IDENTIFIER {
3661 $$.c = abc_pushundefined(0);
3663 as3_warning("ignored .. operator");
3666 E : E '.' '(' E ')' {
3668 $$.c = abc_pushundefined(0);
3670 as3_warning("ignored .() operator");
3673 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
3677 E : E '.' T_IDENTIFIER {
3679 classinfo_t*t = $1.t;
3681 if(TYPE_IS_CLASS(t) && t->data) {
3686 if(t->subtype==INFOTYPE_UNRESOLVED) {
3687 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3689 memberinfo_t*f = findmember_nsset(t, $3, 1);
3691 if(f && !is_static != !(f->flags&FLAG_STATIC))
3693 if(f && f->slot && !noslot) {
3694 $$.c = abc_getslot($$.c, f->slot);
3696 MEMBER_MULTINAME(m, f, $3);
3697 $$.c = abc_getproperty2($$.c, &m);
3699 /* determine type */
3700 $$.t = slotinfo_gettype((slotinfo_t*)f);
3702 $$.c = abc_coerce_a($$.c);
3703 } else if($1.c && $1.c->opcode == OPCODE___PUSHPACKAGE__) {
3704 string_t*package = $1.c->data[0];
3705 char*package2 = concat3(package->str, ".", $3);
3707 slotinfo_t*a = registry_find(package->str, $3);
3710 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3711 registry_ispackage(package2)) {
3713 $$.c->data[0] = string_new4(package2);
3716 syntaxerror("couldn't resolve %s", package2);
3719 /* when resolving a property on an unknown type, we do know the
3720 name of the property (and don't seem to need the package), but
3721 we need to make avm2 try out all access modes */
3722 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3723 $$.c = abc_getproperty2($$.c, &m);
3724 $$.c = abc_coerce_a($$.c);
3725 $$.t = registry_getanytype();
3729 VAR_READ : T_IDENTIFIER {
3731 /* Queue unresolved identifiers for checking against the parent
3732 function's variables.
3733 We consider everything which is not a local variable "unresolved".
3734 This encompasses class names, members of the surrounding class
3735 etc. which is *correct* because local variables of the parent function
3738 if(state->method->inner && !find_variable(state, $1)) {
3739 unknown_variable($1);
3742 /* let the compiler know that it might want to check the current directory/package
3743 for this identifier- maybe there's a file $1.as defining $1. */
3744 //as3_schedule_class_noerror(state->package, $1);
3753 /* look at variables */
3754 if((v = find_variable(state, $1))) {
3755 // $1 is a local variable
3756 $$.c = abc_getlocal($$.c, v->index);
3760 if((v = find_slot(state, $1))) {
3761 $$.c = abc_getscopeobject($$.c, 1);
3762 $$.c = abc_getslot($$.c, v->index);
3767 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3769 /* look at current class' members */
3770 if(!state->method->inner &&
3772 (f = findmember_nsset(state->cls->info, $1, 1)) &&
3773 (f->flags&FLAG_STATIC) >= i_am_static)
3775 // $1 is a function in this class
3776 int var_is_static = (f->flags&FLAG_STATIC);
3778 if(f->kind == INFOTYPE_METHOD) {
3779 $$.t = TYPE_FUNCTION(f);
3783 if(var_is_static && !i_am_static) {
3784 /* access to a static member from a non-static location.
3785 do this via findpropstrict:
3786 there doesn't seem to be any non-lookup way to access
3787 static properties of a class */
3788 state->method->late_binding = 1;
3790 namespace_t ns = {f->access, ""};
3791 multiname_t m = {QNAME, &ns, 0, $1};
3792 $$.c = abc_findpropstrict2($$.c, &m);
3793 $$.c = abc_getproperty2($$.c, &m);
3795 } else if(f->slot>0) {
3796 $$.c = abc_getlocal_0($$.c);
3797 $$.c = abc_getslot($$.c, f->slot);
3800 namespace_t ns = {f->access, ""};
3801 multiname_t m = {QNAME, &ns, 0, $1};
3802 $$.c = abc_getlocal_0($$.c);
3803 $$.c = abc_getproperty2($$.c, &m);
3808 /* look at actual classes, in the current package and imported */
3809 if((a = find_class($1))) {
3814 /* look through package prefixes */
3815 if(dict_contains(state->import_toplevel_packages, $1) ||
3816 registry_ispackage($1)) {
3817 $$.c = abc___pushpackage__($$.c, $1);
3822 /* unknown object, let the avm2 resolve it */
3824 //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3825 as3_warning("Couldn't resolve '%s', doing late binding", $1);
3826 state->method->late_binding = 1;
3828 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3831 $$.c = abc_findpropstrict2($$.c, &m);
3832 $$.c = abc_getproperty2($$.c, &m);
3836 // ----------------- namespaces -------------------------------------------------
3838 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3840 NEW(namespace_decl_t,n);
3845 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3847 NEW(namespace_decl_t,n);
3852 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3854 NEW(namespace_decl_t,n);
3859 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3861 trie_put(active_namespaces, $2->name, (void*)$2->url);
3863 namespace_t access = modifiers2access(&$1);
3864 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3865 var->type = TYPE_NAMESPACE;
3867 ns.access = ACCESS_NAMESPACE;
3869 var->value = constant_new_namespace(&ns);
3874 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3876 const char*url = $3->name;
3877 varinfo_t*s = (varinfo_t*)$3;
3878 if(!s || s->kind != INFOTYPE_SLOT)
3879 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3880 if(!s->value || !NS_TYPE(s->value->type))
3881 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3882 url = s->value->ns->name;
3884 trie_put(active_namespaces, $3->name, (void*)url);
3885 add_active_url(url);