3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
31 #include "tokenizer.h"
46 enum yytokentype token;
48 classinfo_t*classinfo;
49 classinfo_list_t*classinfo_list;
51 slotinfo_list_t*slotinfo_list;
54 unsigned int number_uint;
58 //typedcode_list_t*value_list;
59 codeandnumber_t value_list;
65 for_start_t for_start;
66 abc_exception_t *exception;
69 namespace_decl_t* namespace_decl;
71 abc_exception_list_t *l;
77 %token<id> T_IDENTIFIER T_NAMESPACE
79 %token<regexp> T_REGEXP
81 %token<number_int> T_INT
82 %token<number_uint> T_UINT
83 %token<number_uint> T_BYTE
84 %token<number_uint> T_SHORT
85 %token<number_float> T_FLOAT
87 %token<id> T_FOR "for"
88 %token<id> T_WHILE "while"
90 %token<id> T_SWITCH "switch"
92 %token<token> KW_IMPLEMENTS "implements"
93 %token<token> KW_NAMESPACE "namespace"
94 %token<token> KW_PACKAGE "package"
95 %token<token> KW_PROTECTED "protected"
96 %token<token> KW_PUBLIC "public"
97 %token<token> KW_PRIVATE "private"
98 %token<token> KW_USE "use"
99 %token<token> KW_INTERNAL "internal"
100 %token<token> KW_NEW "new"
101 %token<token> KW_NATIVE "native"
102 %token<token> KW_FUNCTION "function"
103 %token<token> KW_FINALLY "finally"
104 %token<token> KW_UNDEFINED "undefined"
105 %token<token> KW_CONTINUE "continue"
106 %token<token> KW_CLASS "class"
107 %token<token> KW_CONST "const"
108 %token<token> KW_CATCH "catch"
109 %token<token> KW_CASE "case"
110 %token<token> KW_SET "set"
111 %token<token> KW_VOID "void"
112 %token<token> KW_THROW "throw"
113 %token<token> KW_STATIC "static"
114 %token<token> KW_WITH "with"
115 %token<token> KW_INSTANCEOF "instanceof"
116 %token<token> KW_IMPORT "import"
117 %token<token> KW_RETURN "return"
118 %token<token> KW_TYPEOF "typeof"
119 %token<token> KW_INTERFACE "interface"
120 %token<token> KW_NULL "null"
121 %token<token> KW_VAR "var"
122 %token<token> KW_DYNAMIC "dynamic"
123 %token<token> KW_OVERRIDE "override"
124 %token<token> KW_FINAL "final"
125 %token<token> KW_EACH "each"
126 %token<token> KW_GET "get"
127 %token<token> KW_TRY "try"
128 %token<token> KW_SUPER "super"
129 %token<token> KW_EXTENDS "extends"
130 %token<token> KW_FALSE "false"
131 %token<token> KW_TRUE "true"
132 %token<token> KW_BOOLEAN "Boolean"
133 %token<token> KW_UINT "uint"
134 %token<token> KW_INT "int"
135 %token<token> KW_NUMBER "Number"
136 %token<token> KW_STRING "String"
137 %token<token> KW_DEFAULT "default"
138 %token<token> KW_DELETE "delete"
139 %token<token> KW_IF "if"
140 %token<token> KW_ELSE "else"
141 %token<token> KW_BREAK "break"
142 %token<token> KW_IS "is"
143 %token<token> KW_IN "in"
144 %token<token> KW_AS "as"
146 %token<token> T_DICTSTART "{ (dictionary)"
147 %token<token> T_EQEQ "=="
148 %token<token> T_EQEQEQ "==="
149 %token<token> T_NE "!="
150 %token<token> T_NEE "!=="
151 %token<token> T_LE "<="
152 %token<token> T_GE ">="
153 %token<token> T_ORBY "|="
154 %token<token> T_DIVBY "/="
155 %token<token> T_MODBY "%="
156 %token<token> T_MULBY "*="
157 %token<token> T_PLUSBY "+="
158 %token<token> T_MINUSBY "-="
159 %token<token> T_XORBY "^="
160 %token<token> T_SHRBY ">>="
161 %token<token> T_SHLBY "<<="
162 %token<token> T_USHRBY ">>>="
163 %token<token> T_OROR "||"
164 %token<token> T_ANDAND "&&"
165 %token<token> T_COLONCOLON "::"
166 %token<token> T_MINUSMINUS "--"
167 %token<token> T_PLUSPLUS "++"
168 %token<token> T_DOTDOT ".."
169 %token<token> T_DOTDOTDOT "..."
170 %token<token> T_SHL "<<"
171 %token<token> T_USHR ">>>"
172 %token<token> T_SHR ">>"
174 %type <number_int> CONDITIONAL_COMPILATION
175 %type <for_start> FOR_START
176 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
177 %type <namespace_decl> NAMESPACE_ID
178 %type <token> VARCONST
180 %type <code> CODEPIECE CODE_STATEMENT
181 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
182 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
183 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
184 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
185 %type <exception> CATCH FINALLY
186 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
187 %type <code> CLASS_DECLARATION
188 %type <code> NAMESPACE_DECLARATION
189 %type <code> INTERFACE_DECLARATION
190 %type <code> VOIDEXPRESSION
191 %type <value> EXPRESSION NONCOMMAEXPRESSION
192 %type <value> MAYBEEXPRESSION
193 %type <value> E DELETE
194 %type <value> CONSTANT
195 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
196 %type <value> INNERFUNCTION
197 %type <code> USE_NAMESPACE
198 %type <code> FOR_INIT
200 %type <classinfo> MAYBETYPE
203 %type <params> PARAM_LIST
204 %type <params> MAYBE_PARAM_LIST
205 %type <flags> MAYBE_MODIFIERS
206 %type <flags> MODIFIER_LIST
207 %type <flags> MODIFIER
208 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
209 %type <classinfo_list> IMPLEMENTS_LIST
210 %type <classinfo> EXTENDS CLASS_SPEC
211 %type <classinfo_list> EXTENDS_LIST
213 %type <classinfo> CLASS PACKAGEANDCLASS
214 %type <classinfo_list> CLASS_SPEC_LIST
216 %type <classinfo> TYPE
217 //%type <token> VARIABLE
218 %type <value> VAR_READ
220 //%type <token> T_IDENTIFIER
221 %type <value> FUNCTIONCALL
222 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST WITH_HEAD
224 // precedence: from low to high
228 %left below_semicolon
231 %nonassoc below_assignment // for ?:, contrary to spec
232 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
239 %nonassoc "==" "!=" "===" "!=="
240 %nonassoc "is" "as" "in"
241 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
242 %left "<<" ">>" ">>>"
246 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
248 %nonassoc below_curly
252 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
255 %left above_identifier
259 // needed for "return" precedence:
260 %nonassoc T_STRING T_REGEXP
261 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
262 %nonassoc "false" "true" "null" "undefined" "super" "function"
269 static int a3_error(char*s)
271 syntaxerror("%s", s);
272 return 0; //make gcc happy
275 static void parsererror(const char*file, int line, const char*f)
277 syntaxerror("internal error in %s, %s:%d", f, file, line);
280 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
283 static char* concat2(const char* t1, const char* t2)
287 char*text = malloc(l1+l2+1);
288 memcpy(text , t1, l1);
289 memcpy(text+l1, t2, l2);
293 static char* concat3(const char* t1, const char* t2, const char* t3)
298 char*text = malloc(l1+l2+l3+1);
299 memcpy(text , t1, l1);
300 memcpy(text+l1, t2, l2);
301 memcpy(text+l1+l2, t3, l3);
306 typedef struct _import {
309 DECLARE_LIST(import);
311 DECLARE(methodstate);
312 DECLARE_LIST(methodstate);
314 typedef struct _classstate {
320 methodstate_t*static_init;
322 //code_t*static_init;
324 char has_constructor;
327 struct _methodstate {
337 dict_t*unresolved_variables;
340 char uses_parent_function;
346 int var_index; // for inner methods
347 int slot_index; // for inner methods
348 char is_a_slot; // for inner methods
353 abc_exception_list_t*exceptions;
355 methodstate_list_t*innerfunctions;
358 typedef struct _state {
363 import_list_t*wildcard_imports;
364 dict_t*import_toplevel_packages;
367 namespace_list_t*active_namespace_urls;
369 char has_own_imports;
370 char new_vars; // e.g. transition between two functions
373 methodstate_t*method;
382 typedef struct _global {
386 dict_t*file2token2info;
389 static global_t*global = 0;
390 static state_t* state = 0;
394 #define MULTINAME(m,x) \
398 registry_fill_multiname(&m, &m##_ns, (slotinfo_t*)(x));
400 #define MEMBER_MULTINAME(m,f,n) \
404 if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
405 m##_ns.name = ((slotinfo_t*)(f))->package; \
410 m.namespace_set = 0; \
411 m.name = ((slotinfo_t*)(f))->name; \
413 m.type = MULTINAME; \
415 m.namespace_set = &nopackage_namespace_set; \
419 /* warning: list length of namespace set is undefined */
420 #define MULTINAME_LATE(m, access, package) \
421 namespace_t m##_ns = {access, package}; \
422 namespace_set_t m##_nsset; \
423 namespace_list_t m##_l;m##_l.next = 0; \
424 m##_nsset.namespaces = &m##_l; \
425 m##_nsset = m##_nsset; \
426 m##_l.namespace = &m##_ns; \
427 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
429 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
430 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
431 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
432 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
433 static namespace_list_t nl4 = {&ns4,0};
434 static namespace_list_t nl3 = {&ns3,&nl4};
435 static namespace_list_t nl2 = {&ns2,&nl3};
436 static namespace_list_t nl1 = {&ns1,&nl2};
437 static namespace_set_t nopackage_namespace_set = {&nl1};
439 static dict_t*definitions=0;
440 void as3_set_definition(const char*c)
443 definitions = dict_new();
444 if(!dict_contains(definitions,c))
445 dict_put(definitions,c,0);
448 static void new_state()
451 state_t*oldstate = state;
453 memcpy(s, state, sizeof(state_t)); //shallow copy
455 s->imports = dict_new();
457 if(!s->import_toplevel_packages) {
458 s->import_toplevel_packages = dict_new();
462 state->has_own_imports = 0;
463 state->vars = dict_new();
464 state->old = oldstate;
467 trie_remember(active_namespaces);
470 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
473 static void state_destroy(state_t*state)
475 if(state->has_own_imports) {
476 list_free(state->wildcard_imports);
477 dict_destroy(state->imports);state->imports=0;
479 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
480 dict_destroy(state->imports);state->imports=0;
484 for(t=0;t<state->vars->hashsize;t++) {
485 dictentry_t*e =state->vars->slots[t];
487 free(e->data);e->data=0;
491 dict_destroy(state->vars);state->vars=0;
494 list_free(state->active_namespace_urls)
495 state->active_namespace_urls = 0;
500 static void old_state()
502 trie_rollback(active_namespaces);
504 if(!state || !state->old)
505 syntaxerror("invalid nesting");
506 state_t*leaving = state;
510 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
511 free(leaving->method);
514 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
519 state_destroy(leaving);
522 static code_t* method_header(methodstate_t*m);
523 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
524 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
527 static char* internal_filename_package = 0;
528 void initialize_file(char*filename)
531 syntaxerror("invalid call to initialize_file during parsing of another file");
534 active_namespaces = trie_new();
537 state->package = internal_filename_package = strdup(filename);
539 global->token2info = dict_lookup(global->file2token2info,
540 current_filename // use long version
542 if(!global->token2info) {
543 global->token2info = dict_new2(&ptr_type);
544 dict_put(global->file2token2info, current_filename, global->token2info);
548 state->method = rfx_calloc(sizeof(methodstate_t));
549 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
550 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
552 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
553 function_initvars(state->method, 0, 0, 1);
554 global->init = abc_initscript(global->file);
560 if(!state || state->level!=1) {
561 syntaxerror("unexpected end of file in pass %d", as3_pass);
565 code_t*header = method_header(state->method);
566 code_t*c = wrap_function(header, 0, global->init->method->body->code);
567 global->init->method->body->code = c;
568 free(state->method);state->method=0;
571 //free(state->package);state->package=0; // used in registry
572 state_destroy(state);state=0;
575 void initialize_parser()
577 global = rfx_calloc(sizeof(global_t));
578 global->file = abc_file_new();
579 global->file->flags &= ~ABCFILE_LAZY;
580 global->file2token2info = dict_new();
581 global->token2info = 0;
584 void* finish_parser()
586 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
587 global->token2info=0;
591 typedef struct _variable {
596 methodstate_t*is_inner_method;
599 static variable_t* find_variable(state_t*s, char*name)
603 v = dict_lookup(s->vars, name);
605 if(s->new_vars) break;
610 static variable_t* find_slot(state_t*s, const char*name)
612 if(s->method && s->method->slots)
613 return dict_lookup(s->method->slots, name);
617 static variable_t* find_variable_safe(state_t*s, char*name)
619 variable_t* v = find_variable(s, name);
621 syntaxerror("undefined variable: %s", name);
625 static char variable_exists(char*name)
627 return dict_contains(state->vars, name);
630 static code_t*defaultvalue(code_t*c, classinfo_t*type)
632 if(TYPE_IS_INT(type)) {
633 c = abc_pushbyte(c, 0);
634 } else if(TYPE_IS_UINT(type)) {
635 c = abc_pushuint(c, 0);
636 } else if(TYPE_IS_FLOAT(type)) {
638 } else if(TYPE_IS_BOOLEAN(type)) {
639 c = abc_pushfalse(c);
641 //c = abc_pushundefined(c);
642 syntaxerror("internal error: can't generate default value for * type");
646 c = abc_coerce2(c, &m);
651 static int alloc_local()
653 return state->method->variable_count++;
656 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
659 variable_t*v = find_slot(state, name);
665 v->index = alloc_local();
670 dict_put(state->vars, name, v);
674 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
676 return new_variable2(name, type, init, maybeslot)->index;
679 #define TEMPVARNAME "__as3_temp__"
680 static int gettempvar()
682 variable_t*v = find_variable(state, TEMPVARNAME);
685 return new_variable(TEMPVARNAME, 0, 0, 0);
688 static code_t* var_block(code_t*body)
694 for(t=0;t<state->vars->hashsize;t++) {
695 dictentry_t*e = state->vars->slots[t];
697 variable_t*v = (variable_t*)e->data;
698 if(v->type && v->init) {
699 c = defaultvalue(c, v->type);
700 c = abc_setlocal(c, v->index);
701 k = abc_kill(k, v->index);
711 if(x->opcode== OPCODE___BREAK__ ||
712 x->opcode== OPCODE___CONTINUE__) {
713 /* link kill code before break/continue */
714 code_t*e = code_dup(k);
715 code_t*s = code_start(e);
727 c = code_append(c, body);
728 c = code_append(c, k);
732 static void unknown_variable(char*name)
734 if(!state->method->unresolved_variables)
735 state->method->unresolved_variables = dict_new();
736 if(!dict_contains(state->method->unresolved_variables, name))
737 dict_put(state->method->unresolved_variables, name, 0);
740 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
742 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
743 c = abc_getlocal_0(c);
744 c = abc_pushscope(c);
747 /* FIXME: this alloc_local() causes variable indexes to be
748 different in pass2 than in pass1 */
749 if(!m->activation_var)
750 m->activation_var = alloc_local();
752 c = abc_newactivation(c);
754 c = abc_pushscope(c);
755 c = abc_setlocal(c, m->activation_var);
757 c = abc_getlocal(c, m->activation_var);
758 c = abc_pushscope(c);
764 static code_t* method_header(methodstate_t*m)
768 c = add_scope_code(c, m, 1);
770 methodstate_list_t*l = m->innerfunctions;
772 parserassert(l->methodstate->abc);
773 if(m->uses_slots && l->methodstate->is_a_slot) {
774 c = abc_getscopeobject(c, 1);
775 c = abc_newfunction(c, l->methodstate->abc);
777 c = abc_setlocal(c, l->methodstate->var_index);
778 c = abc_setslot(c, l->methodstate->slot_index);
780 c = abc_newfunction(c, l->methodstate->abc);
781 c = abc_setlocal(c, l->methodstate->var_index);
783 free(l->methodstate);l->methodstate=0;
787 c = code_append(c, m->header);
790 if(m->is_constructor && !m->has_super) {
791 // call default constructor
792 c = abc_getlocal_0(c);
793 c = abc_constructsuper(c, 0);
797 /* all parameters that are used by inner functions
798 need to be copied from local to slot */
799 parserassert(m->activation_var);
800 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
801 if(v->is_parameter) {
802 c = abc_getlocal(c, m->activation_var);
803 c = abc_getlocal(c, v->index);
804 c = abc_setslot(c, v->index);
808 list_free(m->innerfunctions);
809 m->innerfunctions = 0;
814 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
816 c = code_append(c, header);
817 c = code_append(c, var_block(body));
818 /* append return if necessary */
819 if(!c || (c->opcode != OPCODE_RETURNVOID &&
820 c->opcode != OPCODE_RETURNVALUE)) {
821 c = abc_returnvoid(c);
826 static void startpackage(char*name)
829 state->package = strdup(name);
831 static void endpackage()
833 //used e.g. in classinfo_register:
834 //free(state->package);state->package=0;
838 #define FLAG_PUBLIC 256
839 #define FLAG_PROTECTED 512
840 #define FLAG_PRIVATE 1024
841 #define FLAG_PACKAGEINTERNAL 2048
842 #define FLAG_NAMESPACE 4096
844 static namespace_t modifiers2access(modifiers_t*mod)
849 if(mod->flags&FLAG_NAMESPACE) {
850 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
851 syntaxerror("invalid combination of access levels and namespaces");
852 ns.access = ACCESS_NAMESPACE;
854 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
856 /* shouldn't happen- the tokenizer only reports something as a namespace
857 if it was already registered */
858 trie_dump(active_namespaces);
859 syntaxerror("unknown namespace: %s", mod->ns);
862 } else if(mod->flags&FLAG_PUBLIC) {
863 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
864 syntaxerror("invalid combination of access levels");
865 ns.access = ACCESS_PACKAGE;
866 } else if(mod->flags&FLAG_PRIVATE) {
867 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
868 syntaxerror("invalid combination of access levels");
869 ns.access = ACCESS_PRIVATE;
870 } else if(mod->flags&FLAG_PROTECTED) {
871 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
872 syntaxerror("invalid combination of access levels");
873 ns.access = ACCESS_PROTECTED;
875 ns.access = ACCESS_PACKAGEINTERNAL;
879 static slotinfo_t* find_class(const char*name);
881 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
883 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
886 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
891 index = new_variable("this", 0, 0, 0);
892 else if(!m->is_global)
893 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
895 index = new_variable("globalscope", 0, 0, 0);
898 parserassert(!index);
902 /* as variables and slots share the same number, make sure
903 that those variable indices are reserved. It's up to the
904 optimizer to later shuffle the variables down to lower
906 m->variable_count = m->uses_slots;
911 for(p=params->list;p;p=p->next) {
912 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
917 methodstate_list_t*l = m->innerfunctions;
919 methodstate_t*m = l->methodstate;
921 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
922 m->var_index = v->index;
923 m->slot_index = v->index;
924 v->is_inner_method = m;
930 m->scope_code = add_scope_code(m->scope_code, m, 0);
933 if(as3_pass==2 && m->slots) {
934 /* exchange unresolved identifiers with the actual objects */
935 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
936 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
937 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
938 if(!type || type->kind != INFOTYPE_CLASS) {
939 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
948 char*as3_globalclass=0;
949 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
952 syntaxerror("inner classes now allowed");
957 classinfo_list_t*mlist=0;
959 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
960 syntaxerror("invalid modifier(s)");
962 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
963 syntaxerror("public and internal not supported at the same time.");
965 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
966 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
967 // all classes extend object
968 extends = registry_getobjectclass();
971 /* create the class name, together with the proper attributes */
975 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
976 access = ACCESS_PRIVATE; package = internal_filename_package;
977 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
978 access = ACCESS_PACKAGEINTERNAL; package = state->package;
979 } else if(state->package!=internal_filename_package) {
980 access = ACCESS_PACKAGE; package = state->package;
982 syntaxerror("public classes only allowed inside a package");
986 state->cls = rfx_calloc(sizeof(classstate_t));
987 state->cls->init = rfx_calloc(sizeof(methodstate_t));
988 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
989 /* notice: we make no effort to initialize the top variable (local0) here,
990 even though it has special meaning. We just rely on the facat
991 that pass 1 won't do anything with variables */
993 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
995 /* set current method to constructor- all code within the class-level (except
996 static variable initializations) will be executed during construction time */
997 state->method = state->cls->init;
999 if(registry_find(package, classname)) {
1000 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1002 /* build info struct */
1003 int num_interfaces = (list_length(implements));
1004 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1005 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1008 classinfo_list_t*l = implements;
1009 for(l=implements;l;l=l->next) {
1010 state->cls->info->interfaces[pos++] = l->classinfo;
1015 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1017 state->method = state->cls->init;
1018 parserassert(state->cls && state->cls->info);
1020 function_initvars(state->cls->init, 0, 0, 1);
1021 function_initvars(state->cls->static_init, 0, 0, 0);
1023 if(extends && (extends->flags & FLAG_FINAL))
1024 syntaxerror("Can't extend final class '%s'", extends->name);
1027 while(state->cls->info->interfaces[pos]) {
1028 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1029 syntaxerror("'%s' is not an interface",
1030 state->cls->info->interfaces[pos]->name);
1034 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
1035 state->cls->info->superclass = extends;
1037 /* generate the abc code for this class */
1038 MULTINAME(classname2,state->cls->info);
1039 multiname_t*extends2 = sig2mname(extends);
1041 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
1042 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1043 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1044 if(state->cls->info->flags&FLAG_INTERFACE) {
1045 abc_class_interface(state->cls->abc);
1048 abc_class_protectedNS(state->cls->abc, classname);
1050 for(mlist=implements;mlist;mlist=mlist->next) {
1051 MULTINAME(m, mlist->classinfo);
1052 abc_class_add_interface(state->cls->abc, &m);
1055 /* write the construction code for this class to the global init
1057 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
1059 abc_method_body_t*m = global->init->method->body;
1060 __ getglobalscope(m);
1061 classinfo_t*s = extends;
1066 //TODO: take a look at the current scope stack, maybe
1067 // we can re-use something
1072 multiname_t*s2 = sig2mname(s);
1074 multiname_destroy(s2);
1076 __ pushscope(m); count++;
1077 m->code = m->code->prev->prev; // invert
1079 /* continue appending after last op end */
1080 while(m->code && m->code->next) m->code = m->code->next;
1082 /* TODO: if this is one of *our* classes, we can also
1083 do a getglobalscope/getslot <nr> (which references
1084 the init function's slots) */
1086 __ getlex2(m, extends2);
1088 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
1089 stack is not the superclass */
1090 __ pushscope(m);count++;
1093 /* notice: we get a verify error #1107 if the top element on the scope
1094 stack is not the global object */
1096 __ pushscope(m);count++;
1098 __ newclass(m,state->cls->abc);
1102 __ setslot(m, slotindex);
1103 multiname_destroy(extends2);
1105 /* flash.display.MovieClip handling */
1107 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1108 if(state->package && state->package[0]) {
1109 as3_globalclass = concat3(state->package, ".", classname);
1111 as3_globalclass = strdup(classname);
1117 static void endclass()
1120 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1122 c = abc_getlocal_0(c);
1123 c = abc_constructsuper(c, 0);
1124 state->cls->init->header = code_append(state->cls->init->header, c);
1125 state->cls->has_constructor=1;
1127 if(state->cls->init) {
1128 if(state->cls->info->flags&FLAG_INTERFACE) {
1129 if(state->cls->init->header)
1130 syntaxerror("interface can not have class-level code");
1132 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1133 code_t*c = method_header(state->cls->init);
1134 m->body->code = wrap_function(c, 0, m->body->code);
1137 if(state->cls->static_init) {
1138 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1139 code_t*c = method_header(state->cls->static_init);
1140 m->body->code = wrap_function(c, 0, m->body->code);
1147 void check_code_for_break(code_t*c)
1150 if(c->opcode == OPCODE___BREAK__) {
1151 char*name = string_cstr(c->data[0]);
1152 syntaxerror("Unresolved \"break %s\"", name);
1154 if(c->opcode == OPCODE___CONTINUE__) {
1155 char*name = string_cstr(c->data[0]);
1156 syntaxerror("Unresolved \"continue %s\"", name);
1158 if(c->opcode == OPCODE___RETHROW__) {
1159 syntaxerror("Unresolved \"rethrow\"");
1161 if(c->opcode == OPCODE___FALLTHROUGH__) {
1162 syntaxerror("Unresolved \"fallthrough\"");
1164 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1165 char*name = string_cstr(c->data[0]);
1166 syntaxerror("Can't reference a package (%s) as such", name);
1172 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1174 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1175 if(TYPE_IS_NUMBER(t)) {
1176 xassert(c->type == CONSTANT_FLOAT
1177 || c->type == CONSTANT_INT
1178 || c->type == CONSTANT_UINT);
1179 } else if(TYPE_IS_UINT(t)) {
1180 xassert(c->type == CONSTANT_UINT ||
1181 (c->type == CONSTANT_INT && c->i>=0));
1182 } else if(TYPE_IS_INT(t)) {
1183 xassert(c->type == CONSTANT_INT);
1184 } else if(TYPE_IS_BOOLEAN(t)) {
1185 xassert(c->type == CONSTANT_TRUE
1186 || c->type == CONSTANT_FALSE);
1190 static void check_override(memberinfo_t*m, int flags)
1194 if(m->parent == state->cls->info)
1195 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1197 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1198 if(m->access==ACCESS_PRIVATE)
1200 if(m->flags & FLAG_FINAL)
1201 syntaxerror("can't override final member %s", m->name);
1203 /* allow this. it's no issue.
1204 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1205 syntaxerror("can't override static member %s", m->name);*/
1207 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1208 syntaxerror("can't override non-static member %s with static declaration", m->name);
1210 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1211 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1212 if(m->kind == INFOTYPE_METHOD)
1213 syntaxerror("can't override without explicit 'override' declaration");
1215 syntaxerror("can't override '%s'", m->name);
1220 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1222 methodinfo_t*minfo = 0;
1223 namespace_t ns = modifiers2access(mod);
1226 minfo = methodinfo_register_global(ns.access, state->package, name);
1227 minfo->return_type = 0; // save this for pass 2
1228 } else if(getset != KW_GET && getset != KW_SET) {
1230 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1232 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1234 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1235 minfo->return_type = 0; // save this for pass 2
1236 // getslot on a member slot only returns "undefined", so no need
1237 // to actually store these
1238 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1240 //class getter/setter
1241 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1243 if(getset == KW_GET) {
1245 } else if(params->list && params->list->param && !params->list->next) {
1246 type = params->list->param->type;
1248 syntaxerror("setter function needs to take exactly one argument");
1249 // not sure wether to look into superclasses here, too
1250 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1252 if(minfo->kind!=INFOTYPE_SLOT)
1253 syntaxerror("class already contains a method called '%s'", name);
1254 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1255 syntaxerror("class already contains a field called '%s'", name);
1256 if(minfo->subtype & gs)
1257 syntaxerror("getter/setter for '%s' already defined", name);
1258 /* make a setter or getter into a getset */
1259 minfo->subtype |= gs;
1262 FIXME: this check needs to be done in pass 2
1264 if((!minfo->return_type != !type) ||
1265 (minfo->return_type && type &&
1266 !strcmp(minfo->return_type->name, type->name))) {
1267 syntaxerror("different type in getter and setter: %s and %s",
1268 minfo->return_type?minfo->return_type->name:"*",
1269 type?type->name:"*");
1272 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1273 minfo->kind = INFOTYPE_SLOT; //hack
1274 minfo->subtype = gs;
1275 minfo->return_type = 0;
1277 /* can't assign a slot as getter and setter might have different slots */
1278 //minfo->slot = slot;
1280 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1281 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1282 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1287 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1289 //parserassert(state->method && state->method->info);
1291 methodstate_t*parent_method = state->method;
1294 return_type = 0; // not valid in pass 1
1298 state->new_vars = 1;
1301 state->method = rfx_calloc(sizeof(methodstate_t));
1302 state->method->inner = 1;
1303 state->method->variable_count = 0;
1304 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1306 NEW(methodinfo_t,minfo);
1307 minfo->kind = INFOTYPE_METHOD;
1308 minfo->access = ACCESS_PACKAGEINTERNAL;
1310 state->method->info = minfo;
1313 list_append(parent_method->innerfunctions, state->method);
1315 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1317 function_initvars(state->method, params, 0, 1);
1321 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1322 state->method->variable_count = 0;
1323 parserassert(state->method);
1325 state->method->info->return_type = return_type;
1326 function_initvars(state->method, params, 0, 1);
1330 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1331 params_t*params, classinfo_t*return_type)
1333 if(state->method && state->method->info) {
1334 syntaxerror("not able to start another method scope");
1337 state->new_vars = 1;
1340 state->method = rfx_calloc(sizeof(methodstate_t));
1341 state->method->has_super = 0;
1344 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1346 state->method->is_global = 1;
1347 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1349 if(state->method->is_constructor)
1350 name = "__as3_constructor__";
1352 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1354 function_initvars(state->method, params, mod->flags, 1);
1356 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1360 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1361 state->method->variable_count = 0;
1362 parserassert(state->method);
1365 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1366 check_override(m, mod->flags);
1370 state->cls->has_constructor |= state->method->is_constructor;
1373 state->method->info->return_type = return_type;
1374 function_initvars(state->method, params, mod->flags, 1);
1378 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1379 params_t*params, classinfo_t*return_type, code_t*body)
1382 // store inner methods in variables
1383 function_initvars(state->method, 0, 0, 0);
1385 methodstate_list_t*ml = state->method->innerfunctions;
1387 dict_t*xvars = dict_new();
1390 methodstate_t*m = ml->methodstate;
1391 parserassert(m->inner);
1392 if(m->unresolved_variables) {
1393 dict_t*d = m->unresolved_variables;
1395 for(t=0;t<d->hashsize;t++) {
1396 dictentry_t*l = d->slots[t];
1398 /* check parent method's variables */
1400 if((v=find_variable(state, l->key))) {
1401 m->uses_parent_function = 1;
1402 state->method->uses_slots = 1;
1403 dict_put(xvars, l->key, 0);
1410 dict_destroy(m->unresolved_variables);
1411 m->unresolved_variables = 0;
1416 if(state->method->uses_slots) {
1417 state->method->slots = dict_new();
1419 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1420 if(!name) syntaxerror("internal error");
1421 if(v->index && dict_contains(xvars, name)) {
1424 if(v->is_inner_method) {
1425 v->is_inner_method->is_a_slot = 1;
1428 dict_put(state->method->slots, name, v);
1431 state->method->uses_slots = i;
1432 dict_destroy(state->vars);state->vars = 0;
1439 /*if(state->method->uses_parent_function){
1440 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1445 multiname_t*type2 = sig2mname(return_type);
1447 if(state->method->inner) {
1448 f = state->method->abc;
1449 abc_method_init(f, global->file, type2, 1);
1450 } else if(state->method->is_constructor) {
1451 f = abc_class_getconstructor(state->cls->abc, type2);
1452 } else if(!state->method->is_global) {
1453 namespace_t mname_ns = modifiers2access(mod);
1454 multiname_t mname = {QNAME, &mname_ns, 0, name};
1456 if(mod->flags&FLAG_STATIC)
1457 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1459 f = abc_class_method(state->cls->abc, type2, &mname);
1460 slot = f->trait->slot_id;
1462 namespace_t mname_ns = {state->method->info->access, state->package};
1463 multiname_t mname = {QNAME, &mname_ns, 0, name};
1465 f = abc_method_new(global->file, type2, 1);
1466 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1467 //abc_code_t*c = global->init->method->body->code;
1469 //flash doesn't seem to allow us to access function slots
1470 //state->method->info->slot = slot;
1472 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1473 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1474 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1475 if(params->varargs) f->flags |= METHOD_NEED_REST;
1479 for(p=params->list;p;p=p->next) {
1480 if(params->varargs && !p->next) {
1481 break; //varargs: omit last parameter in function signature
1483 multiname_t*m = sig2mname(p->param->type);
1484 list_append(f->parameters, m);
1485 if(p->param->value) {
1486 check_constant_against_type(p->param->type, p->param->value);
1487 opt=1;list_append(f->optional_parameters, p->param->value);
1489 syntaxerror("non-optional parameter not allowed after optional parameters");
1492 if(state->method->slots) {
1493 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1495 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1496 multiname_t*type = sig2mname(v->type);
1497 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1498 t->slot_id = v->index;
1503 check_code_for_break(body);
1505 /* Seems this works now.
1506 if(state->method->exceptions && state->method->uses_slots) {
1507 as3_warning("try/catch and activation not supported yet within the same method");
1511 f->body->code = body;
1512 f->body->exceptions = state->method->exceptions;
1513 } else { //interface
1515 syntaxerror("interface methods can't have a method body");
1525 void breakjumpsto(code_t*c, char*name, code_t*jump)
1528 if(c->opcode == OPCODE___BREAK__) {
1529 string_t*name2 = c->data[0];
1530 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1531 c->opcode = OPCODE_JUMP;
1538 void continuejumpsto(code_t*c, char*name, code_t*jump)
1541 if(c->opcode == OPCODE___CONTINUE__) {
1542 string_t*name2 = c->data[0];
1543 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1544 c->opcode = OPCODE_JUMP;
1552 /* TODO: move this to ast.c */
1553 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1554 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1555 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1556 static classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1558 if(!type1 || !type2)
1559 return registry_getanytype();
1560 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1561 return registry_getanytype();
1564 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1573 return registry_getanytype();
1575 static char is_getlocal(code_t*c)
1577 if(!c || c->prev || c->next)
1579 return(c->opcode == OPCODE_GETLOCAL
1580 || c->opcode == OPCODE_GETLOCAL_0
1581 || c->opcode == OPCODE_GETLOCAL_1
1582 || c->opcode == OPCODE_GETLOCAL_2
1583 || c->opcode == OPCODE_GETLOCAL_3);
1585 static int getlocalnr(code_t*c)
1587 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1588 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1589 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1590 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1591 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1592 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1595 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1600 return abc_coerce_a(c);
1604 // cast an "any" type to a specific type. subject to
1605 // runtime exceptions
1606 return abc_coerce2(c, &m);
1609 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1610 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1611 // allow conversion between number types
1612 return abc_coerce2(c, &m);
1614 //printf("%s.%s\n", from.package, from.name);
1615 //printf("%s.%s\n", to.package, to.name);
1617 classinfo_t*supertype = from;
1619 if(supertype == to) {
1620 // target type is one of from's superclasses
1621 return abc_coerce2(c, &m);
1624 while(supertype->interfaces[t]) {
1625 if(supertype->interfaces[t]==to) {
1626 // target type is one of from's interfaces
1627 return abc_coerce2(c, &m);
1631 supertype = supertype->superclass;
1633 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1635 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1637 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1640 as3_error("can't convert type %s%s%s to %s%s%s",
1641 from->package, from->package?".":"", from->name,
1642 to->package, to->package?".":"", to->name);
1646 /* move to ast.c todo end */
1648 char is_pushundefined(code_t*c)
1650 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1653 static const char* get_package_from_name(const char*name)
1655 /* try explicit imports */
1656 dictentry_t* e = dict_get_slot(state->imports, name);
1658 if(!strcmp(e->key, name)) {
1659 slotinfo_t*c = (slotinfo_t*)e->data;
1660 if(c) return c->package;
1666 static namespace_list_t*get_current_imports()
1668 namespace_list_t*searchlist = 0;
1670 list_append(searchlist, namespace_new_package(state->package));
1672 import_list_t*l = state->wildcard_imports;
1674 namespace_t*ns = namespace_new_package(l->import->package);
1675 list_append(searchlist, ns);
1678 list_append(searchlist, namespace_new_package(""));
1679 list_append(searchlist, namespace_new_package(internal_filename_package));
1683 static slotinfo_t* find_class(const char*name)
1687 c = registry_find(state->package, name);
1690 /* try explicit imports */
1691 dictentry_t* e = dict_get_slot(state->imports, name);
1694 if(!strcmp(e->key, name)) {
1695 c = (slotinfo_t*)e->data;
1701 /* try package.* imports */
1702 import_list_t*l = state->wildcard_imports;
1704 //printf("does package %s contain a class %s?\n", l->import->package, name);
1705 c = registry_find(l->import->package, name);
1710 /* try global package */
1711 c = registry_find("", name);
1714 /* try local "filename" package */
1715 c = registry_find(internal_filename_package, name);
1720 typedcode_t push_class(slotinfo_t*a)
1725 if(a->access == ACCESS_PACKAGEINTERNAL &&
1726 strcmp(a->package, state->package) &&
1727 strcmp(a->package, internal_filename_package)
1729 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1730 infotypename(a), a->name, a->package, state->package);
1733 if(a->kind != INFOTYPE_CLASS) {
1735 x.c = abc_findpropstrict2(x.c, &m);
1736 x.c = abc_getproperty2(x.c, &m);
1737 if(a->kind == INFOTYPE_METHOD) {
1738 methodinfo_t*f = (methodinfo_t*)a;
1739 x.t = TYPE_FUNCTION(f);
1741 varinfo_t*v = (varinfo_t*)a;
1745 classinfo_t*c = (classinfo_t*)a;
1747 x.c = abc_getglobalscope(x.c);
1748 x.c = abc_getslot(x.c, c->slot);
1751 x.c = abc_getlex2(x.c, &m);
1753 x.t = TYPE_CLASS(c);
1759 code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore, char pushvalue)
1763 [prefix code] [read instruction]
1767 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1769 if(in && in->opcode == OPCODE_COERCE_A) {
1770 in = code_cutlast(in);
1773 syntaxerror("internal error");
1775 /* chop off read instruction */
1779 prefix = r->prev;r->prev = 0;
1785 char use_temp_var = readbefore;
1787 /* generate the write instruction, and maybe append a dup to the prefix code */
1788 code_t* write = abc_nop(0);
1789 if(r->opcode == OPCODE_GETPROPERTY) {
1790 write->opcode = OPCODE_SETPROPERTY;
1791 multiname_t*m = (multiname_t*)r->data[0];
1792 write->data[0] = multiname_clone(m);
1793 if(m->type == QNAME || m->type == MULTINAME) {
1795 prefix = abc_dup(prefix); // we need the object, too
1798 } else if(m->type == MULTINAMEL) {
1800 /* dupping two values on the stack requires 5 operations and one register-
1801 couldn't adobe just have given us a dup2? */
1802 int temp = gettempvar();
1803 prefix = abc_setlocal(prefix, temp);
1804 prefix = abc_dup(prefix);
1805 prefix = abc_getlocal(prefix, temp);
1806 prefix = abc_swap(prefix);
1807 prefix = abc_getlocal(prefix, temp);
1809 prefix = abc_kill(prefix, temp);
1813 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1815 } else if(r->opcode == OPCODE_GETSLOT) {
1816 write->opcode = OPCODE_SETSLOT;
1817 write->data[0] = r->data[0];
1819 prefix = abc_dup(prefix); // we need the object, too
1822 } else if(r->opcode == OPCODE_GETLOCAL) {
1823 write->opcode = OPCODE_SETLOCAL;
1824 write->data[0] = r->data[0];
1825 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1826 write->opcode = OPCODE_SETLOCAL_0;
1827 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1828 write->opcode = OPCODE_SETLOCAL_1;
1829 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1830 write->opcode = OPCODE_SETLOCAL_2;
1831 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1832 write->opcode = OPCODE_SETLOCAL_3;
1833 } else if(r->opcode == OPCODE_GETSUPER) {
1834 write->opcode = OPCODE_SETSUPER;
1835 multiname_t*m = (multiname_t*)r->data[0];
1836 write->data[0] = multiname_clone(m);
1839 syntaxerror("illegal lvalue: can't assign a value to this expression");
1846 /* with getproperty/getslot, we have to be extra careful not
1847 to execute the read code twice, as it might have side-effects
1848 (e.g. if the property is in fact a setter/getter combination)
1850 So read the value, modify it, and write it again,
1851 using prefix only once and making sure (by using a temporary
1852 register) that the return value is what we just wrote */
1853 temp = gettempvar();
1854 c = code_append(c, prefix);
1855 c = code_append(c, r);
1856 if(pushvalue && readbefore) {
1858 c = abc_setlocal(c, temp);
1860 c = code_append(c, middlepart);
1861 if(pushvalue && !readbefore) {
1863 c = abc_setlocal(c, temp);
1865 c = code_append(c, write);
1867 c = abc_getlocal(c, temp);
1868 c = abc_kill(c, temp);
1871 /* if we're allowed to execute the read code twice *and*
1872 the middlepart doesn't modify the code, things are easier.
1874 //c = code_append(c, prefix);
1875 parserassert(!prefix);
1880 c = code_append(c, r);
1881 c = code_append(c, middlepart);
1882 c = code_append(c, write);
1884 c = code_append(c, r2);
1888 /* even smaller version: overwrite the value without reading
1892 c = code_append(c, prefix);
1895 c = code_append(c, middlepart);
1896 c = code_append(c, write);
1898 c = code_append(c, r);
1902 temp = gettempvar();
1904 c = code_append(c, prefix);
1906 c = code_append(c, middlepart);
1909 c = abc_setlocal(c, temp);
1911 c = code_append(c, write);
1913 c = abc_getlocal(c, temp);
1914 c = abc_kill(c, temp);
1921 char is_break_or_jump(code_t*c)
1925 if(c->opcode == OPCODE_JUMP ||
1926 c->opcode == OPCODE___BREAK__ ||
1927 c->opcode == OPCODE___CONTINUE__ ||
1928 c->opcode == OPCODE_THROW ||
1929 c->opcode == OPCODE_RETURNVOID ||
1930 c->opcode == OPCODE_RETURNVALUE) {
1936 #define IS_FINALLY_TARGET(op) \
1937 ((op) == OPCODE___CONTINUE__ || \
1938 (op) == OPCODE___BREAK__ || \
1939 (op) == OPCODE_RETURNVOID || \
1940 (op) == OPCODE_RETURNVALUE || \
1941 (op) == OPCODE___RETHROW__)
1943 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1945 #define NEED_EXTRA_STACK_ARG
1946 code_t*finally_label = abc_nop(0);
1947 NEW(lookupswitch_t, l);
1953 code_t*prev = i->prev;
1954 if(IS_FINALLY_TARGET(i->opcode)) {
1957 if(i->opcode == OPCODE___RETHROW__ ||
1958 i->opcode == OPCODE_RETURNVALUE) {
1959 if(i->opcode == OPCODE___RETHROW__)
1960 i->opcode = OPCODE_THROW;
1962 p = abc_coerce_a(p);
1963 p = abc_setlocal(p, tempvar);
1965 p = abc_pushbyte(p, count++);
1966 p = abc_jump(p, finally_label);
1967 code_t*target = p = abc_label(p);
1968 #ifdef NEED_EXTRA_STACK_ARG
1972 p = abc_getlocal(p, tempvar);
1975 p->next = i;i->prev = p;
1976 list_append(l->targets, target);
1982 c = abc_pushbyte(c, -1);
1983 c = code_append(c, finally_label);
1984 c = code_append(c, finally);
1986 #ifdef NEED_EXTRA_STACK_ARG
1989 c = abc_lookupswitch(c, l);
1990 c = l->def = abc_label(c);
1991 #ifdef NEED_EXTRA_STACK_ARG
1998 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
2002 code_t*prev = i->prev;
2003 if(IS_FINALLY_TARGET(i->opcode)) {
2004 if(i->opcode == OPCODE___RETHROW__)
2005 i->opcode = OPCODE_THROW;
2006 code_t*end = code_dup(finally);
2007 code_t*start = code_start(end);
2008 if(prev) prev->next = start;
2015 return code_append(c, finally);
2018 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
2024 int num_insertion_points=0;
2026 if(IS_FINALLY_TARGET(i->opcode))
2027 num_insertion_points++;
2034 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
2039 int simple_version_cost = (1+num_insertion_points)*code_size;
2040 int lookup_version_cost = 4*num_insertion_points + 5;
2042 if(cantdup || simple_version_cost > lookup_version_cost) {
2043 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
2044 return insert_finally_lookup(c, finally, tempvar);
2046 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
2047 return insert_finally_simple(c, finally, tempvar);
2051 #define PASS1 }} if(as3_pass == 1) {{
2052 #define PASS1END }} if(as3_pass == 2) {{
2053 #define PASS2 }} if(as3_pass == 2) {{
2054 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
2055 #define PASS12END }} if(as3_pass == 2) {{
2056 #define PASS_ALWAYS }} {{
2062 /* ------------ code blocks / statements ---------------- */
2064 PROGRAM: MAYBE_PROGRAM_CODE_LIST
2066 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
2067 PROGRAM_CODE_LIST: PROGRAM_CODE
2068 | PROGRAM_CODE_LIST PROGRAM_CODE
2070 PROGRAM_CODE: PACKAGE_DECLARATION
2071 | INTERFACE_DECLARATION
2073 | FUNCTION_DECLARATION
2076 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
2079 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
2080 INPACKAGE_CODE_LIST: INPACKAGE_CODE
2081 | INPACKAGE_CODE_LIST INPACKAGE_CODE
2083 INPACKAGE_CODE: INTERFACE_DECLARATION
2085 | FUNCTION_DECLARATION
2088 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
2091 MAYBECODE: CODE {$$=$1;}
2092 MAYBECODE: {$$=code_new();}
2094 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
2095 CODE: CODEPIECE {$$=$1;}
2097 // code which may appear outside of methods
2098 CODE_STATEMENT: IMPORT
2100 CODE_STATEMENT: FOR_IN
2101 CODE_STATEMENT: WHILE
2102 CODE_STATEMENT: DO_WHILE
2103 CODE_STATEMENT: SWITCH
2105 CODE_STATEMENT: WITH
2107 CODE_STATEMENT: VOIDEXPRESSION
2108 CODE_STATEMENT: USE_NAMESPACE
2109 CODE_STATEMENT: NAMESPACE_DECLARATION
2110 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
2111 CODE_STATEMENT: '{' '}' {$$=0;}
2113 // code which may appear in methods
2114 CODEPIECE: ';' {$$=0;}
2115 CODEPIECE: CODE_STATEMENT
2116 CODEPIECE: VARIABLE_DECLARATION
2121 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {PASS_ALWAYS as3_pass=$1;}
2123 //CODEBLOCK : '{' CODE '}' {$$=$2;}
2124 //CODEBLOCK : '{' '}' {$$=0;}
2125 CODEBLOCK : CODEPIECE ';' {$$=$1;}
2126 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
2128 /* ------------ package init code ------------------- */
2130 PACKAGE_INITCODE: CODE_STATEMENT {
2131 code_t**cc = &global->init->method->body->code;
2132 *cc = code_append(*cc, $1);
2135 /* ------------ conditional compilation ------------- */
2137 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
2140 char*key = concat3($1,"::",$3);
2141 if(!definitions || !dict_contains(definitions, key)) {
2147 /* ------------ variables --------------------------- */
2150 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
2156 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
2157 | {$$.c=abc_pushundefined(0);
2161 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
2162 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
2164 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
2165 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2167 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2170 if(variable_exists($1))
2171 syntaxerror("Variable %s already defined", $1);
2173 new_variable($1, 0, 1, 0);
2176 if(!is_subtype_of($3.t, $2)) {
2177 syntaxerror("Can't convert %s to %s", $3.t->name,
2183 if(state->method->uses_slots) {
2184 variable_t* v = find_slot(state, $1);
2186 // this variable is stored in a slot
2194 index = new_variable($1, $2, 1, 0);
2197 $$ = slot?abc_getscopeobject(0, 1):0;
2200 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2201 $$ = code_append($$, $3.c);
2202 $$ = converttype($$, $3.t, $2);
2205 $$ = defaultvalue($$, $2);
2208 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2209 $$ = code_append($$, $3.c);
2210 $$ = abc_coerce_a($$);
2212 // don't do anything
2220 $$ = abc_setslot($$, index);
2222 $$ = abc_setlocal($$, index);
2226 /* ------------ control flow ------------------------- */
2228 MAYBEELSE: %prec below_else {$$ = code_new();}
2229 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2230 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2232 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2235 $$ = code_append($$, $4.c);
2236 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2238 $$ = code_append($$, $6);
2240 myjmp = $$ = abc_jump($$, 0);
2242 myif->branch = $$ = abc_nop($$);
2244 $$ = code_append($$, $7);
2245 myjmp->branch = $$ = abc_nop($$);
2251 FOR_INIT : {$$=code_new();}
2252 FOR_INIT : VARIABLE_DECLARATION
2253 FOR_INIT : VOIDEXPRESSION
2255 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2256 // (I don't see any easy way to revolve this conflict otherwise, as we
2257 // can't touch VAR_READ without upsetting the precedence about "return")
2258 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2259 PASS1 $$=$2;new_variable($2,0,1,0);
2260 PASS2 $$=$2;new_variable($2,$3,1,0);
2262 FOR_IN_INIT : T_IDENTIFIER {
2267 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2268 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2270 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2271 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2273 $$ = code_append($$, $2);
2274 code_t*loopstart = $$ = abc_label($$);
2275 $$ = code_append($$, $4.c);
2276 code_t*myif = $$ = abc_iffalse($$, 0);
2277 $$ = code_append($$, $8);
2278 code_t*cont = $$ = abc_nop($$);
2279 $$ = code_append($$, $6);
2280 $$ = abc_jump($$, loopstart);
2281 code_t*out = $$ = abc_nop($$);
2282 breakjumpsto($$, $1.name, out);
2283 continuejumpsto($$, $1.name, cont);
2290 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2291 variable_t*var = find_variable(state, $2);
2293 syntaxerror("variable %s not known in this scope", $2);
2296 char*tmp1name = concat2($2, "__tmp1__");
2297 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2298 char*tmp2name = concat2($2, "__array__");
2299 int array = new_variable(tmp1name, 0, 0, 0);
2302 $$ = code_append($$, $4.c);
2303 $$ = abc_coerce_a($$);
2304 $$ = abc_setlocal($$, array);
2305 $$ = abc_pushbyte($$, 0);
2306 $$ = abc_setlocal($$, it);
2308 code_t*loopstart = $$ = abc_label($$);
2310 $$ = abc_hasnext2($$, array, it);
2311 code_t*myif = $$ = abc_iffalse($$, 0);
2312 $$ = abc_getlocal($$, array);
2313 $$ = abc_getlocal($$, it);
2315 $$ = abc_nextname($$);
2317 $$ = abc_nextvalue($$);
2318 $$ = converttype($$, 0, var->type);
2319 $$ = abc_setlocal($$, var->index);
2321 $$ = code_append($$, $6);
2322 $$ = abc_jump($$, loopstart);
2324 code_t*out = $$ = abc_nop($$);
2325 breakjumpsto($$, $1.name, out);
2326 continuejumpsto($$, $1.name, loopstart);
2338 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2342 code_t*myjmp = $$ = abc_jump($$, 0);
2343 code_t*loopstart = $$ = abc_label($$);
2344 $$ = code_append($$, $6);
2345 code_t*cont = $$ = abc_nop($$);
2346 myjmp->branch = cont;
2347 $$ = code_append($$, $4.c);
2348 $$ = abc_iftrue($$, loopstart);
2349 code_t*out = $$ = abc_nop($$);
2350 breakjumpsto($$, $1, out);
2351 continuejumpsto($$, $1, cont);
2357 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2359 code_t*loopstart = $$ = abc_label($$);
2360 $$ = code_append($$, $3);
2361 code_t*cont = $$ = abc_nop($$);
2362 $$ = code_append($$, $6.c);
2363 $$ = abc_iftrue($$, loopstart);
2364 code_t*out = $$ = abc_nop($$);
2365 breakjumpsto($$, $1, out);
2366 continuejumpsto($$, $1, cont);
2372 BREAK : "break" %prec prec_none {
2373 $$ = abc___break__(0, "");
2375 BREAK : "break" T_IDENTIFIER {
2376 $$ = abc___break__(0, $2);
2378 CONTINUE : "continue" %prec prec_none {
2379 $$ = abc___continue__(0, "");
2381 CONTINUE : "continue" T_IDENTIFIER {
2382 $$ = abc___continue__(0, $2);
2385 MAYBE_CASE_LIST : {$$=0;}
2386 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2387 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2388 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2389 CASE_LIST: CASE {$$=$1;}
2390 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2392 CASE: "case" E ':' MAYBECODE {
2393 $$ = abc_getlocal(0, state->switch_var);
2394 $$ = code_append($$, $2.c);
2395 code_t*j = $$ = abc_ifne($$, 0);
2396 $$ = code_append($$, $4);
2397 if($$->opcode != OPCODE___BREAK__) {
2398 $$ = abc___fallthrough__($$, "");
2400 code_t*e = $$ = abc_nop($$);
2403 DEFAULT: "default" ':' MAYBECODE {
2406 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2408 $$ = abc_setlocal($$, state->switch_var);
2409 $$ = code_append($$, $7);
2411 code_t*out = $$ = abc_kill($$, state->switch_var);
2412 breakjumpsto($$, $1, out);
2414 code_t*c = $$,*lastblock=0;
2416 if(c->opcode == OPCODE_IFNE) {
2417 if(!c->next) syntaxerror("internal error in fallthrough handling");
2419 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2421 c->opcode = OPCODE_JUMP;
2422 c->branch = lastblock;
2424 /* fall through end of switch */
2425 c->opcode = OPCODE_NOP;
2435 /* ------------ try / catch /finally ---------------- */
2437 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2438 state->exception_name=$3;
2439 PASS1 new_variable($3, 0, 0, 0);
2440 PASS2 new_variable($3, $4, 0, 0);
2443 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2444 multiname_t name = {QNAME, &name_ns, 0, $3};
2446 NEW(abc_exception_t, e)
2447 e->exc_type = sig2mname($4);
2448 e->var_name = multiname_clone(&name);
2452 int i = find_variable_safe(state, $3)->index;
2453 e->target = c = abc_nop(0);
2454 c = abc_setlocal(c, i);
2455 c = code_append(c, code_dup(state->method->scope_code));
2456 c = code_append(c, $8);
2462 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2467 NEW(abc_exception_t, e)
2468 e->exc_type = 0; //all exceptions
2469 e->var_name = 0; //no name
2472 e->to = code_append(e->to, $4);
2478 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2479 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2480 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2481 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2485 list_append($$.l,$2);
2486 $$.finally = $2->to;$2->to=0;
2489 CATCH_FINALLY_LIST: FINALLY {
2493 list_append($$.l,$1);
2494 $$.finally = $1->to;$1->to=0;
2498 TRY : "try" '{' {PASS12 new_state();
2499 state->method->has_exceptions=1;
2500 state->method->late_binding=1;//for invariant scope_code
2501 } MAYBECODE '}' CATCH_FINALLY_LIST {
2502 code_t*out = abc_nop(0);
2504 code_t*start = abc_nop(0);
2505 $$ = code_append(start, $4);
2506 if(!is_break_or_jump($4)) {
2507 $$ = abc_jump($$, out);
2509 code_t*end = $$ = abc_nop($$);
2513 tmp = new_variable("__finally__", 0, 0, 0);
2515 abc_exception_list_t*l = $6.l;
2518 abc_exception_t*e = l->abc_exception;
2520 $$ = code_append($$, e->target);
2521 $$ = abc_jump($$, out);
2523 parserassert((ptroff_t)$6.finally);
2525 e->target = $$ = abc_nop($$);
2526 $$ = code_append($$, code_dup(state->method->scope_code));
2527 $$ = abc___rethrow__($$);
2535 $$ = code_append($$, out);
2537 $$ = insert_finally($$, $6.finally, tmp);
2539 list_concat(state->method->exceptions, $6.l);
2545 /* ------------ throw ------------------------------- */
2547 THROW : "throw" EXPRESSION {
2551 THROW : "throw" %prec prec_none {
2552 if(!state->exception_name)
2553 syntaxerror("re-throw only possible within a catch block");
2554 variable_t*v = find_variable(state, state->exception_name);
2556 $$=abc_getlocal($$, v->index);
2560 /* ------------ with -------------------------------- */
2562 WITH_HEAD : "with" '(' EXPRESSION ')' {
2564 if(state->method->has_exceptions) {
2565 int v = alloc_local();
2566 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2567 state->method->scope_code = abc_pushwith(state->method->scope_code);
2572 WITH : WITH_HEAD CODEBLOCK {
2573 /* remove getlocal;pushwith from scope code again */
2574 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2577 if(state->method->has_exceptions) {
2579 $$ = abc_setlocal($$, $1.number);
2581 $$ = abc_pushwith($$);
2582 $$ = code_append($$, $2);
2583 $$ = abc_popscope($$);
2587 /* ------------ packages and imports ---------------- */
2589 X_IDENTIFIER: T_IDENTIFIER
2590 | "package" {PASS12 $$="package";}
2591 | T_NAMESPACE {PASS12 $$=$1;}
2593 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2594 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2596 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2597 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2598 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2599 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2602 static void state_has_imports()
2604 state->wildcard_imports = list_clone(state->wildcard_imports);
2605 state->imports = dict_clone(state->imports);
2606 state->has_own_imports = 1;
2608 static void import_toplevel(const char*package)
2610 char* s = strdup(package);
2612 dict_put(state->import_toplevel_packages, s, 0);
2613 char*x = strrchr(s, '.');
2621 IMPORT : "import" PACKAGEANDCLASS {
2623 slotinfo_t*s = registry_find($2->package, $2->name);
2624 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2625 as3_schedule_class($2->package, $2->name);
2629 syntaxerror("Couldn't import class\n");
2630 state_has_imports();
2631 dict_put(state->imports, c->name, c);
2632 import_toplevel(c->package);
2635 IMPORT : "import" PACKAGE '.' '*' {
2637 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2638 as3_schedule_package($2);
2643 state_has_imports();
2644 list_append(state->wildcard_imports, i);
2645 import_toplevel(i->package);
2649 /* ------------ classes and interfaces (header) -------------- */
2651 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2652 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2653 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2654 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2656 $$.flags=$1.flags|$2.flags;
2657 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2658 $$.ns=$1.ns?$1.ns:$2.ns;
2661 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2662 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2663 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2664 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2665 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2666 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2667 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2668 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2669 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2670 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2674 EXTENDS : {PASS12 $$=0;}
2675 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2677 EXTENDS_LIST : {PASS12 $$=list_new();}
2678 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2680 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2681 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2683 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2684 EXTENDS IMPLEMENTS_LIST
2685 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2687 '}' {PASS12 endclass();$$=0;}
2689 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2691 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2692 startclass(&$1,$3,0,$4);}
2693 MAYBE_INTERFACE_BODY
2694 '}' {PASS12 endclass();$$=0;}
2696 /* ------------ classes and interfaces (body) -------------- */
2699 MAYBE_CLASS_BODY : CLASS_BODY
2700 CLASS_BODY : CLASS_BODY_ITEM
2701 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2702 CLASS_BODY_ITEM : ';'
2703 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2704 CLASS_BODY_ITEM : SLOT_DECLARATION
2705 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2707 CLASS_BODY_ITEM : CODE_STATEMENT {
2708 code_t*c = state->cls->static_init->header;
2709 c = code_append(c, $1);
2710 state->cls->static_init->header = c;
2713 MAYBE_INTERFACE_BODY :
2714 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2715 INTERFACE_BODY : IDECLARATION
2716 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2718 IDECLARATION : "var" T_IDENTIFIER {
2719 syntaxerror("variable declarations not allowed in interfaces");
2721 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2723 $1.flags |= FLAG_PUBLIC;
2724 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2725 syntaxerror("invalid method modifiers: interface methods always need to be public");
2727 startfunction(&$1,$3,$4,&$6,$8);
2728 endfunction(&$1,$3,$4,&$6,$8, 0);
2729 list_deep_free($6.list);
2732 /* ------------ classes and interfaces (body, slots ) ------- */
2735 static int slotstate_varconst = 0;
2736 static modifiers_t*slotstate_flags = 0;
2737 static void setslotstate(modifiers_t* flags, int varconst)
2739 slotstate_varconst = varconst;
2740 slotstate_flags = flags;
2742 if(flags && flags->flags&FLAG_STATIC) {
2743 state->method = state->cls->static_init;
2745 state->method = state->cls->init;
2748 parserassert(state->method);
2753 VARCONST: "var" | "const"
2755 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2757 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2758 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2760 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2763 int flags = slotstate_flags->flags;
2764 namespace_t ns = modifiers2access(slotstate_flags);
2768 varinfo_t* info = 0;
2770 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2772 check_override(i, flags);
2774 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2776 slotinfo_t*i = registry_find(state->package, $1);
2778 syntaxerror("package %s already contains '%s'", state->package, $1);
2780 if(ns.name && ns.name[0]) {
2781 syntaxerror("namespaces not allowed on package-level variables");
2783 info = varinfo_register_global(ns.access, state->package, $1);
2787 info->flags = flags;
2789 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2793 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2796 multiname_t mname = {QNAME, &ns, 0, $1};
2798 trait_list_t**traits;
2802 ns.name = state->package;
2803 traits = &global->init->traits;
2804 code = &global->init->method->body->code;
2805 } else if(flags&FLAG_STATIC) {
2807 traits = &state->cls->abc->static_traits;
2808 code = &state->cls->static_init->header;
2810 // instance variable
2811 traits = &state->cls->abc->traits;
2812 code = &state->cls->init->header;
2818 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2820 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2822 info->slot = t->slot_id;
2824 /* initalization code (if needed) */
2826 if($3.c && !is_pushundefined($3.c)) {
2827 c = abc_getlocal_0(c);
2828 c = code_append(c, $3.c);
2829 c = converttype(c, $3.t, $2);
2830 c = abc_setslot(c, t->slot_id);
2833 *code = code_append(*code, c);
2835 if(slotstate_varconst==KW_CONST) {
2836 t->kind= TRAIT_CONST;
2843 /* ------------ constants -------------------------------------- */
2845 MAYBESTATICCONSTANT: {$$=0;}
2846 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2848 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2849 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2850 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2851 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2852 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2853 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2854 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2855 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2856 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2857 STATICCONSTANT : T_IDENTIFIER {
2858 if(!strcmp($1, "NaN")) {
2859 $$ = constant_new_float(__builtin_nan(""));
2861 as3_warning("Couldn't evaluate constant value of %s", $1);
2862 $$ = constant_new_null($1);
2866 /* ------------ classes and interfaces (body, functions) ------- */
2868 // non-vararg version
2871 memset(&$$,0,sizeof($$));
2873 MAYBE_PARAM_LIST: PARAM_LIST {
2879 MAYBE_PARAM_LIST: "..." PARAM {
2881 memset(&$$,0,sizeof($$));
2883 list_append($$.list, $2);
2885 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2889 list_append($$.list, $4);
2893 PARAM_LIST: PARAM_LIST ',' PARAM {
2896 list_append($$.list, $3);
2900 memset(&$$,0,sizeof($$));
2901 list_append($$.list, $1);
2904 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2906 $$ = rfx_calloc(sizeof(param_t));
2912 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2914 $$ = rfx_calloc(sizeof(param_t));
2916 $$->type = TYPE_ANY;
2924 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2925 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2928 endfunction(&$1,$3,$4,&$6,0,0);
2930 if(!state->method->info) syntaxerror("internal error");
2932 code_t*c = method_header(state->method);
2933 c = wrap_function(c, 0, $11);
2935 endfunction(&$1,$3,$4,&$6,$8,c);
2937 list_deep_free($6.list);
2941 MAYBE_IDENTIFIER: T_IDENTIFIER
2942 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2943 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2944 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2947 endfunction(0,0,$2,&$4,0,0);
2949 methodinfo_t*f = state->method->info;
2950 if(!f || !f->kind) syntaxerror("internal error");
2952 code_t*c = method_header(state->method);
2953 c = wrap_function(c, 0, $9);
2955 int index = state->method->var_index;
2956 endfunction(0,0,$2,&$4,$6,c);
2958 $$.c = abc_getlocal(0, index);
2959 $$.t = TYPE_FUNCTION(f);
2961 PASS12 list_deep_free($4.list);
2965 /* ------------- package + class ids --------------- */
2967 CLASS: X_IDENTIFIER {
2968 PASS1 NEW(unresolvedinfo_t,c);
2969 memset(c, 0, sizeof(*c));
2970 c->kind = INFOTYPE_UNRESOLVED;
2972 c->package = get_package_from_name($1);
2974 c->nsset = get_current_imports();
2975 /* make the compiler look for this class in the current directory,
2977 as3_schedule_class_noerror(state->package, $1);
2979 $$ = (classinfo_t*)c;
2981 slotinfo_t*s = find_class($1);
2982 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2983 $$ = (classinfo_t*)s;
2986 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2987 PASS1 NEW(unresolvedinfo_t,c);
2988 memset(c, 0, sizeof(*c));
2989 c->kind = INFOTYPE_UNRESOLVED;
2992 $$ = (classinfo_t*)c;
2994 slotinfo_t*s = registry_find($1, $3);
2995 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2997 $$ = (classinfo_t*)s;
3000 CLASS_SPEC: PACKAGEANDCLASS
3003 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
3004 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
3006 TYPE : CLASS_SPEC {PASS12 $$=$1;}
3007 | '*' {PASS12 $$=registry_getanytype();}
3008 | "void" {PASS12 $$=registry_getanytype();}
3010 | "String" {$$=registry_getstringclass();}
3011 | "int" {$$=registry_getintclass();}
3012 | "uint" {$$=registry_getuintclass();}
3013 | "Boolean" {$$=registry_getbooleanclass();}
3014 | "Number" {$$=registry_getnumberclass();}
3017 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
3018 MAYBETYPE: {PASS12 $$=0;}
3020 /* ----------function calls, delete, constructor calls ------ */
3022 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
3023 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
3025 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
3026 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
3027 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
3029 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
3033 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
3034 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
3035 $$.number= $1.number+1;
3036 $$.cc = code_append($1.cc, $2.c);
3040 NEW : "new" E XX MAYBE_PARAM_VALUES {
3042 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
3044 code_t*paramcode = $4.cc;
3045 if($$.c->opcode == OPCODE_GETPROPERTY) {
3046 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3047 $$.c = code_cutlast($$.c);
3048 $$.c = code_append($$.c, paramcode);
3049 $$.c = abc_constructprop2($$.c, name, $4.number);
3050 multiname_destroy(name);
3051 } else if($$.c->opcode == OPCODE_GETSLOT) {
3052 int slot = (int)(ptroff_t)$$.c->data[0];
3053 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3054 multiname_t*name = t->name;
3055 $$.c = code_cutlast($$.c);
3056 $$.c = code_append($$.c, paramcode);
3057 $$.c = abc_constructprop2($$.c, name, $4.number);
3059 $$.c = code_append($$.c, paramcode);
3060 $$.c = abc_construct($$.c, $4.number);
3064 if(TYPE_IS_CLASS($2.t) && $2.t->data) {
3067 $$.c = abc_coerce_a($$.c);
3072 /* TODO: use abc_call (for calling local variables),
3073 abc_callstatic (for calling own methods)
3076 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3079 if($$.c->opcode == OPCODE_COERCE_A) {
3080 $$.c = code_cutlast($$.c);
3082 code_t*paramcode = $3.cc;
3085 if($$.c->opcode == OPCODE_GETPROPERTY) {
3086 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3087 $$.c = code_cutlast($$.c);
3088 $$.c = code_append($$.c, paramcode);
3089 $$.c = abc_callproperty2($$.c, name, $3.number);
3090 multiname_destroy(name);
3091 } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3092 int slot = (int)(ptroff_t)$$.c->data[0];
3093 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3094 if(t->kind!=TRAIT_METHOD) {
3095 //ok: flash allows to assign closures to members.
3097 multiname_t*name = t->name;
3098 $$.c = code_cutlast($$.c);
3099 $$.c = code_append($$.c, paramcode);
3100 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3101 $$.c = abc_callproperty2($$.c, name, $3.number);
3102 } else if($$.c->opcode == OPCODE_GETSUPER) {
3103 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3104 $$.c = code_cutlast($$.c);
3105 $$.c = code_append($$.c, paramcode);
3106 $$.c = abc_callsuper2($$.c, name, $3.number);
3107 multiname_destroy(name);
3109 $$.c = abc_getglobalscope($$.c);
3110 $$.c = code_append($$.c, paramcode);
3111 $$.c = abc_call($$.c, $3.number);
3114 if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
3115 $$.t = ((methodinfo_t*)($1.t->data))->return_type;
3117 $$.c = abc_coerce_a($$.c);
3122 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3123 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3124 if(!state->method) syntaxerror("super() not allowed outside of a function");
3125 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3128 $$.c = abc_getlocal_0($$.c);
3130 $$.c = code_append($$.c, $3.cc);
3132 this is dependent on the control path, check this somewhere else
3133 if(state->method->has_super)
3134 syntaxerror("constructor may call super() only once");
3136 state->method->has_super = 1;
3138 $$.c = abc_constructsuper($$.c, $3.number);
3139 $$.c = abc_pushundefined($$.c);
3143 DELETE: "delete" E {
3145 if($$.c->opcode == OPCODE_COERCE_A) {
3146 $$.c = code_cutlast($$.c);
3148 multiname_t*name = 0;
3149 if($$.c->opcode == OPCODE_GETPROPERTY) {
3150 $$.c->opcode = OPCODE_DELETEPROPERTY;
3151 } else if($$.c->opcode == OPCODE_GETSLOT) {
3152 int slot = (int)(ptroff_t)$$.c->data[0];
3153 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3154 $$.c = code_cutlast($$.c);
3155 $$.c = abc_deleteproperty2($$.c, name);
3157 $$.c = abc_getlocal_0($$.c);
3158 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
3159 $$.c = abc_deleteproperty2($$.c, &m);
3161 $$.t = TYPE_BOOLEAN;
3164 RETURN: "return" %prec prec_none {
3165 $$ = abc_returnvoid(0);
3167 RETURN: "return" EXPRESSION {
3169 $$ = abc_returnvalue($$);
3172 // ----------------------- expression types -------------------------------------
3174 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
3175 EXPRESSION : E %prec below_minus {$$ = $1;}
3176 EXPRESSION : EXPRESSION ',' E %prec below_minus {
3178 $$.c = cut_last_push($$.c);
3179 $$.c = code_append($$.c,$3.c);
3182 VOIDEXPRESSION : EXPRESSION %prec below_minus {
3183 $$=cut_last_push($1.c);
3186 // ----------------------- expression evaluation -------------------------------------
3188 E : INNERFUNCTION %prec prec_none {$$ = $1;}
3190 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3192 E : DELETE {$$ = $1;}
3198 namespace_t ns = {ACCESS_PACKAGE, ""};
3199 multiname_t m = {QNAME, &ns, 0, "RegExp"};
3201 $$.c = abc_getlex2($$.c, &m);
3202 $$.c = abc_pushstring($$.c, $1.pattern);
3203 $$.c = abc_construct($$.c, 1);
3205 $$.c = abc_getlex2($$.c, &m);
3206 $$.c = abc_pushstring($$.c, $1.pattern);
3207 $$.c = abc_pushstring($$.c, $1.options);
3208 $$.c = abc_construct($$.c, 2);
3213 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
3214 //MULTINAME(m, registry_getintclass());
3215 //$$.c = abc_coerce2($$.c, &m); // FIXME
3218 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
3221 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
3224 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
3227 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
3230 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
3233 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
3236 CONSTANT : "true" {$$.c = abc_pushtrue(0);
3237 $$.t = TYPE_BOOLEAN;
3239 CONSTANT : "false" {$$.c = abc_pushfalse(0);
3240 $$.t = TYPE_BOOLEAN;
3242 CONSTANT : "null" {$$.c = abc_pushnull(0);
3246 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
3247 $$.t = TYPE_BOOLEAN;
3249 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
3250 $$.t = TYPE_BOOLEAN;
3252 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
3253 $$.t = TYPE_BOOLEAN;
3255 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
3256 $$.t = TYPE_BOOLEAN;
3258 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
3259 $$.t = TYPE_BOOLEAN;
3261 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
3262 $$.t = TYPE_BOOLEAN;
3264 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
3265 $$.t = TYPE_BOOLEAN;
3267 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
3268 $$.t = TYPE_BOOLEAN;
3271 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
3273 $$.c = converttype($$.c, $1.t, $$.t);
3274 $$.c = abc_dup($$.c);
3275 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
3276 $$.c = cut_last_push($$.c);
3277 $$.c = code_append($$.c,$3.c);
3278 $$.c = converttype($$.c, $3.t, $$.t);
3279 code_t*label = $$.c = abc_label($$.c);
3280 jmp->branch = label;
3283 $$.t = join_types($1.t, $3.t, 'A');
3284 /*printf("%08x:\n",$1.t);
3285 code_dump($1.c, 0, 0, "", stdout);
3286 printf("%08x:\n",$3.t);
3287 code_dump($3.c, 0, 0, "", stdout);
3288 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
3290 $$.c = converttype($$.c, $1.t, $$.t);
3291 $$.c = abc_dup($$.c);
3292 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
3293 $$.c = cut_last_push($$.c);
3294 $$.c = code_append($$.c,$3.c);
3295 $$.c = converttype($$.c, $3.t, $$.t);
3296 code_t*label = $$.c = abc_label($$.c);
3297 jmp->branch = label;
3300 E : '!' E {$$.c=$2.c;
3301 $$.c = abc_not($$.c);
3302 $$.t = TYPE_BOOLEAN;
3305 E : '~' E {$$.c=$2.c;
3306 $$.c = abc_bitnot($$.c);
3310 E : E '&' E {$$.c = code_append($1.c,$3.c);
3311 $$.c = abc_bitand($$.c);
3315 E : E '^' E {$$.c = code_append($1.c,$3.c);
3316 $$.c = abc_bitxor($$.c);
3320 E : E '|' E {$$.c = code_append($1.c,$3.c);
3321 $$.c = abc_bitor($$.c);
3325 E : E ">>" E {$$.c = code_append($1.c,$3.c);
3326 $$.c = abc_rshift($$.c);
3329 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
3330 $$.c = abc_urshift($$.c);
3333 E : E "<<" E {$$.c = code_append($1.c,$3.c);
3334 $$.c = abc_lshift($$.c);
3338 E : E '/' E {$$.c = code_append($1.c,$3.c);
3339 $$.c = abc_divide($$.c);
3342 E : E '%' E {$$.c = code_append($1.c,$3.c);
3343 $$.c = abc_modulo($$.c);
3346 E : E '+' E {$$.c = code_append($1.c,$3.c);
3347 if(BOTH_INT($1.t, $3.t)) {
3348 $$.c = abc_add_i($$.c);
3351 $$.c = abc_add($$.c);
3352 $$.t = join_types($1.t,$3.t,'+');
3355 E : E '-' E {$$.c = code_append($1.c,$3.c);
3356 if(BOTH_INT($1.t,$3.t)) {
3357 $$.c = abc_subtract_i($$.c);
3360 $$.c = abc_subtract($$.c);
3364 E : E '*' E {$$.c = code_append($1.c,$3.c);
3365 if(BOTH_INT($1.t,$3.t)) {
3366 $$.c = abc_multiply_i($$.c);
3369 $$.c = abc_multiply($$.c);
3374 E : E "in" E {$$.c = code_append($1.c,$3.c);
3375 $$.c = abc_in($$.c);
3376 $$.t = TYPE_BOOLEAN;
3379 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
3380 if(use_astype && TYPE_IS_CLASS($3.t) && $3.t->data) {
3381 MULTINAME(m, (classinfo_t*)($3.t->data));
3382 $$.c = abc_astype2($1.c, &m);
3385 $$.c = code_append($1.c, $3.c);
3386 $$.c = abc_astypelate($$.c);
3391 E : E "instanceof" E
3392 {$$.c = code_append($1.c, $3.c);
3393 $$.c = abc_instanceof($$.c);
3394 $$.t = TYPE_BOOLEAN;
3397 E : E "is" E {$$.c = code_append($1.c, $3.c);
3398 $$.c = abc_istypelate($$.c);
3399 $$.t = TYPE_BOOLEAN;
3402 E : "typeof" '(' E ')' {
3404 $$.c = abc_typeof($$.c);
3409 $$.c = cut_last_push($2.c);
3410 $$.c = abc_pushundefined($$.c);
3414 E : "void" { $$.c = abc_pushundefined(0);
3418 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
3423 $$.c=abc_negate_i($$.c);
3426 $$.c=abc_negate($$.c);
3433 $$.c = code_append($$.c, $3.c);
3435 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
3436 $$.c = abc_getproperty2($$.c, &m);
3437 $$.t = 0; // array elements have unknown type
3440 E : '[' MAYBE_EXPRESSION_LIST ']' {
3442 $$.c = code_append($$.c, $2.cc);
3443 $$.c = abc_newarray($$.c, $2.number);
3444 $$.t = registry_getarrayclass();
3447 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3448 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
3450 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3452 $$.cc = code_append($$.cc, $1.c);
3453 $$.cc = code_append($$.cc, $3.c);
3456 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3458 $$.number = $1.number+2;
3459 $$.cc = code_append($$.cc, $3.c);
3460 $$.cc = code_append($$.cc, $5.c);
3465 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
3467 $$.c = code_append($$.c, $2.cc);
3468 $$.c = abc_newobject($$.c, $2.number/2);
3469 $$.t = registry_getobjectclass();
3474 if(BOTH_INT($1.t,$3.t)) {
3475 c=abc_multiply_i(c);
3479 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
3480 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3485 code_t*c = abc_modulo($3.c);
3486 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
3487 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3491 code_t*c = abc_lshift($3.c);
3492 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
3493 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3497 code_t*c = abc_rshift($3.c);
3498 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
3499 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3503 code_t*c = abc_urshift($3.c);
3504 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
3505 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3509 code_t*c = abc_divide($3.c);
3510 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
3511 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3515 code_t*c = abc_bitor($3.c);
3516 c=converttype(c, TYPE_INT, $1.t);
3517 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3521 code_t*c = abc_bitxor($3.c);
3522 c=converttype(c, TYPE_INT, $1.t);
3523 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3529 if(TYPE_IS_INT($1.t)) {
3533 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
3536 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3539 E : E "-=" E { code_t*c = $3.c;
3540 if(TYPE_IS_INT($1.t)) {
3541 c=abc_subtract_i(c);
3544 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
3547 $$.c = toreadwrite($1.c, c, 0, 0, 1);
3550 E : E '=' E { code_t*c = 0;
3551 c = code_append(c, $3.c);
3552 c = converttype(c, $3.t, $1.t);
3553 $$.c = toreadwrite($1.c, c, 1, 0, 1);
3557 E : E '?' E ':' E %prec below_assignment {
3558 $$.t = join_types($3.t,$5.t,'?');
3560 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
3561 $$.c = code_append($$.c, $3.c);
3562 $$.c = converttype($$.c, $3.t, $$.t);
3563 code_t*j2 = $$.c = abc_jump($$.c, 0);
3564 $$.c = j1->branch = abc_label($$.c);
3565 $$.c = code_append($$.c, $5.c);
3566 $$.c = converttype($$.c, $5.t, $$.t);
3567 $$.c = j2->branch = abc_label($$.c);
3570 E : E "++" { code_t*c = 0;
3571 classinfo_t*type = $1.t;
3572 if(is_getlocal($1.c) && (TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t))) {
3573 int nr = getlocalnr($1.c);
3574 code_free($1.c);$1.c=0;
3575 if(TYPE_IS_INT($1.t)) {
3576 $$.c = abc_getlocal(0, nr);
3577 $$.c = abc_inclocal_i($$.c, nr);
3578 } else if(TYPE_IS_NUMBER($1.t)) {
3579 $$.c = abc_getlocal(0, nr);
3580 $$.c = abc_inclocal($$.c, nr);
3581 } else syntaxerror("internal error");
3583 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3584 c=abc_increment_i(c);
3590 c=converttype(c, type, $1.t);
3591 $$.c = toreadwrite($1.c, c, 0, 1, 1);
3596 // TODO: use inclocal, like with ++
3597 E : E "--" { code_t*c = 0;
3598 classinfo_t*type = $1.t;
3599 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3600 c=abc_decrement_i(c);
3606 c=converttype(c, type, $1.t);
3607 $$.c = toreadwrite($1.c, c, 0, 1, 1);
3611 E : "++" %prec plusplus_prefix E { code_t*c = 0;
3612 classinfo_t*type = $2.t;
3613 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3614 c=abc_increment_i(c);
3620 c=converttype(c, type, $2.t);
3621 $$.c = toreadwrite($2.c, c, 0, 0, 1);
3625 E : "--" %prec minusminus_prefix E { code_t*c = 0;
3626 classinfo_t*type = $2.t;
3627 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3628 c=abc_decrement_i(c);
3634 c=converttype(c, type, $2.t);
3635 $$.c = toreadwrite($2.c, c, 0, 0, 1);
3639 E : "super" '.' T_IDENTIFIER
3640 { if(!state->cls->info)
3641 syntaxerror("super keyword not allowed outside a class");
3642 classinfo_t*t = state->cls->info->superclass;
3643 if(!t) t = TYPE_OBJECT;
3645 memberinfo_t*f = findmember_nsset(t, $3, 1);
3647 MEMBER_MULTINAME(m, f, $3);
3649 $$.c = abc_getlocal_0($$.c);
3650 $$.c = abc_getsuper2($$.c, &m);
3651 $$.t = slotinfo_gettype((slotinfo_t*)f);
3654 E : '@' T_IDENTIFIER {
3656 $$.c = abc_pushundefined(0);
3658 as3_warning("ignored @ operator");
3661 E : E '.' '@' T_IDENTIFIER {
3662 // child attribute TODO
3663 $$.c = abc_pushundefined(0);
3665 as3_warning("ignored .@ operator");
3668 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3669 // namespace declaration TODO
3670 $$.c = abc_pushundefined(0);
3672 as3_warning("ignored :: operator");
3675 E : E ".." T_IDENTIFIER {
3677 $$.c = abc_pushundefined(0);
3679 as3_warning("ignored .. operator");
3682 E : E '.' '(' E ')' {
3684 $$.c = abc_pushundefined(0);
3686 as3_warning("ignored .() operator");
3689 //E : E "::" '[' E ']' {
3690 // // qualified expression TODO
3691 // $$.c = abc_pushundefined(0);
3693 // as3_warning("ignored ::[] operator");
3697 E : E '.' T_IDENTIFIER {
3699 classinfo_t*t = $1.t;
3701 if(TYPE_IS_CLASS(t) && t->data) {
3706 if(t->subtype==INFOTYPE_UNRESOLVED) {
3707 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3709 memberinfo_t*f = findmember_nsset(t, $3, 1);
3711 if(f && !is_static != !(f->flags&FLAG_STATIC))
3713 if(f && f->slot && !noslot) {
3714 $$.c = abc_getslot($$.c, f->slot);
3717 as3_warning("Access of undefined property '%s' in %s", $3, t->name);
3720 MEMBER_MULTINAME(m, f, $3);
3721 $$.c = abc_getproperty2($$.c, &m);
3723 /* determine type */
3724 $$.t = slotinfo_gettype((slotinfo_t*)f);
3726 $$.c = abc_coerce_a($$.c);
3727 } else if($1.c && $1.c->opcode == OPCODE___PUSHPACKAGE__) {
3728 string_t*package = $1.c->data[0];
3729 char*package2 = concat3(package->str, ".", $3);
3731 slotinfo_t*a = registry_find(package->str, $3);
3734 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3735 registry_ispackage(package2)) {
3737 $$.c->data[0] = string_new4(package2);
3740 syntaxerror("couldn't resolve %s", package2);
3743 /* when resolving a property on an unknown type, we do know the
3744 name of the property (and don't seem to need the package), but
3745 we need to make avm2 try out all access modes */
3746 as3_warning("Resolving %s on unknown type", $3);
3747 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3748 $$.c = abc_getproperty2($$.c, &m);
3749 $$.c = abc_coerce_a($$.c);
3750 $$.t = registry_getanytype();
3754 VAR_READ : T_IDENTIFIER {
3756 /* Queue unresolved identifiers for checking against the parent
3757 function's variables.
3758 We consider everything which is not a local variable "unresolved".
3759 This encompasses class names, members of the surrounding class
3760 etc. which is *correct* because local variables of the parent function
3763 if(state->method->inner && !find_variable(state, $1)) {
3764 unknown_variable($1);
3767 /* let the compiler know that it might want to check the current directory/package
3768 for this identifier- maybe there's a file $1.as defining $1. */
3769 as3_schedule_class_noerror(state->package, $1);
3778 /* look at variables */
3779 if((v = find_variable(state, $1))) {
3780 // $1 is a local variable
3781 $$.c = abc_getlocal($$.c, v->index);
3785 if((v = find_slot(state, $1))) {
3786 $$.c = abc_getscopeobject($$.c, 1);
3787 $$.c = abc_getslot($$.c, v->index);
3792 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3794 /* look at current class' members */
3795 if(!state->method->inner &&
3797 (f = findmember_nsset(state->cls->info, $1, 1)) &&
3798 (f->flags&FLAG_STATIC) >= i_am_static)
3800 // $1 is a function in this class
3801 int var_is_static = (f->flags&FLAG_STATIC);
3803 if(f->kind == INFOTYPE_METHOD) {
3804 $$.t = TYPE_FUNCTION(f);
3808 if(var_is_static && !i_am_static) {
3809 /* access to a static member from a non-static location.
3810 do this via findpropstrict:
3811 there doesn't seem to be any non-lookup way to access
3812 static properties of a class */
3813 state->method->late_binding = 1;
3815 namespace_t ns = {f->access, f->package};
3816 multiname_t m = {QNAME, &ns, 0, $1};
3817 $$.c = abc_findpropstrict2($$.c, &m);
3818 $$.c = abc_getproperty2($$.c, &m);
3820 } else if(f->slot>0) {
3821 $$.c = abc_getlocal_0($$.c);
3822 $$.c = abc_getslot($$.c, f->slot);
3825 namespace_t ns = {f->access, f->package};
3826 multiname_t m = {QNAME, &ns, 0, $1};
3827 $$.c = abc_getlocal_0($$.c);
3828 $$.c = abc_getproperty2($$.c, &m);
3833 /* look at actual classes, in the current package and imported */
3834 if((a = find_class($1))) {
3839 /* look through package prefixes */
3840 if(dict_contains(state->import_toplevel_packages, $1) ||
3841 registry_ispackage($1)) {
3842 $$.c = abc___pushpackage__($$.c, $1);
3847 /* unknown object, let the avm2 resolve it */
3849 //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3850 as3_warning("Couldn't resolve '%s', doing late binding", $1);
3851 state->method->late_binding = 1;
3853 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3856 $$.c = abc_findpropstrict2($$.c, &m);
3857 $$.c = abc_getproperty2($$.c, &m);
3861 // ----------------- namespaces -------------------------------------------------
3863 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3865 NEW(namespace_decl_t,n);
3870 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3872 NEW(namespace_decl_t,n);
3877 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3879 NEW(namespace_decl_t,n);
3884 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3886 trie_put(active_namespaces, $2->name, (void*)$2->url);
3888 namespace_t access = modifiers2access(&$1);
3889 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3890 var->type = TYPE_NAMESPACE;
3892 ns.access = ACCESS_NAMESPACE;
3894 var->value = constant_new_namespace(&ns);
3900 void add_active_url(const char*url)
3904 list_append(state->active_namespace_urls, n);
3908 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3910 const char*url = $3->name;
3912 varinfo_t*s = (varinfo_t*)$3;
3913 if(s->kind == INFOTYPE_UNRESOLVED) {
3914 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3916 syntaxerror("Couldn't resolve namespace %s", $3->name);
3919 if(!s || s->kind != INFOTYPE_SLOT)
3920 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3921 if(!s->value || !NS_TYPE(s->value->type))
3922 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3923 url = s->value->ns->name;
3925 trie_put(active_namespaces, $3->name, (void*)url);
3926 add_active_url(url);