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 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
955 if(!type || type->kind != INFOTYPE_CLASS) {
956 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
965 char*as3_globalclass=0;
966 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
969 syntaxerror("inner classes now allowed");
974 classinfo_list_t*mlist=0;
976 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
977 syntaxerror("invalid modifier(s)");
979 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
980 syntaxerror("public and internal not supported at the same time.");
982 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
983 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
984 // all classes extend object
985 extends = registry_getobjectclass();
988 /* create the class name, together with the proper attributes */
992 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
993 access = ACCESS_PRIVATE; package = internal_filename_package;
994 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
995 access = ACCESS_PACKAGEINTERNAL; package = state->package;
996 } else if(state->package!=internal_filename_package) {
997 access = ACCESS_PACKAGE; package = state->package;
999 syntaxerror("public classes only allowed inside a package");
1003 state->cls = rfx_calloc(sizeof(classstate_t));
1004 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1005 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1006 /* notice: we make no effort to initialize the top variable (local0) here,
1007 even though it has special meaning. We just rely on the facat
1008 that pass 1 won't do anything with variables */
1010 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1012 /* set current method to constructor- all code within the class-level (except
1013 static variable initializations) will be executed during construction time */
1014 state->method = state->cls->init;
1016 if(registry_find(package, classname)) {
1017 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1019 /* build info struct */
1020 int num_interfaces = (list_length(implements));
1021 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1022 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1025 classinfo_list_t*l = implements;
1026 for(l=implements;l;l=l->next) {
1027 state->cls->info->interfaces[pos++] = l->classinfo;
1032 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1034 state->method = state->cls->init;
1035 parserassert(state->cls && state->cls->info);
1037 function_initvars(state->cls->init, 0, 0, 1);
1038 function_initvars(state->cls->static_init, 0, 0, 0);
1040 if(extends && (extends->flags & FLAG_FINAL))
1041 syntaxerror("Can't extend final class '%s'", extends->name);
1044 while(state->cls->info->interfaces[pos]) {
1045 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1046 syntaxerror("'%s' is not an interface",
1047 state->cls->info->interfaces[pos]->name);
1051 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
1052 state->cls->info->superclass = extends;
1054 /* generate the abc code for this class */
1055 MULTINAME(classname2,state->cls->info);
1056 multiname_t*extends2 = sig2mname(extends);
1058 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
1059 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1060 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1061 if(state->cls->info->flags&FLAG_INTERFACE) {
1062 abc_class_interface(state->cls->abc);
1065 abc_class_protectedNS(state->cls->abc, classname);
1067 for(mlist=implements;mlist;mlist=mlist->next) {
1068 MULTINAME(m, mlist->classinfo);
1069 abc_class_add_interface(state->cls->abc, &m);
1072 /* write the construction code for this class to the global init
1074 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
1076 abc_method_body_t*m = global->init->method->body;
1077 __ getglobalscope(m);
1078 classinfo_t*s = extends;
1083 //TODO: take a look at the current scope stack, maybe
1084 // we can re-use something
1089 multiname_t*s2 = sig2mname(s);
1091 multiname_destroy(s2);
1093 __ pushscope(m); count++;
1094 m->code = m->code->prev->prev; // invert
1096 /* continue appending after last op end */
1097 while(m->code && m->code->next) m->code = m->code->next;
1099 /* TODO: if this is one of *our* classes, we can also
1100 do a getglobalscope/getslot <nr> (which references
1101 the init function's slots) */
1103 __ getlex2(m, extends2);
1105 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
1106 stack is not the superclass */
1107 __ pushscope(m);count++;
1110 /* notice: we get a verify error #1107 if the top element on the scope
1111 stack is not the global object */
1113 __ pushscope(m);count++;
1115 __ newclass(m,state->cls->abc);
1119 __ setslot(m, slotindex);
1120 multiname_destroy(extends2);
1122 /* flash.display.MovieClip handling */
1124 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1125 if(state->package && state->package[0]) {
1126 as3_globalclass = concat3(state->package, ".", classname);
1128 as3_globalclass = strdup(classname);
1134 static int slotstate_varconst = 0;
1135 static modifiers_t*slotstate_flags = 0;
1136 static void setslotstate(modifiers_t* flags, int varconst)
1138 slotstate_varconst = varconst;
1139 slotstate_flags = flags;
1141 if(flags && flags->flags&FLAG_STATIC) {
1142 state->method = state->cls->static_init;
1144 state->method = state->cls->init;
1147 parserassert(state->method);
1151 static void endclass()
1154 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1156 c = abc_getlocal_0(c);
1157 c = abc_constructsuper(c, 0);
1158 state->cls->init->header = code_append(state->cls->init->header, c);
1159 state->cls->has_constructor=1;
1161 if(state->cls->init) {
1162 if(state->cls->info->flags&FLAG_INTERFACE) {
1163 if(state->cls->init->header)
1164 syntaxerror("interface can not have class-level code");
1166 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1167 code_t*c = method_header(state->cls->init);
1168 m->body->code = wrap_function(c, 0, m->body->code);
1171 if(state->cls->static_init) {
1172 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1173 code_t*c = method_header(state->cls->static_init);
1174 m->body->code = wrap_function(c, 0, m->body->code);
1181 void check_code_for_break(code_t*c)
1184 if(c->opcode == OPCODE___BREAK__) {
1185 char*name = string_cstr(c->data[0]);
1186 syntaxerror("Unresolved \"break %s\"", name);
1188 if(c->opcode == OPCODE___CONTINUE__) {
1189 char*name = string_cstr(c->data[0]);
1190 syntaxerror("Unresolved \"continue %s\"", name);
1192 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1193 char*name = string_cstr(c->data[0]);
1194 syntaxerror("Can't reference a package (%s) as such", name);
1201 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1204 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1205 if(TYPE_IS_NUMBER(t)) {
1206 xassert(c->type == CONSTANT_FLOAT
1207 || c->type == CONSTANT_INT
1208 || c->type == CONSTANT_UINT);
1209 } else if(TYPE_IS_UINT(t)) {
1210 xassert(c->type == CONSTANT_UINT ||
1211 (c->type == CONSTANT_INT && c->i>=0));
1212 } else if(TYPE_IS_INT(t)) {
1213 xassert(c->type == CONSTANT_INT);
1214 } else if(TYPE_IS_BOOLEAN(t)) {
1215 xassert(c->type == CONSTANT_TRUE
1216 || c->type == CONSTANT_FALSE);
1220 static void check_override(memberinfo_t*m, int flags)
1224 if(m->parent == state->cls->info)
1225 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1227 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1228 if(m->access==ACCESS_PRIVATE)
1230 if(m->flags & FLAG_FINAL)
1231 syntaxerror("can't override final member %s", m->name);
1233 /* allow this. it's no issue.
1234 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1235 syntaxerror("can't override static member %s", m->name);*/
1237 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1238 syntaxerror("can't override non-static member %s with static declaration", m->name);
1240 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1241 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1242 if(m->kind == INFOTYPE_METHOD)
1243 syntaxerror("can't override without explicit 'override' declaration");
1245 syntaxerror("can't override '%s'", m->name);
1250 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1252 methodinfo_t*minfo = 0;
1253 namespace_t ns = modifiers2access(mod);
1256 minfo = methodinfo_register_global(ns.access, state->package, name);
1257 minfo->return_type = 0; // save this for pass 2
1258 } else if(getset != KW_GET && getset != KW_SET) {
1260 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1262 printf("%s.%s | %s.%s\n",
1263 m->package, m->name,
1265 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1267 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1268 minfo->return_type = 0; // save this for pass 2
1269 // getslot on a member slot only returns "undefined", so no need
1270 // to actually store these
1271 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1273 //class getter/setter
1274 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1276 if(getset == KW_GET) {
1278 } else if(params->list && params->list->param && !params->list->next) {
1279 type = params->list->param->type;
1281 syntaxerror("setter function needs to take exactly one argument");
1282 // not sure wether to look into superclasses here, too
1283 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1285 if(minfo->kind!=INFOTYPE_SLOT)
1286 syntaxerror("class already contains a method called '%s'", name);
1287 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1288 syntaxerror("class already contains a field called '%s'", name);
1289 if(minfo->subtype & gs)
1290 syntaxerror("getter/setter for '%s' already defined", name);
1291 /* make a setter or getter into a getset */
1292 minfo->subtype |= gs;
1295 FIXME: this check needs to be done in pass 2
1297 if((!minfo->return_type != !type) ||
1298 (minfo->return_type && type &&
1299 !strcmp(minfo->return_type->name, type->name))) {
1300 syntaxerror("different type in getter and setter: %s and %s",
1301 minfo->return_type?minfo->return_type->name:"*",
1302 type?type->name:"*");
1305 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1306 minfo->kind = INFOTYPE_SLOT; //hack
1307 minfo->subtype = gs;
1308 minfo->return_type = 0;
1310 /* can't assign a slot as getter and setter might have different slots */
1311 //minfo->slot = slot;
1313 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1314 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1315 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1320 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1322 //parserassert(state->method && state->method->info);
1324 methodstate_t*parent_method = state->method;
1327 return_type = 0; // not valid in pass 1
1331 state->new_vars = 1;
1334 state->method = rfx_calloc(sizeof(methodstate_t));
1335 state->method->inner = 1;
1336 state->method->variable_count = 0;
1337 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1339 NEW(methodinfo_t,minfo);
1340 minfo->kind = INFOTYPE_METHOD;
1341 minfo->access = ACCESS_PACKAGEINTERNAL;
1343 state->method->info = minfo;
1346 list_append(parent_method->innerfunctions, state->method);
1348 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1350 function_initvars(state->method, params, 0, 1);
1354 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1355 state->method->variable_count = 0;
1356 parserassert(state->method);
1358 state->method->info->return_type = return_type;
1359 function_initvars(state->method, params, 0, 1);
1363 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1364 params_t*params, classinfo_t*return_type)
1366 if(state->method && state->method->info) {
1367 syntaxerror("not able to start another method scope");
1370 state->new_vars = 1;
1373 state->method = rfx_calloc(sizeof(methodstate_t));
1374 state->method->has_super = 0;
1377 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1379 state->method->is_global = 1;
1380 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1382 if(state->method->is_constructor)
1383 name = "__as3_constructor__";
1385 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1387 function_initvars(state->method, params, mod->flags, 1);
1389 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1393 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1394 state->method->variable_count = 0;
1395 parserassert(state->method);
1398 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1399 check_override(m, mod->flags);
1403 state->cls->has_constructor |= state->method->is_constructor;
1406 state->method->info->return_type = return_type;
1407 function_initvars(state->method, params, mod->flags, 1);
1411 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1412 params_t*params, classinfo_t*return_type, code_t*body)
1415 // store inner methods in variables
1416 function_initvars(state->method, 0, 0, 0);
1418 methodstate_list_t*ml = state->method->innerfunctions;
1420 dict_t*xvars = dict_new();
1423 methodstate_t*m = ml->methodstate;
1424 parserassert(m->inner);
1425 if(m->unresolved_variables) {
1426 dict_t*d = m->unresolved_variables;
1428 for(t=0;t<d->hashsize;t++) {
1429 dictentry_t*l = d->slots[t];
1431 /* check parent method's variables */
1433 if((v=find_variable(state, l->key))) {
1434 m->uses_parent_function = 1;
1435 state->method->uses_slots = 1;
1436 dict_put(xvars, l->key, 0);
1443 dict_destroy(m->unresolved_variables);
1444 m->unresolved_variables = 0;
1449 if(state->method->uses_slots) {
1450 state->method->slots = dict_new();
1452 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1453 if(!name) syntaxerror("internal error");
1454 if(v->index && dict_contains(xvars, name)) {
1457 if(v->is_inner_method) {
1458 v->is_inner_method->is_a_slot = 1;
1461 dict_put(state->method->slots, name, v);
1464 state->method->uses_slots = i;
1465 dict_destroy(state->vars);state->vars = 0;
1472 /*if(state->method->uses_parent_function){
1473 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1478 multiname_t*type2 = sig2mname(return_type);
1480 if(state->method->inner) {
1481 f = state->method->abc;
1482 abc_method_init(f, global->file, type2, 1);
1483 } else if(state->method->is_constructor) {
1484 f = abc_class_getconstructor(state->cls->abc, type2);
1485 } else if(!state->method->is_global) {
1486 namespace_t mname_ns = modifiers2access(mod);
1487 multiname_t mname = {QNAME, &mname_ns, 0, name};
1489 if(mod->flags&FLAG_STATIC)
1490 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1492 f = abc_class_method(state->cls->abc, type2, &mname);
1493 slot = f->trait->slot_id;
1495 namespace_t mname_ns = {state->method->info->access, state->package};
1496 multiname_t mname = {QNAME, &mname_ns, 0, name};
1498 f = abc_method_new(global->file, type2, 1);
1499 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1500 //abc_code_t*c = global->init->method->body->code;
1502 //flash doesn't seem to allow us to access function slots
1503 //state->method->info->slot = slot;
1505 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1506 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1507 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1508 if(params->varargs) f->flags |= METHOD_NEED_REST;
1512 for(p=params->list;p;p=p->next) {
1513 if(params->varargs && !p->next) {
1514 break; //varargs: omit last parameter in function signature
1516 multiname_t*m = sig2mname(p->param->type);
1517 list_append(f->parameters, m);
1518 if(p->param->value) {
1519 check_constant_against_type(p->param->type, p->param->value);
1520 opt=1;list_append(f->optional_parameters, p->param->value);
1522 syntaxerror("non-optional parameter not allowed after optional parameters");
1525 if(state->method->slots) {
1526 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1528 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1529 multiname_t*type = sig2mname(v->type);
1530 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1531 t->slot_id = v->index;
1536 check_code_for_break(body);
1538 /* Seems this works now.
1539 if(state->method->exceptions && state->method->uses_slots) {
1540 as3_warning("try/catch and activation not supported yet within the same method");
1544 f->body->code = body;
1545 f->body->exceptions = state->method->exceptions;
1546 } else { //interface
1548 syntaxerror("interface methods can't have a method body");
1558 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1563 void breakjumpsto(code_t*c, char*name, code_t*jump)
1566 if(c->opcode == OPCODE___BREAK__) {
1567 string_t*name2 = c->data[0];
1568 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1569 c->opcode = OPCODE_JUMP;
1576 void continuejumpsto(code_t*c, char*name, code_t*jump)
1579 if(c->opcode == OPCODE___CONTINUE__) {
1580 string_t*name2 = c->data[0];
1581 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1582 c->opcode = OPCODE_JUMP;
1590 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1591 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1592 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1594 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1596 if(!type1 || !type2)
1597 return registry_getanytype();
1598 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1599 return registry_getanytype();
1602 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1611 return registry_getanytype();
1613 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1618 return abc_coerce_a(c);
1622 // cast an "any" type to a specific type. subject to
1623 // runtime exceptions
1624 return abc_coerce2(c, &m);
1627 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1628 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1629 // allow conversion between number types
1630 return abc_coerce2(c, &m);
1632 //printf("%s.%s\n", from.package, from.name);
1633 //printf("%s.%s\n", to.package, to.name);
1635 classinfo_t*supertype = from;
1637 if(supertype == to) {
1638 // target type is one of from's superclasses
1639 return abc_coerce2(c, &m);
1642 while(supertype->interfaces[t]) {
1643 if(supertype->interfaces[t]==to) {
1644 // target type is one of from's interfaces
1645 return abc_coerce2(c, &m);
1649 supertype = supertype->superclass;
1651 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1653 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1655 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1658 as3_error("can't convert type %s%s%s to %s%s%s",
1659 from->package, from->package?".":"", from->name,
1660 to->package, to->package?".":"", to->name);
1664 code_t*defaultvalue(code_t*c, classinfo_t*type)
1666 if(TYPE_IS_INT(type)) {
1667 c = abc_pushbyte(c, 0);
1668 } else if(TYPE_IS_UINT(type)) {
1669 c = abc_pushuint(c, 0);
1670 } else if(TYPE_IS_FLOAT(type)) {
1672 } else if(TYPE_IS_BOOLEAN(type)) {
1673 c = abc_pushfalse(c);
1675 //c = abc_pushundefined(c);
1677 c = abc_pushnull(c);
1679 c = abc_coerce2(c, &m);
1684 char is_pushundefined(code_t*c)
1686 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1689 static const char* get_package_from_name(const char*name)
1691 /* try explicit imports */
1692 dictentry_t* e = dict_get_slot(state->imports, name);
1694 if(!strcmp(e->key, name)) {
1695 slotinfo_t*c = (slotinfo_t*)e->data;
1696 if(c) return c->package;
1702 static namespace_list_t*get_current_imports()
1704 namespace_list_t*searchlist = 0;
1706 list_append(searchlist, namespace_new_package(state->package));
1708 import_list_t*l = state->wildcard_imports;
1710 namespace_t*ns = namespace_new_package(l->import->package);
1711 list_append(searchlist, ns);
1714 list_append(searchlist, namespace_new_package(""));
1715 list_append(searchlist, namespace_new_package(internal_filename_package));
1719 static slotinfo_t* find_class(const char*name)
1723 c = registry_find(state->package, name);
1726 /* try explicit imports */
1727 dictentry_t* e = dict_get_slot(state->imports, name);
1730 if(!strcmp(e->key, name)) {
1731 c = (slotinfo_t*)e->data;
1737 /* try package.* imports */
1738 import_list_t*l = state->wildcard_imports;
1740 //printf("does package %s contain a class %s?\n", l->import->package, name);
1741 c = registry_find(l->import->package, name);
1746 /* try global package */
1747 c = registry_find("", name);
1750 /* try local "filename" package */
1751 c = registry_find(internal_filename_package, name);
1756 typedcode_t push_class(slotinfo_t*a)
1761 if(a->access == ACCESS_PACKAGEINTERNAL &&
1762 strcmp(a->package, state->package) &&
1763 strcmp(a->package, internal_filename_package)
1765 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1766 infotypename(a), a->name, a->package, state->package);
1769 if(a->kind != INFOTYPE_CLASS) {
1771 x.c = abc_findpropstrict2(x.c, &m);
1772 x.c = abc_getproperty2(x.c, &m);
1773 if(a->kind == INFOTYPE_METHOD) {
1774 methodinfo_t*f = (methodinfo_t*)a;
1775 x.t = TYPE_FUNCTION(f);
1777 varinfo_t*v = (varinfo_t*)a;
1781 classinfo_t*c = (classinfo_t*)a;
1783 x.c = abc_getglobalscope(x.c);
1784 x.c = abc_getslot(x.c, c->slot);
1787 x.c = abc_getlex2(x.c, &m);
1789 x.t = TYPE_CLASS(c);
1794 static char is_getlocal(code_t*c)
1796 if(!c || c->prev || c->next)
1798 return(c->opcode == OPCODE_GETLOCAL
1799 || c->opcode == OPCODE_GETLOCAL_0
1800 || c->opcode == OPCODE_GETLOCAL_1
1801 || c->opcode == OPCODE_GETLOCAL_2
1802 || c->opcode == OPCODE_GETLOCAL_3);
1804 static int getlocalnr(code_t*c)
1806 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1807 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1808 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1809 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1810 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1811 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1815 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1819 [prefix code] [read instruction]
1823 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1825 if(in && in->opcode == OPCODE_COERCE_A) {
1826 in = code_cutlast(in);
1829 syntaxerror("internal error");
1831 /* chop off read instruction */
1835 prefix = r->prev;r->prev = 0;
1841 char use_temp_var = readbefore;
1843 /* generate the write instruction, and maybe append a dup to the prefix code */
1844 code_t* write = abc_nop(0);
1845 if(r->opcode == OPCODE_GETPROPERTY) {
1846 write->opcode = OPCODE_SETPROPERTY;
1847 multiname_t*m = (multiname_t*)r->data[0];
1848 write->data[0] = multiname_clone(m);
1849 if(m->type == QNAME || m->type == MULTINAME) {
1851 prefix = abc_dup(prefix); // we need the object, too
1854 } else if(m->type == MULTINAMEL) {
1856 /* dupping two values on the stack requires 5 operations and one register-
1857 couldn't adobe just have given us a dup2? */
1858 int temp = gettempvar();
1859 prefix = abc_setlocal(prefix, temp);
1860 prefix = abc_dup(prefix);
1861 prefix = abc_getlocal(prefix, temp);
1862 prefix = abc_swap(prefix);
1863 prefix = abc_getlocal(prefix, temp);
1865 prefix = abc_kill(prefix, temp);
1869 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1871 } else if(r->opcode == OPCODE_GETSLOT) {
1872 write->opcode = OPCODE_SETSLOT;
1873 write->data[0] = r->data[0];
1875 prefix = abc_dup(prefix); // we need the object, too
1878 } else if(r->opcode == OPCODE_GETLOCAL) {
1879 write->opcode = OPCODE_SETLOCAL;
1880 write->data[0] = r->data[0];
1881 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1882 write->opcode = OPCODE_SETLOCAL_0;
1883 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1884 write->opcode = OPCODE_SETLOCAL_1;
1885 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1886 write->opcode = OPCODE_SETLOCAL_2;
1887 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1888 write->opcode = OPCODE_SETLOCAL_3;
1889 } else if(r->opcode == OPCODE_GETSUPER) {
1890 write->opcode = OPCODE_SETSUPER;
1891 multiname_t*m = (multiname_t*)r->data[0];
1892 write->data[0] = multiname_clone(m);
1895 syntaxerror("illegal lvalue: can't assign a value to this expression");
1902 /* with getproperty/getslot, we have to be extra careful not
1903 to execute the read code twice, as it might have side-effects
1904 (e.g. if the property is in fact a setter/getter combination)
1906 So read the value, modify it, and write it again,
1907 using prefix only once and making sure (by using a temporary
1908 register) that the return value is what we just wrote */
1909 temp = gettempvar();
1910 c = code_append(c, prefix);
1911 c = code_append(c, r);
1914 c = abc_setlocal(c, temp);
1916 c = code_append(c, middlepart);
1919 c = abc_setlocal(c, temp);
1921 c = code_append(c, write);
1922 c = abc_getlocal(c, temp);
1923 c = abc_kill(c, temp);
1925 /* if we're allowed to execute the read code twice *and*
1926 the middlepart doesn't modify the code, things are easier.
1928 code_t* r2 = code_dup(r);
1929 //c = code_append(c, prefix);
1930 parserassert(!prefix);
1931 c = code_append(c, r);
1932 c = code_append(c, middlepart);
1933 c = code_append(c, write);
1934 c = code_append(c, r2);
1937 /* even smaller version: overwrite the value without reading
1941 c = code_append(c, prefix);
1944 c = code_append(c, middlepart);
1945 c = code_append(c, write);
1946 c = code_append(c, r);
1949 temp = gettempvar();
1951 c = code_append(c, prefix);
1953 c = code_append(c, middlepart);
1955 c = abc_setlocal(c, temp);
1956 c = code_append(c, write);
1957 c = abc_getlocal(c, temp);
1958 c = abc_kill(c, temp);
1964 char is_break_or_jump(code_t*c)
1968 if(c->opcode == OPCODE_JUMP ||
1969 c->opcode == OPCODE___BREAK__ ||
1970 c->opcode == OPCODE___CONTINUE__ ||
1971 c->opcode == OPCODE_THROW ||
1972 c->opcode == OPCODE_RETURNVOID ||
1973 c->opcode == OPCODE_RETURNVALUE) {
1979 #define IS_FINALLY_TARGET(op) \
1980 ((op) == OPCODE___CONTINUE__ || \
1981 (op) == OPCODE___BREAK__ || \
1982 (op) == OPCODE_RETURNVOID || \
1983 (op) == OPCODE_RETURNVALUE || \
1984 (op) == OPCODE___RETHROW__)
1986 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1988 #define NEED_EXTRA_STACK_ARG
1989 code_t*finally_label = abc_nop(0);
1990 NEW(lookupswitch_t, l);
1996 code_t*prev = i->prev;
1997 if(IS_FINALLY_TARGET(i->opcode)) {
2000 if(i->opcode == OPCODE___RETHROW__ ||
2001 i->opcode == OPCODE_RETURNVALUE) {
2002 if(i->opcode == OPCODE___RETHROW__)
2003 i->opcode = OPCODE_THROW;
2005 p = abc_coerce_a(p);
2006 p = abc_setlocal(p, tempvar);
2008 p = abc_pushbyte(p, count++);
2009 p = abc_jump(p, finally_label);
2010 code_t*target = p = abc_label(p);
2011 #ifdef NEED_EXTRA_STACK_ARG
2015 p = abc_getlocal(p, tempvar);
2018 p->next = i;i->prev = p;
2019 list_append(l->targets, target);
2025 c = abc_pushbyte(c, -1);
2026 c = code_append(c, finally_label);
2027 c = code_append(c, finally);
2029 #ifdef NEED_EXTRA_STACK_ARG
2032 c = abc_lookupswitch(c, l);
2033 c = l->def = abc_label(c);
2034 #ifdef NEED_EXTRA_STACK_ARG
2041 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
2045 code_t*prev = i->prev;
2046 if(IS_FINALLY_TARGET(i->opcode)) {
2047 if(i->opcode == OPCODE___RETHROW__)
2048 i->opcode = OPCODE_THROW;
2049 code_t*end = code_dup(finally);
2050 code_t*start = code_start(end);
2051 if(prev) prev->next = start;
2058 return code_append(c, finally);
2061 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
2067 int num_insertion_points=0;
2069 if(IS_FINALLY_TARGET(i->opcode))
2070 num_insertion_points++;
2077 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
2082 int simple_version_cost = (1+num_insertion_points)*code_size;
2083 int lookup_version_cost = 4*num_insertion_points + 5;
2085 if(cantdup || simple_version_cost > lookup_version_cost) {
2086 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
2087 return insert_finally_lookup(c, finally, tempvar);
2089 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
2090 return insert_finally_simple(c, finally, tempvar);
2094 #define PASS1 }} if(as3_pass == 1) {{
2095 #define PASS1END }} if(as3_pass == 2) {{
2096 #define PASS2 }} if(as3_pass == 2) {{
2097 #define PASS12 }} {{
2098 #define PASS12END }} if(as3_pass == 2) {{
2104 /* ------------ code blocks / statements ---------------- */
2106 PROGRAM: MAYBE_PROGRAM_CODE_LIST
2108 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
2109 PROGRAM_CODE_LIST: PROGRAM_CODE
2110 | PROGRAM_CODE_LIST PROGRAM_CODE
2112 PROGRAM_CODE: PACKAGE_DECLARATION
2113 | INTERFACE_DECLARATION
2115 | FUNCTION_DECLARATION
2118 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' // conditional compilation
2121 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
2122 INPACKAGE_CODE_LIST: INPACKAGE_CODE
2123 | INPACKAGE_CODE_LIST INPACKAGE_CODE
2125 INPACKAGE_CODE: INTERFACE_DECLARATION
2127 | FUNCTION_DECLARATION
2130 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' // conditional compilation
2133 MAYBECODE: CODE {$$=$1;}
2134 MAYBECODE: {$$=code_new();}
2136 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
2137 CODE: CODEPIECE {$$=$1;}
2139 // code which may appear outside of methods
2140 CODE_STATEMENT: IMPORT
2142 CODE_STATEMENT: FOR_IN
2143 CODE_STATEMENT: WHILE
2144 CODE_STATEMENT: DO_WHILE
2145 CODE_STATEMENT: SWITCH
2147 CODE_STATEMENT: WITH
2149 CODE_STATEMENT: VOIDEXPRESSION
2150 CODE_STATEMENT: USE_NAMESPACE
2151 CODE_STATEMENT: NAMESPACE_DECLARATION
2152 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
2153 CODE_STATEMENT: '{' '}' {$$=0;}
2155 // code which may appear in methods
2156 CODEPIECE: ';' {$$=0;}
2157 CODEPIECE: CODE_STATEMENT
2158 CODEPIECE: VARIABLE_DECLARATION
2163 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
2165 //CODEBLOCK : '{' CODE '}' {$$=$2;}
2166 //CODEBLOCK : '{' '}' {$$=0;}
2167 CODEBLOCK : CODEPIECE ';' {$$=$1;}
2168 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
2170 /* ------------ package init code ------------------- */
2172 PACKAGE_INITCODE: CODE_STATEMENT {
2173 code_t**cc = &global->init->method->body->code;
2174 *cc = code_append(*cc, $1);
2177 /* ------------ conditional compilation ------------- */
2179 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER
2181 /* ------------ variables --------------------------- */
2183 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
2184 | {$$.c=abc_pushundefined(0);
2188 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2189 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2191 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2192 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2194 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2197 if(variable_exists($1))
2198 syntaxerror("Variable %s already defined", $1);
2200 new_variable($1, 0, 1, 0);
2203 if(!is_subtype_of($3.t, $2)) {
2204 syntaxerror("Can't convert %s to %s", $3.t->name,
2210 if(state->method->uses_slots) {
2211 variable_t* v = find_slot(state, $1);
2213 // this variable is stored in a slot
2221 index = new_variable($1, $2, 1, 0);
2224 $$ = slot?abc_getscopeobject(0, 1):0;
2227 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2228 $$ = code_append($$, $3.c);
2229 $$ = converttype($$, $3.t, $2);
2232 $$ = defaultvalue($$, $2);
2235 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2236 $$ = code_append($$, $3.c);
2237 $$ = abc_coerce_a($$);
2239 // don't do anything
2247 $$ = abc_setslot($$, index);
2249 $$ = abc_setlocal($$, index);
2253 /* ------------ control flow ------------------------- */
2255 MAYBEELSE: %prec below_else {$$ = code_new();}
2256 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2257 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2259 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2262 $$ = code_append($$, $4.c);
2263 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2265 $$ = code_append($$, $6);
2267 myjmp = $$ = abc_jump($$, 0);
2269 myif->branch = $$ = abc_nop($$);
2271 $$ = code_append($$, $7);
2272 myjmp->branch = $$ = abc_nop($$);
2278 FOR_INIT : {$$=code_new();}
2279 FOR_INIT : VARIABLE_DECLARATION
2280 FOR_INIT : VOIDEXPRESSION
2282 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2283 // (I don't see any easy way to revolve this conflict otherwise, as we
2284 // can't touch VAR_READ without upsetting the precedence about "return")
2285 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2286 PASS1 $$=$2;new_variable($2,0,1,0);
2287 PASS2 $$=$2;new_variable($2,$3,1,0);
2289 FOR_IN_INIT : T_IDENTIFIER {
2294 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2295 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2297 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2298 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2300 $$ = code_append($$, $2);
2301 code_t*loopstart = $$ = abc_label($$);
2302 $$ = code_append($$, $4.c);
2303 code_t*myif = $$ = abc_iffalse($$, 0);
2304 $$ = code_append($$, $8);
2305 code_t*cont = $$ = abc_nop($$);
2306 $$ = code_append($$, $6);
2307 $$ = abc_jump($$, loopstart);
2308 code_t*out = $$ = abc_nop($$);
2309 breakjumpsto($$, $1.name, out);
2310 continuejumpsto($$, $1.name, cont);
2317 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2318 variable_t*var = find_variable(state, $2);
2320 syntaxerror("variable %s not known in this scope", $2);
2323 char*tmp1name = concat2($2, "__tmp1__");
2324 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2325 char*tmp2name = concat2($2, "__array__");
2326 int array = new_variable(tmp1name, 0, 0, 0);
2329 $$ = code_append($$, $4.c);
2330 $$ = abc_coerce_a($$);
2331 $$ = abc_setlocal($$, array);
2332 $$ = abc_pushbyte($$, 0);
2333 $$ = abc_setlocal($$, it);
2335 code_t*loopstart = $$ = abc_label($$);
2337 $$ = abc_hasnext2($$, array, it);
2338 code_t*myif = $$ = abc_iffalse($$, 0);
2339 $$ = abc_getlocal($$, array);
2340 $$ = abc_getlocal($$, it);
2342 $$ = abc_nextname($$);
2344 $$ = abc_nextvalue($$);
2345 $$ = converttype($$, 0, var->type);
2346 $$ = abc_setlocal($$, var->index);
2348 $$ = code_append($$, $6);
2349 $$ = abc_jump($$, loopstart);
2351 code_t*out = $$ = abc_nop($$);
2352 breakjumpsto($$, $1.name, out);
2353 continuejumpsto($$, $1.name, loopstart);
2365 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2369 code_t*myjmp = $$ = abc_jump($$, 0);
2370 code_t*loopstart = $$ = abc_label($$);
2371 $$ = code_append($$, $6);
2372 code_t*cont = $$ = abc_nop($$);
2373 myjmp->branch = cont;
2374 $$ = code_append($$, $4.c);
2375 $$ = abc_iftrue($$, loopstart);
2376 code_t*out = $$ = abc_nop($$);
2377 breakjumpsto($$, $1, out);
2378 continuejumpsto($$, $1, cont);
2384 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2386 code_t*loopstart = $$ = abc_label($$);
2387 $$ = code_append($$, $3);
2388 code_t*cont = $$ = abc_nop($$);
2389 $$ = code_append($$, $6.c);
2390 $$ = abc_iftrue($$, loopstart);
2391 code_t*out = $$ = abc_nop($$);
2392 breakjumpsto($$, $1, out);
2393 continuejumpsto($$, $1, cont);
2399 BREAK : "break" %prec prec_none {
2400 $$ = abc___break__(0, "");
2402 BREAK : "break" T_IDENTIFIER {
2403 $$ = abc___break__(0, $2);
2405 CONTINUE : "continue" %prec prec_none {
2406 $$ = abc___continue__(0, "");
2408 CONTINUE : "continue" T_IDENTIFIER {
2409 $$ = abc___continue__(0, $2);
2412 MAYBE_CASE_LIST : {$$=0;}
2413 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2414 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2415 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2416 CASE_LIST: CASE {$$=$1;}
2417 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2419 CASE: "case" E ':' MAYBECODE {
2420 $$ = abc_getlocal(0, state->switch_var);
2421 $$ = code_append($$, $2.c);
2422 code_t*j = $$ = abc_ifne($$, 0);
2423 $$ = code_append($$, $4);
2424 if($$->opcode != OPCODE___BREAK__) {
2425 $$ = abc___fallthrough__($$, "");
2427 code_t*e = $$ = abc_nop($$);
2430 DEFAULT: "default" ':' MAYBECODE {
2433 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2435 $$ = abc_setlocal($$, state->switch_var);
2436 $$ = code_append($$, $7);
2438 code_t*out = $$ = abc_kill($$, state->switch_var);
2439 breakjumpsto($$, $1, out);
2441 code_t*c = $$,*lastblock=0;
2443 if(c->opcode == OPCODE_IFNE) {
2444 if(!c->next) syntaxerror("internal error in fallthrough handling");
2446 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2448 c->opcode = OPCODE_JUMP;
2449 c->branch = lastblock;
2451 /* fall through end of switch */
2452 c->opcode = OPCODE_NOP;
2462 /* ------------ try / catch /finally ---------------- */
2464 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2465 state->exception_name=$3;
2466 PASS1 new_variable($3, 0, 0, 0);
2467 PASS2 new_variable($3, $4, 0, 0);
2470 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2471 multiname_t name = {QNAME, &name_ns, 0, $3};
2473 NEW(abc_exception_t, e)
2474 e->exc_type = sig2mname($4);
2475 e->var_name = multiname_clone(&name);
2479 int i = find_variable_safe(state, $3)->index;
2480 e->target = c = abc_nop(0);
2481 c = abc_setlocal(c, i);
2482 c = code_append(c, code_dup(state->method->scope_code));
2483 c = code_append(c, $8);
2489 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2494 NEW(abc_exception_t, e)
2495 e->exc_type = 0; //all exceptions
2496 e->var_name = 0; //no name
2499 e->to = code_append(e->to, $4);
2505 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2506 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2507 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2508 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2512 list_append($$.l,$2);
2513 $$.finally = $2->to;$2->to=0;
2516 CATCH_FINALLY_LIST: FINALLY {
2520 list_append($$.l,$1);
2521 $$.finally = $1->to;$1->to=0;
2525 TRY : "try" '{' {PASS12 new_state();
2526 state->method->has_exceptions=1;
2527 state->method->late_binding=1;//for invariant scope_code
2528 } MAYBECODE '}' CATCH_FINALLY_LIST {
2529 code_t*out = abc_nop(0);
2531 code_t*start = abc_nop(0);
2532 $$ = code_append(start, $4);
2533 if(!is_break_or_jump($4)) {
2534 $$ = abc_jump($$, out);
2536 code_t*end = $$ = abc_nop($$);
2540 tmp = new_variable("__finally__", 0, 0, 0);
2542 abc_exception_list_t*l = $6.l;
2545 abc_exception_t*e = l->abc_exception;
2547 $$ = code_append($$, e->target);
2548 $$ = abc_jump($$, out);
2550 parserassert((ptroff_t)$6.finally);
2552 e->target = $$ = abc_nop($$);
2553 $$ = code_append($$, code_dup(state->method->scope_code));
2554 $$ = abc___rethrow__($$);
2562 $$ = code_append($$, out);
2564 $$ = insert_finally($$, $6.finally, tmp);
2566 list_concat(state->method->exceptions, $6.l);
2572 /* ------------ throw ------------------------------- */
2574 THROW : "throw" EXPRESSION {
2578 THROW : "throw" %prec prec_none {
2579 if(!state->exception_name)
2580 syntaxerror("re-throw only possible within a catch block");
2581 variable_t*v = find_variable(state, state->exception_name);
2583 $$=abc_getlocal($$, v->index);
2587 /* ------------ with -------------------------------- */
2589 WITH_HEAD : "with" '(' EXPRESSION ')' {
2591 if(state->method->has_exceptions) {
2592 int v = alloc_local();
2593 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2594 state->method->scope_code = abc_pushwith(state->method->scope_code);
2599 WITH : WITH_HEAD CODEBLOCK {
2600 /* remove getlocal;pushwith from scope code again */
2601 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2604 if(state->method->has_exceptions) {
2606 $$ = abc_setlocal($$, $1.number);
2608 $$ = abc_pushwith($$);
2609 $$ = code_append($$, $2);
2610 $$ = abc_popscope($$);
2614 /* ------------ packages and imports ---------------- */
2616 X_IDENTIFIER: T_IDENTIFIER
2617 | "package" {PASS12 $$="package";}
2618 | T_NAMESPACE {PASS12 $$=$1;}
2620 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2621 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2623 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2624 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2625 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2626 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2628 IMPORT : "import" PACKAGEANDCLASS {
2630 slotinfo_t*s = registry_find($2->package, $2->name);
2631 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2632 as3_schedule_class($2->package, $2->name);
2636 syntaxerror("Couldn't import class\n");
2637 state_has_imports();
2638 dict_put(state->imports, c->name, c);
2639 import_toplevel(c->package);
2642 IMPORT : "import" PACKAGE '.' '*' {
2644 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2645 as3_schedule_package($2);
2650 state_has_imports();
2651 list_append(state->wildcard_imports, i);
2652 import_toplevel(i->package);
2656 /* ------------ classes and interfaces (header) -------------- */
2658 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2659 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2660 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2661 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2663 $$.flags=$1.flags|$2.flags;
2664 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2665 $$.ns=$1.ns?$1.ns:$2.ns;
2668 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2669 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2670 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2671 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2672 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2673 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2674 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2675 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2676 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2677 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2681 EXTENDS : {PASS12 $$=0;}
2682 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2684 EXTENDS_LIST : {PASS12 $$=list_new();}
2685 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2687 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2688 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2690 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2691 EXTENDS IMPLEMENTS_LIST
2692 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2694 '}' {PASS12 endclass();$$=0;}
2696 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2698 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2699 startclass(&$1,$3,0,$4);}
2700 MAYBE_INTERFACE_BODY
2701 '}' {PASS12 endclass();$$=0;}
2703 /* ------------ classes and interfaces (body) -------------- */
2706 MAYBE_CLASS_BODY : CLASS_BODY
2707 CLASS_BODY : CLASS_BODY_ITEM
2708 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2709 CLASS_BODY_ITEM : ';'
2710 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}'
2711 CLASS_BODY_ITEM : SLOT_DECLARATION
2712 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2714 CLASS_BODY_ITEM : CODE_STATEMENT {
2715 code_t*c = state->cls->static_init->header;
2716 c = code_append(c, $1);
2717 state->cls->static_init->header = c;
2720 MAYBE_INTERFACE_BODY :
2721 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2722 INTERFACE_BODY : IDECLARATION
2723 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2725 IDECLARATION : "var" T_IDENTIFIER {
2726 syntaxerror("variable declarations not allowed in interfaces");
2728 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2730 $1.flags |= FLAG_PUBLIC;
2731 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2732 syntaxerror("invalid method modifiers: interface methods always need to be public");
2734 startfunction(&$1,$3,$4,&$6,$8);
2735 endfunction(&$1,$3,$4,&$6,$8, 0);
2736 list_deep_free($6.list);
2739 /* ------------ classes and interfaces (body, slots ) ------- */
2741 VARCONST: "var" | "const"
2743 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {setslotstate(&$1,$2);} SLOT_LIST {$$=$4;setslotstate(0, 0);}
2745 SLOT_LIST: ONE_SLOT {$$ = $1;}
2746 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {$$ = code_append($1, $3);}
2748 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2750 int flags = slotstate_flags->flags;
2751 namespace_t ns = modifiers2access(slotstate_flags);
2753 varinfo_t* info = 0;
2755 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2757 check_override(i, flags);
2759 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2761 slotinfo_t*i = registry_find(state->package, $1);
2763 syntaxerror("package %s already contains '%s'", state->package, $1);
2765 if(ns.name && ns.name[0]) {
2766 syntaxerror("namespaces not allowed on package-level variables");
2768 info = varinfo_register_global(ns.access, state->package, $1);
2772 info->flags = flags;
2775 multiname_t mname = {QNAME, &ns, 0, $1};
2777 trait_list_t**traits;
2781 ns.name = state->package;
2782 traits = &global->init->traits;
2783 code = &global->init->method->body->code;
2784 } else if(flags&FLAG_STATIC) {
2786 traits = &state->cls->abc->static_traits;
2787 code = &state->cls->static_init->header;
2789 // instance variable
2790 traits = &state->cls->abc->traits;
2791 code = &state->cls->init->header;
2797 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2799 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2801 info->slot = t->slot_id;
2803 /* initalization code (if needed) */
2805 if($3.c && !is_pushundefined($3.c)) {
2806 c = abc_getlocal_0(c);
2807 c = code_append(c, $3.c);
2808 c = converttype(c, $3.t, $2);
2809 c = abc_setslot(c, t->slot_id);
2812 *code = code_append(*code, c);
2814 if(slotstate_varconst==KW_CONST) {
2815 t->kind= TRAIT_CONST;
2821 /* ------------ constants -------------------------------------- */
2823 MAYBESTATICCONSTANT: {$$=0;}
2824 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2826 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2827 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2828 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2829 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2830 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2831 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2832 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2833 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2834 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2835 STATICCONSTANT : T_IDENTIFIER {
2836 if(!strcmp($1, "NaN")) {
2837 $$ = constant_new_float(__builtin_nan(""));
2839 as3_warning("Couldn't evaluate constant value of %s", $1);
2840 $$ = constant_new_null($1);
2844 /* ------------ classes and interfaces (body, functions) ------- */
2846 // non-vararg version
2849 memset(&$$,0,sizeof($$));
2851 MAYBE_PARAM_LIST: PARAM_LIST {
2857 MAYBE_PARAM_LIST: "..." PARAM {
2859 memset(&$$,0,sizeof($$));
2861 list_append($$.list, $2);
2863 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2867 list_append($$.list, $4);
2871 PARAM_LIST: PARAM_LIST ',' PARAM {
2874 list_append($$.list, $3);
2878 memset(&$$,0,sizeof($$));
2879 list_append($$.list, $1);
2882 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2884 $$ = rfx_calloc(sizeof(param_t));
2890 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2892 $$ = rfx_calloc(sizeof(param_t));
2894 $$->type = TYPE_ANY;
2902 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2903 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2906 endfunction(&$1,$3,$4,&$6,0,0);
2908 if(!state->method->info) syntaxerror("internal error");
2910 code_t*c = method_header(state->method);
2911 c = wrap_function(c, 0, $11);
2913 endfunction(&$1,$3,$4,&$6,$8,c);
2915 list_deep_free($6.list);
2919 MAYBE_IDENTIFIER: T_IDENTIFIER
2920 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2921 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2922 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2925 endfunction(0,0,$2,&$4,0,0);
2927 methodinfo_t*f = state->method->info;
2928 if(!f || !f->kind) syntaxerror("internal error");
2930 code_t*c = method_header(state->method);
2931 c = wrap_function(c, 0, $9);
2933 int index = state->method->var_index;
2934 endfunction(0,0,$2,&$4,$6,c);
2936 $$.c = abc_getlocal(0, index);
2937 $$.t = TYPE_FUNCTION(f);
2939 PASS12 list_deep_free($4.list);
2943 /* ------------- package + class ids --------------- */
2945 CLASS: X_IDENTIFIER {
2946 PASS1 NEW(unresolvedinfo_t,c);
2947 memset(c, 0, sizeof(*c));
2948 c->kind = INFOTYPE_UNRESOLVED;
2950 c->package = get_package_from_name($1);
2952 c->nsset = get_current_imports();
2953 /* make the compiler look for this class in the current directory,
2955 //as3_schedule_class_noerror(state->package, $1);
2957 $$ = (classinfo_t*)c;
2959 slotinfo_t*s = find_class($1);
2960 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2961 $$ = (classinfo_t*)s;
2964 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2965 PASS1 NEW(unresolvedinfo_t,c);
2966 memset(c, 0, sizeof(*c));
2967 c->kind = INFOTYPE_UNRESOLVED;
2970 $$ = (classinfo_t*)c;
2972 slotinfo_t*s = registry_find($1, $3);
2973 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2975 $$ = (classinfo_t*)s;
2978 CLASS_SPEC: PACKAGEANDCLASS
2981 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2982 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2984 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2985 | '*' {PASS12 $$=registry_getanytype();}
2986 | "void" {PASS12 $$=registry_getanytype();}
2988 | "String" {$$=registry_getstringclass();}
2989 | "int" {$$=registry_getintclass();}
2990 | "uint" {$$=registry_getuintclass();}
2991 | "Boolean" {$$=registry_getbooleanclass();}
2992 | "Number" {$$=registry_getnumberclass();}
2995 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2996 MAYBETYPE: {PASS12 $$=0;}
2998 /* ----------function calls, delete, constructor calls ------ */
3000 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3001 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3003 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3004 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3005 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3007 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3011 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3012 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3013 $$.number= $1.number+1;
3014 $$.cc = code_append($1.cc, $2.c);
3018 NEW : "new" E XX MAYBE_PARAM_VALUES {
3020 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3022 code_t*paramcode = $4.cc;
3023 if($$.c->opcode == OPCODE_GETPROPERTY) {
3024 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3025 $$.c = code_cutlast($$.c);
3026 $$.c = code_append($$.c, paramcode);
3027 $$.c = abc_constructprop2($$.c, name, $4.number);
3028 multiname_destroy(name);
3029 } else if($$.c->opcode == OPCODE_GETSLOT) {
3030 int slot = (int)(ptroff_t)$$.c->data[0];
3031 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3032 multiname_t*name = t->name;
3033 $$.c = code_cutlast($$.c);
3034 $$.c = code_append($$.c, paramcode);
3035 $$.c = abc_constructprop2($$.c, name, $4.number);
3037 $$.c = code_append($$.c, paramcode);
3038 $$.c = abc_construct($$.c, $4.number);
3042 if(TYPE_IS_CLASS($2.t) && $2.t->data) {
3045 $$.c = abc_coerce_a($$.c);
3050 /* TODO: use abc_call (for calling local variables),
3051 abc_callstatic (for calling own methods)
3054 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3057 if($$.c->opcode == OPCODE_COERCE_A) {
3058 $$.c = code_cutlast($$.c);
3060 code_t*paramcode = $3.cc;
3063 if($$.c->opcode == OPCODE_GETPROPERTY) {
3064 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3065 $$.c = code_cutlast($$.c);
3066 $$.c = code_append($$.c, paramcode);
3067 $$.c = abc_callproperty2($$.c, name, $3.number);
3068 multiname_destroy(name);
3069 } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3070 int slot = (int)(ptroff_t)$$.c->data[0];
3071 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3072 if(t->kind!=TRAIT_METHOD) {
3073 //ok: flash allows to assign closures to members.
3075 multiname_t*name = t->name;
3076 $$.c = code_cutlast($$.c);
3077 $$.c = code_append($$.c, paramcode);
3078 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3079 $$.c = abc_callproperty2($$.c, name, $3.number);
3080 } else if($$.c->opcode == OPCODE_GETSUPER) {
3081 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3082 $$.c = code_cutlast($$.c);
3083 $$.c = code_append($$.c, paramcode);
3084 $$.c = abc_callsuper2($$.c, name, $3.number);
3085 multiname_destroy(name);
3087 $$.c = abc_getglobalscope($$.c);
3088 $$.c = code_append($$.c, paramcode);
3089 $$.c = abc_call($$.c, $3.number);
3092 if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
3093 $$.t = ((methodinfo_t*)($1.t->data))->return_type;
3095 $$.c = abc_coerce_a($$.c);
3100 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3101 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3102 if(!state->method) syntaxerror("super() not allowed outside of a function");
3103 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3106 $$.c = abc_getlocal_0($$.c);
3108 $$.c = code_append($$.c, $3.cc);
3110 this is dependent on the control path, check this somewhere else
3111 if(state->method->has_super)
3112 syntaxerror("constructor may call super() only once");
3114 state->method->has_super = 1;
3116 $$.c = abc_constructsuper($$.c, $3.number);
3117 $$.c = abc_pushundefined($$.c);
3121 DELETE: "delete" E {
3123 if($$.c->opcode == OPCODE_COERCE_A) {
3124 $$.c = code_cutlast($$.c);
3126 multiname_t*name = 0;
3127 if($$.c->opcode == OPCODE_GETPROPERTY) {
3128 $$.c->opcode = OPCODE_DELETEPROPERTY;
3129 } else if($$.c->opcode == OPCODE_GETSLOT) {
3130 int slot = (int)(ptroff_t)$$.c->data[0];
3131 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3132 $$.c = code_cutlast($$.c);
3133 $$.c = abc_deleteproperty2($$.c, name);
3135 $$.c = abc_getlocal_0($$.c);
3136 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
3137 $$.c = abc_deleteproperty2($$.c, &m);
3139 $$.t = TYPE_BOOLEAN;
3142 RETURN: "return" %prec prec_none {
3143 $$ = abc_returnvoid(0);
3145 RETURN: "return" EXPRESSION {
3147 $$ = abc_returnvalue($$);
3150 // ----------------------- expression types -------------------------------------
3152 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
3153 EXPRESSION : E %prec below_minus {$$ = $1;}
3154 EXPRESSION : EXPRESSION ',' E %prec below_minus {
3156 $$.c = cut_last_push($$.c);
3157 $$.c = code_append($$.c,$3.c);
3160 VOIDEXPRESSION : EXPRESSION %prec below_minus {
3161 $$=cut_last_push($1.c);
3164 // ----------------------- expression evaluation -------------------------------------
3166 E : INNERFUNCTION %prec prec_none {$$ = $1;}
3167 //V : CONSTANT {$$ = 0;}
3169 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
3170 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3171 //V : NEW {$$ = $1.c;}
3173 //V : DELETE {$$ = $1.c;}
3174 E : DELETE {$$ = $1;}
3180 namespace_t ns = {ACCESS_PACKAGE, ""};
3181 multiname_t m = {QNAME, &ns, 0, "RegExp"};
3183 $$.c = abc_getlex2($$.c, &m);
3184 $$.c = abc_pushstring($$.c, $1.pattern);
3185 $$.c = abc_construct($$.c, 1);
3187 $$.c = abc_getlex2($$.c, &m);
3188 $$.c = abc_pushstring($$.c, $1.pattern);
3189 $$.c = abc_pushstring($$.c, $1.options);
3190 $$.c = abc_construct($$.c, 2);
3195 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
3196 //MULTINAME(m, registry_getintclass());
3197 //$$.c = abc_coerce2($$.c, &m); // FIXME
3200 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
3203 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
3206 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
3209 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
3212 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
3215 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
3218 CONSTANT : "true" {$$.c = abc_pushtrue(0);
3219 $$.t = TYPE_BOOLEAN;
3221 CONSTANT : "false" {$$.c = abc_pushfalse(0);
3222 $$.t = TYPE_BOOLEAN;
3224 CONSTANT : "null" {$$.c = abc_pushnull(0);
3228 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
3229 $$.t = TYPE_BOOLEAN;
3231 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
3232 $$.t = TYPE_BOOLEAN;
3234 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
3235 $$.t = TYPE_BOOLEAN;
3237 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
3238 $$.t = TYPE_BOOLEAN;
3240 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
3241 $$.t = TYPE_BOOLEAN;
3243 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
3244 $$.t = TYPE_BOOLEAN;
3246 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
3247 $$.t = TYPE_BOOLEAN;
3249 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
3250 $$.t = TYPE_BOOLEAN;
3253 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
3255 $$.c = converttype($$.c, $1.t, $$.t);
3256 $$.c = abc_dup($$.c);
3257 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
3258 $$.c = cut_last_push($$.c);
3259 $$.c = code_append($$.c,$3.c);
3260 $$.c = converttype($$.c, $3.t, $$.t);
3261 code_t*label = $$.c = abc_label($$.c);
3262 jmp->branch = label;
3265 $$.t = join_types($1.t, $3.t, 'A');
3266 /*printf("%08x:\n",$1.t);
3267 code_dump($1.c, 0, 0, "", stdout);
3268 printf("%08x:\n",$3.t);
3269 code_dump($3.c, 0, 0, "", stdout);
3270 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
3272 $$.c = converttype($$.c, $1.t, $$.t);
3273 $$.c = abc_dup($$.c);
3274 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
3275 $$.c = cut_last_push($$.c);
3276 $$.c = code_append($$.c,$3.c);
3277 $$.c = converttype($$.c, $3.t, $$.t);
3278 code_t*label = $$.c = abc_label($$.c);
3279 jmp->branch = label;
3282 E : '!' E {$$.c=$2.c;
3283 $$.c = abc_not($$.c);
3284 $$.t = TYPE_BOOLEAN;
3287 E : '~' E {$$.c=$2.c;
3288 $$.c = abc_bitnot($$.c);
3292 E : E '&' E {$$.c = code_append($1.c,$3.c);
3293 $$.c = abc_bitand($$.c);
3297 E : E '^' E {$$.c = code_append($1.c,$3.c);
3298 $$.c = abc_bitxor($$.c);
3302 E : E '|' E {$$.c = code_append($1.c,$3.c);
3303 $$.c = abc_bitor($$.c);
3307 E : E ">>" E {$$.c = code_append($1.c,$3.c);
3308 $$.c = abc_rshift($$.c);
3311 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
3312 $$.c = abc_urshift($$.c);
3315 E : E "<<" E {$$.c = code_append($1.c,$3.c);
3316 $$.c = abc_lshift($$.c);
3320 E : E '/' E {$$.c = code_append($1.c,$3.c);
3321 $$.c = abc_divide($$.c);
3324 E : E '%' E {$$.c = code_append($1.c,$3.c);
3325 $$.c = abc_modulo($$.c);
3328 E : E '+' E {$$.c = code_append($1.c,$3.c);
3329 if(BOTH_INT($1.t, $3.t)) {
3330 $$.c = abc_add_i($$.c);
3333 $$.c = abc_add($$.c);
3334 $$.t = join_types($1.t,$3.t,'+');
3337 E : E '-' E {$$.c = code_append($1.c,$3.c);
3338 if(BOTH_INT($1.t,$3.t)) {
3339 $$.c = abc_subtract_i($$.c);
3342 $$.c = abc_subtract($$.c);
3346 E : E '*' E {$$.c = code_append($1.c,$3.c);
3347 if(BOTH_INT($1.t,$3.t)) {
3348 $$.c = abc_multiply_i($$.c);
3351 $$.c = abc_multiply($$.c);
3356 E : E "in" E {$$.c = code_append($1.c,$3.c);
3357 $$.c = abc_in($$.c);
3358 $$.t = TYPE_BOOLEAN;
3361 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
3362 if(use_astype && TYPE_IS_CLASS($3.t) && $3.t->data) {
3363 MULTINAME(m, (classinfo_t*)($3.t->data));
3364 $$.c = abc_astype2($1.c, &m);
3367 $$.c = code_append($1.c, $3.c);
3368 $$.c = abc_astypelate($$.c);
3373 E : E "instanceof" E
3374 {$$.c = code_append($1.c, $3.c);
3375 $$.c = abc_instanceof($$.c);
3376 $$.t = TYPE_BOOLEAN;
3379 E : E "is" E {$$.c = code_append($1.c, $3.c);
3380 $$.c = abc_istypelate($$.c);
3381 $$.t = TYPE_BOOLEAN;
3384 E : "typeof" '(' E ')' {
3386 $$.c = abc_typeof($$.c);
3391 $$.c = cut_last_push($2.c);
3392 $$.c = abc_pushundefined($$.c);
3396 E : "void" { $$.c = abc_pushundefined(0);
3400 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
3405 $$.c=abc_negate_i($$.c);
3408 $$.c=abc_negate($$.c);
3415 $$.c = code_append($$.c, $3.c);
3417 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
3418 $$.c = abc_getproperty2($$.c, &m);
3419 $$.t = 0; // array elements have unknown type
3422 E : '[' MAYBE_EXPRESSION_LIST ']' {
3424 $$.c = code_append($$.c, $2.cc);
3425 $$.c = abc_newarray($$.c, $2.number);
3426 $$.t = registry_getarrayclass();
3429 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3430 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
3432 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3434 $$.cc = code_append($$.cc, $1.c);
3435 $$.cc = code_append($$.cc, $3.c);
3438 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3440 $$.number = $1.number+2;
3441 $$.cc = code_append($$.cc, $3.c);
3442 $$.cc = code_append($$.cc, $5.c);
3447 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
3449 $$.c = code_append($$.c, $2.cc);
3450 $$.c = abc_newobject($$.c, $2.number/2);
3451 $$.t = registry_getobjectclass();
3456 if(BOTH_INT($1.t,$3.t)) {
3457 c=abc_multiply_i(c);
3461 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
3462 $$.c = toreadwrite($1.c, c, 0, 0);
3467 code_t*c = abc_modulo($3.c);
3468 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
3469 $$.c = toreadwrite($1.c, c, 0, 0);
3473 code_t*c = abc_lshift($3.c);
3474 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
3475 $$.c = toreadwrite($1.c, c, 0, 0);
3479 code_t*c = abc_rshift($3.c);
3480 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
3481 $$.c = toreadwrite($1.c, c, 0, 0);
3485 code_t*c = abc_urshift($3.c);
3486 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
3487 $$.c = toreadwrite($1.c, c, 0, 0);
3491 code_t*c = abc_divide($3.c);
3492 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
3493 $$.c = toreadwrite($1.c, c, 0, 0);
3497 code_t*c = abc_bitor($3.c);
3498 c=converttype(c, TYPE_INT, $1.t);
3499 $$.c = toreadwrite($1.c, c, 0, 0);
3503 code_t*c = abc_bitxor($3.c);
3504 c=converttype(c, TYPE_INT, $1.t);
3505 $$.c = toreadwrite($1.c, c, 0, 0);
3511 if(TYPE_IS_INT($1.t)) {
3515 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
3518 $$.c = toreadwrite($1.c, c, 0, 0);
3521 E : E "-=" E { code_t*c = $3.c;
3522 if(TYPE_IS_INT($1.t)) {
3523 c=abc_subtract_i(c);
3526 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
3529 $$.c = toreadwrite($1.c, c, 0, 0);
3532 E : E '=' E { code_t*c = 0;
3533 c = code_append(c, $3.c);
3534 c = converttype(c, $3.t, $1.t);
3535 $$.c = toreadwrite($1.c, c, 1, 0);
3539 E : E '?' E ':' E %prec below_assignment {
3540 $$.t = join_types($3.t,$5.t,'?');
3542 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
3543 $$.c = code_append($$.c, $3.c);
3544 $$.c = converttype($$.c, $3.t, $$.t);
3545 code_t*j2 = $$.c = abc_jump($$.c, 0);
3546 $$.c = j1->branch = abc_label($$.c);
3547 $$.c = code_append($$.c, $5.c);
3548 $$.c = converttype($$.c, $5.t, $$.t);
3549 $$.c = j2->branch = abc_label($$.c);
3552 E : E "++" { code_t*c = 0;
3553 classinfo_t*type = $1.t;
3554 if(is_getlocal($1.c) && (TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t))) {
3555 int nr = getlocalnr($1.c);
3556 code_free($1.c);$1.c=0;
3557 if(TYPE_IS_INT($1.t)) {
3558 $$.c = abc_getlocal(0, nr);
3559 $$.c = abc_inclocal_i($$.c, nr);
3560 } else if(TYPE_IS_NUMBER($1.t)) {
3561 $$.c = abc_getlocal(0, nr);
3562 $$.c = abc_inclocal($$.c, nr);
3563 } else syntaxerror("internal error");
3565 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3566 c=abc_increment_i(c);
3572 c=converttype(c, type, $1.t);
3573 $$.c = toreadwrite($1.c, c, 0, 1);
3578 // TODO: use inclocal, like with ++
3579 E : E "--" { code_t*c = 0;
3580 classinfo_t*type = $1.t;
3581 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3582 c=abc_decrement_i(c);
3588 c=converttype(c, type, $1.t);
3589 $$.c = toreadwrite($1.c, c, 0, 1);
3593 E : "++" %prec plusplus_prefix E { code_t*c = 0;
3594 classinfo_t*type = $2.t;
3595 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3596 c=abc_increment_i(c);
3602 c=converttype(c, type, $2.t);
3603 $$.c = toreadwrite($2.c, c, 0, 0);
3607 E : "--" %prec minusminus_prefix E { code_t*c = 0;
3608 classinfo_t*type = $2.t;
3609 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3610 c=abc_decrement_i(c);
3616 c=converttype(c, type, $2.t);
3617 $$.c = toreadwrite($2.c, c, 0, 0);
3621 E : "super" '.' T_IDENTIFIER
3622 { if(!state->cls->info)
3623 syntaxerror("super keyword not allowed outside a class");
3624 classinfo_t*t = state->cls->info->superclass;
3625 if(!t) t = TYPE_OBJECT;
3627 memberinfo_t*f = findmember_nsset(t, $3, 1);
3629 MEMBER_MULTINAME(m, f, $3);
3631 $$.c = abc_getlocal_0($$.c);
3632 $$.c = abc_getsuper2($$.c, &m);
3633 $$.t = slotinfo_gettype((slotinfo_t*)f);
3636 E : '@' T_IDENTIFIER {
3638 $$.c = abc_pushundefined(0);
3640 as3_warning("ignored @ operator");
3643 E : E '.' '@' T_IDENTIFIER {
3644 // child attribute TODO
3645 $$.c = abc_pushundefined(0);
3647 as3_warning("ignored .@ operator");
3650 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3651 // namespace declaration TODO
3652 $$.c = abc_pushundefined(0);
3654 as3_warning("ignored :: operator");
3657 E : E ".." T_IDENTIFIER {
3659 $$.c = abc_pushundefined(0);
3661 as3_warning("ignored .. operator");
3664 E : E '.' '(' E ')' {
3666 $$.c = abc_pushundefined(0);
3668 as3_warning("ignored .() operator");
3671 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
3675 E : E '.' T_IDENTIFIER {
3677 classinfo_t*t = $1.t;
3679 if(TYPE_IS_CLASS(t) && t->data) {
3684 if(t->subtype==INFOTYPE_UNRESOLVED) {
3685 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3687 memberinfo_t*f = findmember_nsset(t, $3, 1);
3689 if(f && !is_static != !(f->flags&FLAG_STATIC))
3691 if(f && f->slot && !noslot) {
3692 $$.c = abc_getslot($$.c, f->slot);
3694 MEMBER_MULTINAME(m, f, $3);
3695 $$.c = abc_getproperty2($$.c, &m);
3697 /* determine type */
3698 $$.t = slotinfo_gettype((slotinfo_t*)f);
3700 $$.c = abc_coerce_a($$.c);
3701 } else if($1.c && $1.c->opcode == OPCODE___PUSHPACKAGE__) {
3702 string_t*package = $1.c->data[0];
3703 char*package2 = concat3(package->str, ".", $3);
3705 slotinfo_t*a = registry_find(package->str, $3);
3708 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3709 registry_ispackage(package2)) {
3711 $$.c->data[0] = string_new4(package2);
3714 syntaxerror("couldn't resolve %s", package2);
3717 /* when resolving a property on an unknown type, we do know the
3718 name of the property (and don't seem to need the package), but
3719 we need to make avm2 try out all access modes */
3720 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3721 $$.c = abc_getproperty2($$.c, &m);
3722 $$.c = abc_coerce_a($$.c);
3723 $$.t = registry_getanytype();
3727 VAR_READ : T_IDENTIFIER {
3729 /* Queue unresolved identifiers for checking against the parent
3730 function's variables.
3731 We consider everything which is not a local variable "unresolved".
3732 This encompasses class names, members of the surrounding class
3733 etc. which is *correct* because local variables of the parent function
3736 if(state->method->inner && !find_variable(state, $1)) {
3737 unknown_variable($1);
3740 /* let the compiler know that it might want to check the current directory/package
3741 for this identifier- maybe there's a file $1.as defining $1. */
3742 //as3_schedule_class_noerror(state->package, $1);
3751 /* look at variables */
3752 if((v = find_variable(state, $1))) {
3753 // $1 is a local variable
3754 $$.c = abc_getlocal($$.c, v->index);
3758 if((v = find_slot(state, $1))) {
3759 $$.c = abc_getscopeobject($$.c, 1);
3760 $$.c = abc_getslot($$.c, v->index);
3765 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3767 /* look at current class' members */
3768 if(!state->method->inner &&
3770 (f = findmember_nsset(state->cls->info, $1, 1)) &&
3771 (f->flags&FLAG_STATIC) >= i_am_static)
3773 // $1 is a function in this class
3774 int var_is_static = (f->flags&FLAG_STATIC);
3776 if(f->kind == INFOTYPE_METHOD) {
3777 $$.t = TYPE_FUNCTION(f);
3781 if(var_is_static && !i_am_static) {
3782 /* access to a static member from a non-static location.
3783 do this via findpropstrict:
3784 there doesn't seem to be any non-lookup way to access
3785 static properties of a class */
3786 state->method->late_binding = 1;
3788 namespace_t ns = {f->access, ""};
3789 multiname_t m = {QNAME, &ns, 0, $1};
3790 $$.c = abc_findpropstrict2($$.c, &m);
3791 $$.c = abc_getproperty2($$.c, &m);
3793 } else if(f->slot>0) {
3794 $$.c = abc_getlocal_0($$.c);
3795 $$.c = abc_getslot($$.c, f->slot);
3798 namespace_t ns = {f->access, ""};
3799 multiname_t m = {QNAME, &ns, 0, $1};
3800 $$.c = abc_getlocal_0($$.c);
3801 $$.c = abc_getproperty2($$.c, &m);
3806 /* look at actual classes, in the current package and imported */
3807 if((a = find_class($1))) {
3812 /* look through package prefixes */
3813 if(dict_contains(state->import_toplevel_packages, $1) ||
3814 registry_ispackage($1)) {
3815 $$.c = abc___pushpackage__($$.c, $1);
3820 /* unknown object, let the avm2 resolve it */
3822 //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3823 as3_warning("Couldn't resolve '%s', doing late binding", $1);
3824 state->method->late_binding = 1;
3826 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3829 $$.c = abc_findpropstrict2($$.c, &m);
3830 $$.c = abc_getproperty2($$.c, &m);
3834 // ----------------- namespaces -------------------------------------------------
3836 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3838 NEW(namespace_decl_t,n);
3843 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3845 NEW(namespace_decl_t,n);
3850 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3852 NEW(namespace_decl_t,n);
3857 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3859 trie_put(active_namespaces, $2->name, (void*)$2->url);
3861 namespace_t access = modifiers2access(&$1);
3862 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3863 var->type = TYPE_NAMESPACE;
3865 ns.access = ACCESS_NAMESPACE;
3867 var->value = constant_new_namespace(&ns);
3872 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3874 const char*url = $3->name;
3875 varinfo_t*s = (varinfo_t*)$3;
3876 if(!s || s->kind != INFOTYPE_SLOT)
3877 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3878 if(!s->value || !NS_TYPE(s->value->type))
3879 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3880 url = s->value->ns->name;
3882 trie_put(active_namespaces, $3->name, (void*)url);
3883 add_active_url(url);