3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
30 #include "tokenizer.h"
45 enum yytokentype token;
48 classinfo_t*classinfo;
49 classinfo_list_t*classinfo_list;
52 unsigned int number_uint;
56 //typedcode_list_t*value_list;
57 codeandnumber_t value_list;
63 for_start_t for_start;
64 abc_exception_t *exception;
67 abc_exception_list_t *l;
73 %token<id> T_IDENTIFIER
75 %token<regexp> T_REGEXP
77 %token<number_int> T_INT
78 %token<number_uint> T_UINT
79 %token<number_uint> T_BYTE
80 %token<number_uint> T_SHORT
81 %token<number_float> T_FLOAT
83 %token<id> T_FOR "for"
84 %token<id> T_WHILE "while"
86 %token<id> T_SWITCH "switch"
88 %token<token> KW_IMPLEMENTS "implements"
89 %token<token> KW_NAMESPACE "namespace"
90 %token<token> KW_PACKAGE "package"
91 %token<token> KW_PROTECTED "protected"
92 %token<token> KW_PUBLIC "public"
93 %token<token> KW_PRIVATE "private"
94 %token<token> KW_USE "use"
95 %token<token> KW_INTERNAL "internal"
96 %token<token> KW_NEW "new"
97 %token<token> KW_NATIVE "native"
98 %token<token> KW_FUNCTION "function"
99 %token<token> KW_FINALLY "finally"
100 %token<token> KW_UNDEFINED "undefined"
101 %token<token> KW_CONTINUE "continue"
102 %token<token> KW_CLASS "class"
103 %token<token> KW_CONST "const"
104 %token<token> KW_CATCH "catch"
105 %token<token> KW_CASE "case"
106 %token<token> KW_SET "set"
107 %token<token> KW_VOID "void"
108 %token<token> KW_THROW "throw"
109 %token<token> KW_STATIC "static"
110 %token<token> KW_WITH "with"
111 %token<token> KW_INSTANCEOF "instanceof"
112 %token<token> KW_IMPORT "import"
113 %token<token> KW_RETURN "return"
114 %token<token> KW_TYPEOF "typeof"
115 %token<token> KW_INTERFACE "interface"
116 %token<token> KW_NULL "null"
117 %token<token> KW_VAR "var"
118 %token<token> KW_DYNAMIC "dynamic"
119 %token<token> KW_OVERRIDE "override"
120 %token<token> KW_FINAL "final"
121 %token<token> KW_EACH "each"
122 %token<token> KW_GET "get"
123 %token<token> KW_TRY "try"
124 %token<token> KW_SUPER "super"
125 %token<token> KW_EXTENDS "extends"
126 %token<token> KW_FALSE "false"
127 %token<token> KW_TRUE "true"
128 %token<token> KW_BOOLEAN "Boolean"
129 %token<token> KW_UINT "uint"
130 %token<token> KW_INT "int"
131 %token<token> KW_NUMBER "Number"
132 %token<token> KW_STRING "String"
133 %token<token> KW_DEFAULT "default"
134 %token<token> KW_DELETE "delete"
135 %token<token> KW_IF "if"
136 %token<token> KW_ELSE "else"
137 %token<token> KW_BREAK "break"
138 %token<token> KW_IS "is"
139 %token<token> KW_IN "in"
140 %token<token> KW_AS "as"
142 %token<token> T_EQEQ "=="
143 %token<token> T_EQEQEQ "==="
144 %token<token> T_NE "!="
145 %token<token> T_NEE "!=="
146 %token<token> T_LE "<="
147 %token<token> T_GE ">="
148 %token<token> T_ORBY "|="
149 %token<token> T_DIVBY "/="
150 %token<token> T_MODBY "%="
151 %token<token> T_MULBY "*="
152 %token<token> T_PLUSBY "+="
153 %token<token> T_MINUSBY "-="
154 %token<token> T_SHRBY ">>="
155 %token<token> T_SHLBY "<<="
156 %token<token> T_USHRBY ">>>="
157 %token<token> T_OROR "||"
158 %token<token> T_ANDAND "&&"
159 %token<token> T_COLONCOLON "::"
160 %token<token> T_MINUSMINUS "--"
161 %token<token> T_PLUSPLUS "++"
162 %token<token> T_DOTDOT ".."
163 %token<token> T_DOTDOTDOT "..."
164 %token<token> T_SHL "<<"
165 %token<token> T_USHR ">>>"
166 %token<token> T_SHR ">>"
168 %type <for_start> FOR_START
169 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
170 %type <token> VARCONST
172 %type <code> CODEPIECE CODE_STATEMENT
173 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
174 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
175 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
176 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
177 %type <exception> CATCH FINALLY
178 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
179 %type <code> CLASS_DECLARATION
180 %type <code> NAMESPACE_DECLARATION
181 %type <code> INTERFACE_DECLARATION
182 %type <code> VOIDEXPRESSION
183 %type <value> EXPRESSION NONCOMMAEXPRESSION
184 %type <value> MAYBEEXPRESSION
185 %type <value> E DELETE
186 %type <value> CONSTANT
187 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
188 %type <value> INNERFUNCTION
189 %type <token> USE_NAMESPACE
190 %type <code> FOR_INIT
192 %type <classinfo> MAYBETYPE
195 %type <params> PARAM_LIST
196 %type <params> MAYBE_PARAM_LIST
197 %type <flags> MAYBE_MODIFIERS
198 %type <flags> MODIFIER_LIST
199 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
200 %type <classinfo_list> IMPLEMENTS_LIST
201 %type <classinfo> EXTENDS
202 %type <classinfo_list> EXTENDS_LIST
203 %type <classinfo> CLASS PACKAGEANDCLASS CLASS_SPEC
204 %type <classinfo_list> CLASS_SPEC_LIST
205 %type <classinfo> TYPE
206 //%type <token> VARIABLE
207 %type <value> VAR_READ
209 //%type <token> T_IDENTIFIER
210 %type <token> MODIFIER
211 %type <value> FUNCTIONCALL
212 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
214 // precedence: from low to high
218 %left below_semicolon
221 %nonassoc below_assignment // for ?:, contrary to spec
222 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
229 %nonassoc "==" "!=" "===" "!=="
230 %nonassoc "is" "as" "in"
231 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
232 %left "<<" ">>" ">>>"
236 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
238 %nonassoc below_curly
242 %left '[' ']' "new" '{' '.' ".." "::"
244 %nonassoc T_IDENTIFIER
245 %left above_identifier
249 // needed for "return" precedence:
250 %nonassoc T_STRING T_REGEXP
251 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
252 %nonassoc "false" "true" "null" "undefined" "super" "function"
259 static int a3_error(char*s)
261 syntaxerror("%s", s);
262 return 0; //make gcc happy
266 static char* concat2(const char* t1, const char* t2)
270 char*text = malloc(l1+l2+1);
271 memcpy(text , t1, l1);
272 memcpy(text+l1, t2, l2);
276 static char* concat3(const char* t1, const char* t2, const char* t3)
281 char*text = malloc(l1+l2+l3+1);
282 memcpy(text , t1, l1);
283 memcpy(text+l1, t2, l2);
284 memcpy(text+l1+l2, t3, l3);
289 typedef struct _import {
293 DECLARE_LIST(import);
295 typedef struct _classstate {
301 char has_constructor;
304 DECLARE_LIST(methodstate);
306 typedef struct _methodstate {
317 int var_index; // for inner methods
319 abc_exception_list_t*exceptions;
321 methodstate_list_t*innerfunctions;
324 typedef struct _state {
329 import_list_t*wildcard_imports;
331 char has_own_imports;
332 char new_vars; // e.g. transition between two functions
335 methodstate_t*method;
342 typedef struct _global {
348 static global_t*global = 0;
349 static state_t* state = 0;
353 #define MULTINAME(m,x) \
356 registry_fill_multiname(&m, &m##_ns, x);
358 #define MEMBER_MULTINAME(m,f,n) \
362 m##_ns = flags2namespace(f->flags, ""); \
365 m.namespace_set = 0; \
368 m.type = MULTINAME; \
370 m.namespace_set = &nopackage_namespace_set; \
374 /* warning: list length of namespace set is undefined */
375 #define MULTINAME_LATE(m, access, package) \
376 namespace_t m##_ns = {access, package}; \
377 namespace_set_t m##_nsset; \
378 namespace_list_t m##_l;m##_l.next = 0; \
379 m##_nsset.namespaces = &m##_l; \
380 m##_nsset = m##_nsset; \
381 m##_l.namespace = &m##_ns; \
382 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
384 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
385 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
386 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
387 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
388 static namespace_list_t nl4 = {&ns4,0};
389 static namespace_list_t nl3 = {&ns3,&nl4};
390 static namespace_list_t nl2 = {&ns2,&nl3};
391 static namespace_list_t nl1 = {&ns1,&nl2};
392 static namespace_set_t nopackage_namespace_set = {&nl1};
394 static void new_state()
397 state_t*oldstate = state;
399 memcpy(s, state, sizeof(state_t)); //shallow copy
401 s->imports = dict_new();
405 state->has_own_imports = 0;
406 state->vars = dict_new();
407 state->old = oldstate;
409 static void state_has_imports()
411 state->wildcard_imports = list_clone(state->wildcard_imports);
412 state->imports = dict_clone(state->imports);
413 state->has_own_imports = 1;
416 static void state_destroy(state_t*state)
418 if(state->has_own_imports) {
419 list_free(state->wildcard_imports);
420 dict_destroy(state->imports);state->imports=0;
422 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
423 dict_destroy(state->imports);state->imports=0;
427 for(t=0;t<state->vars->hashsize;t++) {
428 dictentry_t*e =state->vars->slots[t];
430 free(e->data);e->data=0;
434 dict_destroy(state->vars);state->vars=0;
440 static void old_state()
442 if(!state || !state->old)
443 syntaxerror("invalid nesting");
444 state_t*leaving = state;
448 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
449 free(leaving->method);
452 if(leaving->cls && leaving->cls != state->cls) {
457 state_destroy(leaving);
460 void initialize_file(char*filename)
463 syntaxerror("invalid call to initialize_file during parsing of another file");
466 state->package = strdup(filename);
468 state->method = rfx_calloc(sizeof(methodstate_t));
469 state->method->variable_count = 1;
474 if(!state || state->level!=1) {
475 syntaxerror("unexpected end of file in pass %d", as3_pass);
477 free(state->method);state->method=0;
479 //free(state->package);state->package=0; // used in registry
481 state_destroy(state);state=0;
484 void initialize_parser()
486 global = rfx_calloc(sizeof(global_t));
487 global->file = abc_file_new();
488 global->file->flags &= ~ABCFILE_LAZY;
489 global->token2info = dict_new2(&ptr_type);
491 global->init = abc_initscript(global->file);
492 code_t*c = global->init->method->body->code;
493 c = abc_getlocal_0(c);
494 c = abc_pushscope(c);
495 global->init->method->body->code = c;
498 void* finish_parser()
500 code_t*c = global->init->method->body->code;
501 /*c = abc_findpropstrict(c, "[package]::trace");
502 c = abc_pushstring(c, "[leaving global init function]");
503 c = abc_callpropvoid(c, "[package]::trace", 1);*/
504 c = abc_returnvoid(c);
505 global->init->method->body->code = c;
506 dict_destroy(global->token2info);global->token2info=0;
511 static void xx_scopetest()
513 /* findpropstrict doesn't just return a scope object- it
514 also makes it "active" somehow. Push local_0 on the
515 scope stack and read it back with findpropstrict, it'll
516 contain properties like "trace". Trying to find the same
517 property on a "vanilla" local_0 yields only a "undefined" */
518 //c = abc_findpropstrict(c, "[package]::trace");
520 /*c = abc_getlocal_0(c);
521 c = abc_findpropstrict(c, "[package]::trace");
523 c = abc_setlocal_1(c);
525 c = abc_pushbyte(c, 0);
526 c = abc_setlocal_2(c);
528 code_t*xx = c = abc_label(c);
529 c = abc_findpropstrict(c, "[package]::trace");
530 c = abc_pushstring(c, "prop:");
531 c = abc_hasnext2(c, 1, 2);
533 c = abc_setlocal_3(c);
534 c = abc_callpropvoid(c, "[package]::trace", 2);
535 c = abc_getlocal_3(c);
537 c = abc_iftrue(c,xx);*/
541 typedef struct _variable {
547 static variable_t* find_variable(char*name)
553 v = dict_lookup(s->vars, name);
563 static variable_t* find_variable_safe(char*name)
565 variable_t* v = find_variable(name);
567 syntaxerror("undefined variable: %s", name);
570 static char variable_exists(char*name)
572 return dict_lookup(state->vars, name)!=0;
574 code_t*defaultvalue(code_t*c, classinfo_t*type);
575 static int new_variable(const char*name, classinfo_t*type, char init)
578 v->index = state->method->variable_count;
582 dict_put(state->vars, name, v);
584 return state->method->variable_count++;
586 #define TEMPVARNAME "__as3_temp__"
587 static int gettempvar()
589 variable_t*v = find_variable(TEMPVARNAME);
592 return new_variable(TEMPVARNAME, 0, 0);
595 code_t* var_block(code_t*body)
601 for(t=0;t<state->vars->hashsize;t++) {
602 dictentry_t*e = state->vars->slots[t];
604 variable_t*v = (variable_t*)e->data;
605 if(v->type && v->init) {
606 c = defaultvalue(c, v->type);
607 c = abc_setlocal(c, v->index);
608 k = abc_kill(k, v->index);
618 if(x->opcode== OPCODE___BREAK__ ||
619 x->opcode== OPCODE___CONTINUE__) {
620 /* link kill code before break/continue */
621 code_t*e = code_dup(k);
622 code_t*s = code_start(e);
634 c = code_append(c, body);
635 c = code_append(c, k);
639 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
641 static void parsererror(const char*file, int line, const char*f)
643 syntaxerror("internal error in %s, %s:%d", f, file, line);
647 code_t* method_header()
650 if(state->method->late_binding && !state->method->inner) {
651 c = abc_getlocal_0(c);
652 c = abc_pushscope(c);
654 /*if(state->method->innerfunctions) {
655 c = abc_newactivation(c);
656 c = abc_pushscope(c);
658 if(state->method->is_constructor && !state->method->has_super) {
659 // call default constructor
660 c = abc_getlocal_0(c);
661 c = abc_constructsuper(c, 0);
663 methodstate_list_t*l = state->method->innerfunctions;
665 parserassert(l->methodstate->abc);
666 c = abc_newfunction(c, l->methodstate->abc);
667 c = abc_setlocal(c, l->methodstate->var_index);
668 free(l->methodstate);l->methodstate=0;
671 list_free(state->method->innerfunctions);
672 state->method->innerfunctions = 0;
677 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
679 c = code_append(c, header);
680 c = code_append(c, var_block(body));
681 /* append return if necessary */
682 if(!c || (c->opcode != OPCODE_RETURNVOID &&
683 c->opcode != OPCODE_RETURNVALUE)) {
684 c = abc_returnvoid(c);
690 static void startpackage(char*name)
693 /*printf("entering package \"%s\"\n", name);*/
694 state->package = strdup(name);
696 static void endpackage()
698 /*printf("leaving package \"%s\"\n", state->package);*/
700 //used e.g. in classinfo_register:
701 //free(state->package);state->package=0;
707 char*as3_globalclass=0;
708 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
711 syntaxerror("inner classes now allowed");
714 state->cls = rfx_calloc(sizeof(classstate_t));
717 classinfo_list_t*mlist=0;
719 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
720 syntaxerror("invalid modifier(s)");
722 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
723 syntaxerror("public and internal not supported at the same time.");
725 /* create the class name, together with the proper attributes */
729 if(!(flags&FLAG_PUBLIC) && !state->package) {
730 access = ACCESS_PRIVATE; package = strdup(current_filename_short);
731 } else if(!(flags&FLAG_PUBLIC) && state->package) {
732 access = ACCESS_PACKAGEINTERNAL; package = state->package;
733 } else if(state->package) {
734 access = ACCESS_PACKAGE; package = state->package;
736 syntaxerror("public classes only allowed inside a package");
740 state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
741 state->method->variable_count = 1;
742 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
744 if(registry_findclass(package, classname)) {
745 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
747 /* build info struct */
748 int num_interfaces = (list_length(implements));
749 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
753 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
755 state->cls->info = registry_findclass(package, classname);
756 parserassert((int)state->cls->info);
758 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
759 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
761 classinfo_list_t*l = implements;
762 for(l=implements;l;l=l->next) {
763 state->cls->info->interfaces[pos++] = l->classinfo;
766 /* generate the abc code for this class */
767 MULTINAME(classname2,state->cls->info);
768 multiname_t*extends2 = sig2mname(extends);
770 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
771 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
772 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
774 state->cls->info->flags |= CLASS_INTERFACE;
775 abc_class_interface(state->cls->abc);
778 abc_class_protectedNS(state->cls->abc, classname);
780 for(mlist=implements;mlist;mlist=mlist->next) {
781 MULTINAME(m, mlist->classinfo);
782 abc_class_add_interface(state->cls->abc, &m);
785 /* write the construction code for this class to the global init
787 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
789 abc_method_body_t*m = global->init->method->body;
790 __ getglobalscope(m);
791 classinfo_t*s = extends;
796 //TODO: take a look at the current scope stack, maybe
797 // we can re-use something
802 multiname_t*s2 = sig2mname(s);
804 multiname_destroy(s2);
806 __ pushscope(m); count++;
807 m->code = m->code->prev->prev; // invert
809 /* continue appending after last op end */
810 while(m->code && m->code->next) m->code = m->code->next;
812 /* TODO: if this is one of *our* classes, we can also
813 do a getglobalscope/getslot <nr> (which references
814 the init function's slots) */
816 __ getlex2(m, extends2);
818 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
819 stack is not the superclass */
820 __ pushscope(m);count++;
823 /* notice: we get a verify error #1107 if the top element on the scope
824 stack is not the global object */
826 __ pushscope(m);count++;
828 __ newclass(m,state->cls->abc);
832 __ setslot(m, slotindex);
833 multiname_destroy(extends2);
835 /* flash.display.MovieClip handling */
837 if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
838 if(state->package && state->package[0]) {
839 as3_globalclass = concat3(state->package, ".", classname);
841 as3_globalclass = strdup(classname);
847 static void endclass()
850 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
852 c = abc_getlocal_0(c);
853 c = abc_constructsuper(c, 0);
854 state->cls->init = code_append(state->cls->init, c);
856 if(!state->method->late_binding) {
857 // class initialization code uses late binding
859 c = abc_getlocal_0(c);
860 c = abc_pushscope(c);
861 state->cls->static_init = code_append(c, state->cls->static_init);
864 if(state->cls->init) {
865 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
866 m->body->code = wrap_function(0, state->cls->init, m->body->code);
868 if(state->cls->static_init) {
869 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
870 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
877 void check_code_for_break(code_t*c)
880 if(c->opcode == OPCODE___BREAK__) {
881 char*name = string_cstr(c->data[0]);
882 syntaxerror("Unresolved \"break %s\"", name);
884 if(c->opcode == OPCODE___CONTINUE__) {
885 char*name = string_cstr(c->data[0]);
886 syntaxerror("Unresolved \"continue %s\"", name);
893 static void check_constant_against_type(classinfo_t*t, constant_t*c)
895 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
896 if(TYPE_IS_NUMBER(t)) {
897 xassert(c->type == CONSTANT_FLOAT
898 || c->type == CONSTANT_INT
899 || c->type == CONSTANT_UINT);
900 } else if(TYPE_IS_UINT(t)) {
901 xassert(c->type == CONSTANT_UINT ||
902 (c->type == CONSTANT_INT && c->i>0));
903 } else if(TYPE_IS_INT(t)) {
904 xassert(c->type == CONSTANT_INT);
905 } else if(TYPE_IS_BOOLEAN(t)) {
906 xassert(c->type == CONSTANT_TRUE
907 || c->type == CONSTANT_FALSE);
912 static int flags2access(int flags)
915 if(flags&FLAG_PUBLIC) {
916 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
917 syntaxerror("invalid combination of access levels");
918 access = ACCESS_PACKAGE;
919 } else if(flags&FLAG_PRIVATE) {
920 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
921 syntaxerror("invalid combination of access levels");
922 access = ACCESS_PRIVATE;
923 } else if(flags&FLAG_PROTECTED) {
924 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
925 syntaxerror("invalid combination of access levels");
926 access = ACCESS_PROTECTED;
928 access = ACCESS_PACKAGEINTERNAL;
934 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
936 memberinfo_t*minfo = 0;
939 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
940 minfo->return_type = return_type;
941 } else if(getset != KW_GET && getset != KW_SET) {
943 if((minfo = registry_findmember(state->cls->info, name, 0))) {
944 if(minfo->parent == state->cls->info) {
945 syntaxerror("class already contains a member/method called '%s'", name);
946 } else if(!minfo->parent) {
947 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
949 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
950 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
953 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
954 minfo->return_type = return_type;
955 // getslot on a member slot only returns "undefined", so no need
956 // to actually store these
957 //state->minfo->slot = state->method->abc->method->trait->slot_id;
959 //class getter/setter
960 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
964 else if(params->list && params->list->param)
965 type = params->list->param->type;
966 // not sure wether to look into superclasses here, too
967 if((minfo=registry_findmember(state->cls->info, name, 0))) {
968 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
969 syntaxerror("class already contains a member or method called '%s'", name);
971 syntaxerror("getter/setter for '%s' already defined", name);
972 /* make a setter or getter into a getset */
977 if(type && minfo->type != type)
978 syntaxerror("different type in getter and setter");
980 minfo = memberinfo_register(state->cls->info, name, gs);
983 /* can't assign a slot as getter and setter might have different slots */
984 //minfo->slot = slot;
986 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
987 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
988 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
989 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
990 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
991 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
995 static void function_initvars(params_t*params, int flags)
997 if(state->method->inner)
998 new_variable("this", 0, 0);
999 else if(!state->method->is_global)
1000 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
1002 new_variable("globalscope", 0, 0);
1005 for(p=params->list;p;p=p->next) {
1006 new_variable(p->param->name, p->param->type, 0);
1009 methodstate_list_t*l = state->method->innerfunctions;
1011 methodstate_t*m = l->methodstate;
1012 m->var_index = new_variable(m->info->name, TYPE_FUNCTION(m->info), 0);
1017 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1019 parserassert(state->method && state->method->info);
1021 methodstate_t*parent_method = state->method;
1030 state->new_vars = 1;
1033 state->method = rfx_calloc(sizeof(methodstate_t));
1034 state->method->inner = 1;
1035 state->method->variable_count = 0;
1036 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1038 NEW(memberinfo_t,minfo);
1040 state->method->info = minfo;
1042 list_append(parent_method->innerfunctions, state->method);
1044 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1048 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1049 parserassert(state->method);
1051 state->method->info->return_type = return_type;
1052 function_initvars(params, 0);
1056 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
1057 params_t*params, classinfo_t*return_type)
1059 if(state->method && state->method->info) {
1060 syntaxerror("not able to start another method scope");
1065 state->method = rfx_calloc(sizeof(methodstate_t));
1066 state->method->has_super = 0;
1067 state->method->variable_count = 0;
1070 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1072 state->method->is_global = 1;
1073 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1075 if(state->method->is_constructor)
1076 name = "__as3_constructor__";
1079 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
1081 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1085 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1086 parserassert(state->method);
1089 state->cls->has_constructor |= state->method->is_constructor;
1092 state->method->info->return_type = return_type;
1093 function_initvars(params, flags);
1097 static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
1098 params_t*params, classinfo_t*return_type, code_t*body)
1107 multiname_t*type2 = sig2mname(return_type);
1109 if(state->method->inner) {
1110 f = state->method->abc;
1111 abc_method_init(f, global->file, type2, 1);
1112 } else if(state->method->is_constructor) {
1113 f = abc_class_getconstructor(state->cls->abc, type2);
1114 } else if(!state->method->is_global) {
1115 namespace_t mname_ns = flags2namespace(flags, "");
1116 multiname_t mname = {QNAME, &mname_ns, 0, name};
1118 if(flags&FLAG_STATIC)
1119 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1121 f = abc_class_method(state->cls->abc, type2, &mname);
1122 slot = f->trait->slot_id;
1124 namespace_t mname_ns = flags2namespace(flags, state->package);
1125 multiname_t mname = {QNAME, &mname_ns, 0, name};
1127 f = abc_method_new(global->file, type2, 1);
1128 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1129 //abc_code_t*c = global->init->method->body->code;
1131 //flash doesn't seem to allow us to access function slots
1132 //state->method->info->slot = slot;
1134 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1135 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1136 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1137 if(params->varargs) f->flags |= METHOD_NEED_REST;
1141 for(p=params->list;p;p=p->next) {
1142 if(params->varargs && !p->next) {
1143 break; //varargs: omit last parameter in function signature
1145 multiname_t*m = sig2mname(p->param->type);
1146 list_append(f->parameters, m);
1147 if(p->param->value) {
1148 check_constant_against_type(p->param->type, p->param->value);
1149 opt=1;list_append(f->optional_parameters, p->param->value);
1151 syntaxerror("non-optional parameter not allowed after optional parameters");
1154 check_code_for_break(body);
1157 f->body->code = body;
1158 f->body->exceptions = state->method->exceptions;
1159 } else { //interface
1161 syntaxerror("interface methods can't have a method body");
1168 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1173 void breakjumpsto(code_t*c, char*name, code_t*jump)
1176 if(c->opcode == OPCODE___BREAK__) {
1177 string_t*name2 = c->data[0];
1178 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1179 c->opcode = OPCODE_JUMP;
1186 void continuejumpsto(code_t*c, char*name, code_t*jump)
1189 if(c->opcode == OPCODE___CONTINUE__) {
1190 string_t*name2 = c->data[0];
1191 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1192 c->opcode = OPCODE_JUMP;
1200 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1201 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1202 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1204 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1206 if(!type1 || !type2)
1207 return registry_getanytype();
1208 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1209 return registry_getanytype();
1212 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1221 return registry_getanytype();
1223 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1228 return abc_coerce_a(c);
1232 // cast an "any" type to a specific type. subject to
1233 // runtime exceptions
1234 return abc_coerce2(c, &m);
1237 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1238 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1239 // allow conversion between number types
1240 return abc_coerce2(c, &m);
1242 //printf("%s.%s\n", from.package, from.name);
1243 //printf("%s.%s\n", to.package, to.name);
1245 classinfo_t*supertype = from;
1247 if(supertype == to) {
1248 // target type is one of from's superclasses
1249 return abc_coerce2(c, &m);
1252 while(supertype->interfaces[t]) {
1253 if(supertype->interfaces[t]==to) {
1254 // target type is one of from's interfaces
1255 return abc_coerce2(c, &m);
1259 supertype = supertype->superclass;
1261 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1263 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1265 syntaxerror("can't convert type %s to %s", from->name, to->name);
1266 return 0; // make gcc happy
1269 code_t*defaultvalue(code_t*c, classinfo_t*type)
1271 if(TYPE_IS_INT(type)) {
1272 c = abc_pushbyte(c, 0);
1273 } else if(TYPE_IS_UINT(type)) {
1274 c = abc_pushuint(c, 0);
1275 } else if(TYPE_IS_FLOAT(type)) {
1277 } else if(TYPE_IS_BOOLEAN(type)) {
1278 c = abc_pushfalse(c);
1280 //c = abc_pushundefined(c);
1282 c = abc_pushnull(c);
1284 c = abc_coerce2(c, &m);
1289 char is_pushundefined(code_t*c)
1291 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1294 static classinfo_t* find_class(char*name)
1298 c = registry_findclass(state->package, name);
1301 /* try explicit imports */
1302 dictentry_t* e = dict_get_slot(state->imports, name);
1305 if(!strcmp(e->key, name)) {
1306 c = (classinfo_t*)e->data;
1312 /* try package.* imports */
1313 import_list_t*l = state->wildcard_imports;
1315 //printf("does package %s contain a class %s?\n", l->import->package, name);
1316 c = registry_findclass(l->import->package, name);
1321 /* try global package */
1322 c = registry_findclass("", name);
1325 /* try local "filename" package */
1326 c = registry_findclass(current_filename_short, name);
1332 static char is_getlocal(code_t*c)
1334 if(!c || c->prev || c->next)
1336 return(c->opcode == OPCODE_GETLOCAL
1337 || c->opcode == OPCODE_GETLOCAL_0
1338 || c->opcode == OPCODE_GETLOCAL_1
1339 || c->opcode == OPCODE_GETLOCAL_2
1340 || c->opcode == OPCODE_GETLOCAL_3);
1342 static int getlocalnr(code_t*c)
1344 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1345 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1346 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1347 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1348 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1349 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1353 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1357 [prefix code] [read instruction]
1361 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1363 if(in && in->opcode == OPCODE_COERCE_A) {
1364 in = code_cutlast(in);
1367 syntaxerror("internal error");
1369 /* chop off read instruction */
1373 prefix = r->prev;r->prev = 0;
1379 char use_temp_var = readbefore;
1381 /* generate the write instruction, and maybe append a dup to the prefix code */
1382 code_t* write = abc_nop(0);
1383 if(r->opcode == OPCODE_GETPROPERTY) {
1384 write->opcode = OPCODE_SETPROPERTY;
1385 multiname_t*m = (multiname_t*)r->data[0];
1386 write->data[0] = multiname_clone(m);
1387 if(m->type == QNAME || m->type == MULTINAME) {
1389 prefix = abc_dup(prefix); // we need the object, too
1392 } else if(m->type == MULTINAMEL) {
1394 /* dupping two values on the stack requires 5 operations and one register-
1395 couldn't adobe just have given us a dup2? */
1396 int temp = gettempvar();
1397 prefix = abc_setlocal(prefix, temp);
1398 prefix = abc_dup(prefix);
1399 prefix = abc_getlocal(prefix, temp);
1400 prefix = abc_swap(prefix);
1401 prefix = abc_getlocal(prefix, temp);
1403 prefix = abc_kill(prefix, temp);
1407 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1409 } else if(r->opcode == OPCODE_GETSLOT) {
1410 write->opcode = OPCODE_SETSLOT;
1411 write->data[0] = r->data[0];
1413 prefix = abc_dup(prefix); // we need the object, too
1416 } else if(r->opcode == OPCODE_GETLOCAL) {
1417 write->opcode = OPCODE_SETLOCAL;
1418 write->data[0] = r->data[0];
1419 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1420 write->opcode = OPCODE_SETLOCAL_0;
1421 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1422 write->opcode = OPCODE_SETLOCAL_1;
1423 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1424 write->opcode = OPCODE_SETLOCAL_2;
1425 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1426 write->opcode = OPCODE_SETLOCAL_3;
1429 syntaxerror("illegal lvalue: can't assign a value to this expression");
1436 /* with getproperty/getslot, we have to be extra careful not
1437 to execute the read code twice, as it might have side-effects
1438 (e.g. if the property is in fact a setter/getter combination)
1440 So read the value, modify it, and write it again,
1441 using prefix only once and making sure (by using a temporary
1442 register) that the return value is what we just wrote */
1443 temp = gettempvar();
1444 c = code_append(c, prefix);
1445 c = code_append(c, r);
1448 c = abc_setlocal(c, temp);
1450 c = code_append(c, middlepart);
1453 c = abc_setlocal(c, temp);
1455 c = code_append(c, write);
1456 c = abc_getlocal(c, temp);
1457 c = abc_kill(c, temp);
1459 /* if we're allowed to execute the read code twice *and*
1460 the middlepart doesn't modify the code, things are easier.
1462 code_t* r2 = code_dup(r);
1463 //c = code_append(c, prefix);
1464 parserassert(!prefix);
1465 c = code_append(c, r);
1466 c = code_append(c, middlepart);
1467 c = code_append(c, write);
1468 c = code_append(c, r2);
1471 /* even smaller version: overwrite the value without reading
1475 c = code_append(c, prefix);
1478 c = code_append(c, middlepart);
1479 c = code_append(c, write);
1480 c = code_append(c, r);
1483 temp = gettempvar();
1485 c = code_append(c, prefix);
1487 c = code_append(c, middlepart);
1489 c = abc_setlocal(c, temp);
1490 c = code_append(c, write);
1491 c = abc_getlocal(c, temp);
1492 c = abc_kill(c, temp);
1498 char is_break_or_jump(code_t*c)
1502 if(c->opcode == OPCODE_JUMP ||
1503 c->opcode == OPCODE___BREAK__ ||
1504 c->opcode == OPCODE___CONTINUE__ ||
1505 c->opcode == OPCODE_THROW ||
1506 c->opcode == OPCODE_RETURNVOID ||
1507 c->opcode == OPCODE_RETURNVALUE) {
1514 #define IS_FINALLY_TARGET(op) \
1515 ((op) == OPCODE___CONTINUE__ || \
1516 (op) == OPCODE___BREAK__ || \
1517 (op) == OPCODE_RETURNVOID || \
1518 (op) == OPCODE_RETURNVALUE || \
1519 (op) == OPCODE___RETHROW__)
1521 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1523 #define NEED_EXTRA_STACK_ARG
1524 code_t*finally_label = abc_nop(0);
1525 NEW(lookupswitch_t, l);
1531 code_t*prev = i->prev;
1532 if(IS_FINALLY_TARGET(i->opcode)) {
1535 if(i->opcode == OPCODE___RETHROW__ ||
1536 i->opcode == OPCODE_RETURNVALUE) {
1537 if(i->opcode == OPCODE___RETHROW__)
1538 i->opcode = OPCODE_THROW;
1540 p = abc_coerce_a(p);
1541 p = abc_setlocal(p, tempvar);
1543 p = abc_pushbyte(p, count++);
1544 p = abc_jump(p, finally_label);
1545 code_t*target = p = abc_label(p);
1546 #ifdef NEED_EXTRA_STACK_ARG
1550 p = abc_getlocal(p, tempvar);
1553 p->next = i;i->prev = p;
1554 list_append(l->targets, target);
1560 c = abc_pushbyte(c, -1);
1561 c = code_append(c, finally_label);
1562 c = code_append(c, finally);
1564 #ifdef NEED_EXTRA_STACK_ARG
1567 c = abc_lookupswitch(c, l);
1568 c = l->def = abc_label(c);
1569 #ifdef NEED_EXTRA_STACK_ARG
1576 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1580 code_t*prev = i->prev;
1581 if(IS_FINALLY_TARGET(i->opcode)) {
1582 if(i->opcode == OPCODE___RETHROW__)
1583 i->opcode = OPCODE_THROW;
1584 code_t*end = code_dup(finally);
1585 code_t*start = code_start(end);
1586 if(prev) prev->next = start;
1593 return code_append(c, finally);
1596 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1602 int num_insertion_points=0;
1604 if(IS_FINALLY_TARGET(i->opcode))
1605 num_insertion_points++;
1612 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1617 int simple_version_cost = (1+num_insertion_points)*code_size;
1618 int lookup_version_cost = 4*num_insertion_points + 5;
1620 if(cantdup || simple_version_cost > lookup_version_cost) {
1621 printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
1622 return insert_finally_lookup(c, finally, tempvar);
1624 printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
1625 return insert_finally_simple(c, finally, tempvar);
1629 #define PASS1 }} if(as3_pass == 1) {{
1630 #define PASS1END }} if(as3_pass == 2) {{
1631 #define PASS2 }} if(as3_pass == 2) {{
1632 #define PASS12 }} {{
1633 #define PASS12END }} if(as3_pass == 2) {{
1639 /* ------------ code blocks / statements ---------------- */
1641 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1643 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1644 PROGRAM_CODE_LIST: PROGRAM_CODE
1645 | PROGRAM_CODE_LIST PROGRAM_CODE
1647 PROGRAM_CODE: PACKAGE_DECLARATION
1648 | INTERFACE_DECLARATION
1650 | FUNCTION_DECLARATION
1653 | T_IDENTIFIER "::" T_IDENTIFIER '{' PROGRAM_CODE_LIST '}' // conditional compilation
1656 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1657 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1658 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1660 INPACKAGE_CODE: INTERFACE_DECLARATION
1662 | FUNCTION_DECLARATION
1665 | T_IDENTIFIER "::" T_IDENTIFIER '{' INPACKAGE_CODE_LIST '}' // conditional compilation
1668 MAYBECODE: CODE {$$=$1;}
1669 MAYBECODE: {$$=code_new();}
1671 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1672 CODE: CODEPIECE {$$=$1;}
1674 // code which also may appear outside a method
1675 CODE_STATEMENT: IMPORT
1677 CODE_STATEMENT: FOR_IN
1678 CODE_STATEMENT: WHILE
1679 CODE_STATEMENT: DO_WHILE
1680 CODE_STATEMENT: SWITCH
1682 CODE_STATEMENT: WITH
1684 CODE_STATEMENT: VOIDEXPRESSION
1686 // code which may appear anywhere
1687 CODEPIECE: ';' {$$=0;}
1688 CODEPIECE: CODE_STATEMENT
1689 CODEPIECE: VARIABLE_DECLARATION
1695 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1696 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1698 CODEBLOCK : '{' CODE '}' {$$=$2;}
1699 CODEBLOCK : '{' '}' {$$=0;}
1700 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1701 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1703 /* ------------ package init code ------------------- */
1705 PACKAGE_INITCODE: CODE_STATEMENT {
1706 code_t**cc = &global->init->method->body->code;
1707 *cc = code_append(*cc, $1);
1710 /* ------------ variables --------------------------- */
1712 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1713 | {$$.c=abc_pushundefined(0);
1717 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1718 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1720 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1721 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1723 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1725 if(variable_exists($1))
1726 syntaxerror("Variable %s already defined", $1);
1728 if(!is_subtype_of($3.t, $2)) {
1729 syntaxerror("Can't convert %s to %s", $3.t->name,
1733 int index = new_variable($1, $2, 1);
1736 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1738 $$ = converttype($$, $3.t, $2);
1739 $$ = abc_setlocal($$, index);
1742 $$ = defaultvalue(0, $2);
1743 $$ = abc_setlocal($$, index);
1746 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1748 $$ = abc_coerce_a($$);
1749 $$ = abc_setlocal($$, index);
1756 /* that's the default for a local register, anyway
1758 state->method->initcode = abc_pushundefined(state->method->initcode);
1759 state->method->initcode = abc_setlocal(state->method->initcode, index);
1761 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1764 /* ------------ control flow ------------------------- */
1766 MAYBEELSE: %prec below_else {$$ = code_new();}
1767 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1768 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1770 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1773 $$ = code_append($$, $4.c);
1774 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1776 $$ = code_append($$, $6);
1778 myjmp = $$ = abc_jump($$, 0);
1780 myif->branch = $$ = abc_nop($$);
1782 $$ = code_append($$, $7);
1783 myjmp->branch = $$ = abc_nop($$);
1789 FOR_INIT : {$$=code_new();}
1790 FOR_INIT : VARIABLE_DECLARATION
1791 FOR_INIT : VOIDEXPRESSION
1793 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1794 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1795 $$=$2;new_variable($2,$3,1);
1797 FOR_IN_INIT : T_IDENTIFIER {
1801 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1802 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1804 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1805 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1807 $$ = code_append($$, $2);
1808 code_t*loopstart = $$ = abc_label($$);
1809 $$ = code_append($$, $4.c);
1810 code_t*myif = $$ = abc_iffalse($$, 0);
1811 $$ = code_append($$, $8);
1812 code_t*cont = $$ = abc_nop($$);
1813 $$ = code_append($$, $6);
1814 $$ = abc_jump($$, loopstart);
1815 code_t*out = $$ = abc_nop($$);
1816 breakjumpsto($$, $1.name, out);
1817 continuejumpsto($$, $1.name, cont);
1824 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1825 variable_t*var = find_variable($2);
1826 char*tmp1name = concat2($2, "__tmp1__");
1827 int it = new_variable(tmp1name, TYPE_INT, 0);
1828 char*tmp2name = concat2($2, "__array__");
1829 int array = new_variable(tmp1name, 0, 0);
1832 $$ = code_append($$, $4.c);
1833 $$ = abc_coerce_a($$);
1834 $$ = abc_setlocal($$, array);
1835 $$ = abc_pushbyte($$, 0);
1836 $$ = abc_setlocal($$, it);
1838 code_t*loopstart = $$ = abc_label($$);
1840 $$ = abc_hasnext2($$, array, it);
1841 code_t*myif = $$ = abc_iffalse($$, 0);
1842 $$ = abc_getlocal($$, array);
1843 $$ = abc_getlocal($$, it);
1845 $$ = abc_nextname($$);
1847 $$ = abc_nextvalue($$);
1848 $$ = converttype($$, 0, var->type);
1849 $$ = abc_setlocal($$, var->index);
1851 $$ = code_append($$, $6);
1852 $$ = abc_jump($$, loopstart);
1854 code_t*out = $$ = abc_nop($$);
1855 breakjumpsto($$, $1.name, out);
1856 continuejumpsto($$, $1.name, loopstart);
1867 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1871 code_t*myjmp = $$ = abc_jump($$, 0);
1872 code_t*loopstart = $$ = abc_label($$);
1873 $$ = code_append($$, $6);
1874 code_t*cont = $$ = abc_nop($$);
1875 myjmp->branch = cont;
1876 $$ = code_append($$, $4.c);
1877 $$ = abc_iftrue($$, loopstart);
1878 code_t*out = $$ = abc_nop($$);
1879 breakjumpsto($$, $1, out);
1880 continuejumpsto($$, $1, cont);
1886 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1888 code_t*loopstart = $$ = abc_label($$);
1889 $$ = code_append($$, $3);
1890 code_t*cont = $$ = abc_nop($$);
1891 $$ = code_append($$, $6.c);
1892 $$ = abc_iftrue($$, loopstart);
1893 code_t*out = $$ = abc_nop($$);
1894 breakjumpsto($$, $1, out);
1895 continuejumpsto($$, $1, cont);
1901 BREAK : "break" %prec prec_none {
1902 $$ = abc___break__(0, "");
1904 BREAK : "break" T_IDENTIFIER {
1905 $$ = abc___break__(0, $2);
1907 CONTINUE : "continue" %prec prec_none {
1908 $$ = abc___continue__(0, "");
1910 CONTINUE : "continue" T_IDENTIFIER {
1911 $$ = abc___continue__(0, $2);
1914 MAYBE_CASE_LIST : {$$=0;}
1915 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1916 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1917 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1918 CASE_LIST: CASE {$$=$1;}
1919 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1921 CASE: "case" E ':' MAYBECODE {
1923 $$ = code_append($$, $2.c);
1924 code_t*j = $$ = abc_ifne($$, 0);
1925 $$ = code_append($$, $4);
1926 if($$->opcode != OPCODE___BREAK__) {
1927 $$ = abc___fallthrough__($$, "");
1929 code_t*e = $$ = abc_nop($$);
1932 DEFAULT: "default" ':' MAYBECODE {
1935 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1937 $$ = code_append($$, $7);
1938 code_t*out = $$ = abc_pop($$);
1939 breakjumpsto($$, $1, out);
1941 code_t*c = $$,*lastblock=0;
1943 if(c->opcode == OPCODE_IFNE) {
1944 if(!c->next) syntaxerror("internal error in fallthrough handling");
1946 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1948 c->opcode = OPCODE_JUMP;
1949 c->branch = lastblock;
1951 /* fall through end of switch */
1952 c->opcode = OPCODE_NOP;
1962 /* ------------ try / catch /finally ---------------- */
1964 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1966 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1967 multiname_t name = {QNAME, &name_ns, 0, $3};
1969 NEW(abc_exception_t, e)
1970 e->exc_type = sig2mname($4);
1971 e->var_name = multiname_clone(&name);
1975 int i = find_variable_safe($3)->index;
1976 e->target = c = abc_nop(0);
1977 c = abc_setlocal(c, i);
1978 c = code_append(c, $8);
1984 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
1990 NEW(abc_exception_t, e)
1991 e->exc_type = 0; //all exceptions
1992 e->var_name = 0; //no name
1995 e->to = code_append(e->to, $4);
2001 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2002 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2003 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2004 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2008 list_append($$.l,$2);
2009 $$.finally = $2->to;$2->to=0;
2012 CATCH_FINALLY_LIST: FINALLY {
2016 list_append($$.l,$1);
2017 $$.finally = $1->to;$1->to=0;
2021 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
2022 code_t*out = abc_nop(0);
2024 code_t*start = abc_nop(0);
2025 $$ = code_append(start, $4);
2026 if(!is_break_or_jump($4)) {
2027 $$ = abc_jump($$, out);
2029 code_t*end = $$ = abc_nop($$);
2033 tmp = new_variable("__finally__", 0, 0);
2035 abc_exception_list_t*l = $6.l;
2038 abc_exception_t*e = l->abc_exception;
2040 $$ = code_append($$, e->target);
2041 $$ = abc_jump($$, out);
2043 parserassert((ptroff_t)$6.finally);
2045 e->target = $$ = abc_nop($$);
2046 $$ = abc___rethrow__($$);
2054 $$ = code_append($$, out);
2056 $$ = insert_finally($$, $6.finally, tmp);
2058 list_concat(state->method->exceptions, $6.l);
2064 /* ------------ throw ------------------------------- */
2066 THROW : "throw" EXPRESSION {
2070 THROW : "throw" %prec prec_none {
2071 if(!state->exception_name)
2072 syntaxerror("re-throw only possible within a catch block");
2073 variable_t*v = find_variable(state->exception_name);
2075 $$=abc_getlocal($$, v->index);
2079 /* ------------ with -------------------------------- */
2081 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
2083 $$ = abc_pushscope($$);
2084 $$ = code_append($$, $5);
2085 $$ = abc_popscope($$);
2088 /* ------------ packages and imports ---------------- */
2090 X_IDENTIFIER: T_IDENTIFIER
2091 | "package" {PASS12 $$="package";}
2093 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2094 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2096 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2097 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2098 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2099 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2101 IMPORT : "import" PACKAGEANDCLASS {
2103 if(!registry_findclass($2->package, $2->name)) {
2104 as3_schedule_class($2->package, $2->name);
2110 syntaxerror("Couldn't import class\n");
2111 state_has_imports();
2112 dict_put(state->imports, c->name, c);
2115 IMPORT : "import" PACKAGE '.' '*' {
2117 if(strncmp("flash.", $2, 6)) {
2118 as3_schedule_package($2);
2124 state_has_imports();
2125 list_append(state->wildcard_imports, i);
2129 /* ------------ classes and interfaces (header) -------------- */
2131 MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
2132 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2133 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2134 MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
2136 MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
2137 | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
2138 | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
2139 | KW_STATIC {PASS12 $$=FLAG_STATIC;}
2140 | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
2141 | KW_FINAL {PASS12 $$=FLAG_FINAL;}
2142 | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
2143 | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
2144 | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
2146 EXTENDS : {$$=registry_getobjectclass();}
2147 EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
2149 EXTENDS_LIST : {PASS12 $$=list_new();}
2150 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2152 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2153 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2155 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2156 EXTENDS IMPLEMENTS_LIST
2157 '{' {PASS12 startclass($1,$3,$4,$5, 0);}
2159 '}' {PASS12 endclass();$$=0;}
2161 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2163 '{' {PASS12 startclass($1,$3,0,$4,1);}
2164 MAYBE_INTERFACE_BODY
2165 '}' {PASS12 endclass();$$=0;}
2167 /* ------------ classes and interfaces (body) -------------- */
2170 MAYBE_CLASS_BODY : CLASS_BODY
2171 CLASS_BODY : CLASS_BODY_ITEM
2172 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2173 CLASS_BODY_ITEM : ';'
2174 CLASS_BODY_ITEM : SLOT_DECLARATION
2175 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2177 CLASS_BODY_ITEM : CODE_STATEMENT {
2178 code_t*c = state->cls->static_init;
2179 c = code_append(c, $1);
2180 state->cls->static_init = c;
2183 MAYBE_INTERFACE_BODY :
2184 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2185 INTERFACE_BODY : IDECLARATION
2186 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2188 IDECLARATION : "var" T_IDENTIFIER {
2189 syntaxerror("variable declarations not allowed in interfaces");
2191 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2194 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2195 syntaxerror("invalid method modifiers: interface methods always need to be public");
2197 startfunction(0,$1,$3,$4,&$6,$8);
2198 endfunction(0,$1,$3,$4,&$6,$8, 0);
2199 list_deep_free($6.list);
2202 /* ------------ classes and interfaces (body, slots ) ------- */
2204 VARCONST: "var" | "const"
2206 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
2208 memberinfo_t* info = state->cls?
2209 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
2210 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
2213 info->flags = flags;
2216 namespace_t mname_ns = {flags2access(flags), ""};
2217 multiname_t mname = {QNAME, &mname_ns, 0, $3};
2219 trait_list_t**traits;
2223 mname_ns.name = state->package;
2224 traits = &global->init->traits;
2225 code = &global->init->method->body->code;
2226 } else if(flags&FLAG_STATIC) {
2228 traits = &state->cls->abc->static_traits;
2229 code = &state->cls->static_init;
2231 // instance variable
2232 traits = &state->cls->abc->traits;
2233 code = &state->cls->init;
2239 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2241 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2243 info->slot = t->slot_id;
2245 /* initalization code (if needed) */
2247 if($5.c && !is_pushundefined($5.c)) {
2248 c = abc_getlocal_0(c);
2249 c = code_append(c, $5.c);
2250 c = converttype(c, $5.t, $4);
2251 c = abc_setslot(c, t->slot_id);
2254 *code = code_append(*code, c);
2257 t->kind= TRAIT_CONST;
2263 /* ------------ constants -------------------------------------- */
2265 MAYBESTATICCONSTANT: {$$=0;}
2266 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2268 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2269 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2270 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2271 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2272 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2273 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2274 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2275 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2276 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2278 /* ------------ classes and interfaces (body, functions) ------- */
2280 // non-vararg version
2283 memset(&$$,0,sizeof($$));
2285 MAYBE_PARAM_LIST: PARAM_LIST {
2291 MAYBE_PARAM_LIST: "..." PARAM {
2293 memset(&$$,0,sizeof($$));
2295 list_append($$.list, $2);
2297 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2301 list_append($$.list, $4);
2305 PARAM_LIST: PARAM_LIST ',' PARAM {
2308 list_append($$.list, $3);
2312 memset(&$$,0,sizeof($$));
2313 list_append($$.list, $1);
2316 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2319 $$ = malloc(sizeof(param_t));
2324 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2327 $$ = malloc(sizeof(param_t));
2329 $$->type = TYPE_ANY;
2332 GETSET : "get" {$$=$1;}
2336 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2337 MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}'
2339 PASS1 old_state();list_deep_free($6.list);
2341 if(!state->method->info) syntaxerror("internal error");
2343 code_t*c = method_header();
2344 c = wrap_function(c, 0, $11);
2346 endfunction(0,$1,$3,$4,&$6,$8,c);
2347 list_deep_free($6.list);
2351 MAYBE_IDENTIFIER: T_IDENTIFIER
2352 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2353 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2354 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2356 PASS1 old_state();list_deep_free($4.list);
2358 memberinfo_t*f = state->method->info;
2359 if(!f) syntaxerror("internal error");
2361 code_t*c = method_header();
2362 c = wrap_function(c, 0, $9);
2364 int index = state->method->var_index;
2365 endfunction(0,0,0,$2,&$4,$6,c);
2366 list_deep_free($4.list);
2368 $$.c = abc_getlocal(0, index);
2369 $$.t = TYPE_FUNCTION(f);
2373 /* ------------- package + class ids --------------- */
2375 CLASS: T_IDENTIFIER {
2378 /* try current package */
2379 $$ = find_class($1);
2380 if(!$$) syntaxerror("Could not find class %s\n", $1);
2383 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2384 PASS1 static classinfo_t c;
2385 memset(&c, 0, sizeof(c));
2390 $$ = registry_findclass($1, $3);
2391 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
2395 CLASS_SPEC: PACKAGEANDCLASS
2398 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2399 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2401 TYPE : CLASS_SPEC {$$=$1;}
2402 | '*' {$$=registry_getanytype();}
2403 | "void" {$$=registry_getanytype();}
2405 | "String" {$$=registry_getstringclass();}
2406 | "int" {$$=registry_getintclass();}
2407 | "uint" {$$=registry_getuintclass();}
2408 | "Boolean" {$$=registry_getbooleanclass();}
2409 | "Number" {$$=registry_getnumberclass();}
2412 MAYBETYPE: ':' TYPE {$$=$2;}
2415 /* ----------function calls, delete, constructor calls ------ */
2417 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2418 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2420 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2421 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2422 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2425 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2427 $$.cc = code_append($1.cc, $3.c);
2431 NEW : "new" E XX MAYBE_PARAM_VALUES {
2433 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2435 code_t*paramcode = $4.cc;
2436 if($$.c->opcode == OPCODE_GETPROPERTY) {
2437 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2438 $$.c = code_cutlast($$.c);
2439 $$.c = code_append($$.c, paramcode);
2440 $$.c = abc_constructprop2($$.c, name, $4.len);
2441 multiname_destroy(name);
2442 } else if($$.c->opcode == OPCODE_GETSLOT) {
2443 int slot = (int)(ptroff_t)$$.c->data[0];
2444 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2445 multiname_t*name = t->name;
2446 $$.c = code_cutlast($$.c);
2447 $$.c = code_append($$.c, paramcode);
2448 $$.c = abc_constructprop2($$.c, name, $4.len);
2450 $$.c = code_append($$.c, paramcode);
2451 $$.c = abc_construct($$.c, $4.len);
2455 if(TYPE_IS_CLASS($2.t) && $2.t->cls) {
2458 $$.c = abc_coerce_a($$.c);
2463 /* TODO: use abc_call (for calling local variables),
2464 abc_callstatic (for calling own methods)
2467 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2470 if($$.c->opcode == OPCODE_COERCE_A) {
2471 $$.c = code_cutlast($$.c);
2473 code_t*paramcode = $3.cc;
2476 if($$.c->opcode == OPCODE_GETPROPERTY) {
2477 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2478 $$.c = code_cutlast($$.c);
2479 $$.c = code_append($$.c, paramcode);
2480 $$.c = abc_callproperty2($$.c, name, $3.len);
2481 multiname_destroy(name);
2482 } else if($$.c->opcode == OPCODE_GETSLOT) {
2483 int slot = (int)(ptroff_t)$$.c->data[0];
2484 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2485 if(t->kind!=TRAIT_METHOD) {
2486 //ok: flash allows to assign closures to members.
2488 multiname_t*name = t->name;
2489 $$.c = code_cutlast($$.c);
2490 $$.c = code_append($$.c, paramcode);
2491 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2492 $$.c = abc_callproperty2($$.c, name, $3.len);
2493 } else if($$.c->opcode == OPCODE_GETSUPER) {
2494 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2495 $$.c = code_cutlast($$.c);
2496 $$.c = code_append($$.c, paramcode);
2497 $$.c = abc_callsuper2($$.c, name, $3.len);
2498 multiname_destroy(name);
2500 $$.c = abc_getglobalscope($$.c);
2501 $$.c = code_append($$.c, paramcode);
2502 $$.c = abc_call($$.c, $3.len);
2505 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2506 $$.t = $1.t->function->return_type;
2508 $$.c = abc_coerce_a($$.c);
2513 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2514 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2515 if(!state->method) syntaxerror("super() not allowed outside of a function");
2516 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2519 $$.c = abc_getlocal_0($$.c);
2521 $$.c = code_append($$.c, $3.cc);
2523 this is dependent on the control path, check this somewhere else
2524 if(state->method->has_super)
2525 syntaxerror("constructor may call super() only once");
2527 state->method->has_super = 1;
2529 $$.c = abc_constructsuper($$.c, $3.len);
2530 $$.c = abc_pushundefined($$.c);
2534 DELETE: "delete" E {
2536 if($$.c->opcode == OPCODE_COERCE_A) {
2537 $$.c = code_cutlast($$.c);
2539 multiname_t*name = 0;
2540 if($$.c->opcode == OPCODE_GETPROPERTY) {
2541 $$.c->opcode = OPCODE_DELETEPROPERTY;
2542 } else if($$.c->opcode == OPCODE_GETSLOT) {
2543 int slot = (int)(ptroff_t)$$.c->data[0];
2544 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2545 $$.c = code_cutlast($$.c);
2546 $$.c = abc_deleteproperty2($$.c, name);
2548 $$.c = abc_getlocal_0($$.c);
2549 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2550 $$.c = abc_deleteproperty2($$.c, &m);
2552 $$.t = TYPE_BOOLEAN;
2555 RETURN: "return" %prec prec_none {
2556 $$ = abc_returnvoid(0);
2558 RETURN: "return" EXPRESSION {
2560 $$ = abc_returnvalue($$);
2563 // ----------------------- expression types -------------------------------------
2565 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2566 EXPRESSION : E %prec below_minus {$$ = $1;}
2567 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2569 $$.c = cut_last_push($$.c);
2570 $$.c = code_append($$.c,$3.c);
2573 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2574 $$=cut_last_push($1.c);
2577 // ----------------------- expression evaluation -------------------------------------
2579 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2580 //V : CONSTANT {$$ = 0;}
2582 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2583 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2584 //V : NEW {$$ = $1.c;}
2586 //V : DELETE {$$ = $1.c;}
2587 E : DELETE {$$ = $1;}
2593 namespace_t ns = {ACCESS_PACKAGE, ""};
2594 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2596 $$.c = abc_getlex2($$.c, &m);
2597 $$.c = abc_pushstring($$.c, $1.pattern);
2598 $$.c = abc_construct($$.c, 1);
2600 $$.c = abc_getlex2($$.c, &m);
2601 $$.c = abc_pushstring($$.c, $1.pattern);
2602 $$.c = abc_pushstring($$.c, $1.options);
2603 $$.c = abc_construct($$.c, 2);
2608 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2609 //MULTINAME(m, registry_getintclass());
2610 //$$.c = abc_coerce2($$.c, &m); // FIXME
2613 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2616 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2619 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2622 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2625 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
2628 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2631 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2632 $$.t = TYPE_BOOLEAN;
2634 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2635 $$.t = TYPE_BOOLEAN;
2637 CONSTANT : "null" {$$.c = abc_pushnull(0);
2641 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2642 $$.t = TYPE_BOOLEAN;
2644 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2645 $$.t = TYPE_BOOLEAN;
2647 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2648 $$.t = TYPE_BOOLEAN;
2650 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2651 $$.t = TYPE_BOOLEAN;
2653 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2654 $$.t = TYPE_BOOLEAN;
2656 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2657 $$.t = TYPE_BOOLEAN;
2659 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2660 $$.t = TYPE_BOOLEAN;
2662 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2663 $$.t = TYPE_BOOLEAN;
2666 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2668 $$.c = converttype($$.c, $1.t, $$.t);
2669 $$.c = abc_dup($$.c);
2670 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2671 $$.c = cut_last_push($$.c);
2672 $$.c = code_append($$.c,$3.c);
2673 $$.c = converttype($$.c, $3.t, $$.t);
2674 code_t*label = $$.c = abc_label($$.c);
2675 jmp->branch = label;
2678 $$.t = join_types($1.t, $3.t, 'A');
2679 /*printf("%08x:\n",$1.t);
2680 code_dump($1.c, 0, 0, "", stdout);
2681 printf("%08x:\n",$3.t);
2682 code_dump($3.c, 0, 0, "", stdout);
2683 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2685 $$.c = converttype($$.c, $1.t, $$.t);
2686 $$.c = abc_dup($$.c);
2687 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2688 $$.c = cut_last_push($$.c);
2689 $$.c = code_append($$.c,$3.c);
2690 $$.c = converttype($$.c, $3.t, $$.t);
2691 code_t*label = $$.c = abc_label($$.c);
2692 jmp->branch = label;
2695 E : '!' E {$$.c=$2.c;
2696 $$.c = abc_not($$.c);
2697 $$.t = TYPE_BOOLEAN;
2700 E : '~' E {$$.c=$2.c;
2701 $$.c = abc_bitnot($$.c);
2705 E : E '&' E {$$.c = code_append($1.c,$3.c);
2706 $$.c = abc_bitand($$.c);
2710 E : E '^' E {$$.c = code_append($1.c,$3.c);
2711 $$.c = abc_bitxor($$.c);
2715 E : E '|' E {$$.c = code_append($1.c,$3.c);
2716 $$.c = abc_bitor($$.c);
2720 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2721 $$.c = abc_rshift($$.c);
2724 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2725 $$.c = abc_urshift($$.c);
2728 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2729 $$.c = abc_lshift($$.c);
2733 E : E '/' E {$$.c = code_append($1.c,$3.c);
2734 $$.c = abc_divide($$.c);
2737 E : E '%' E {$$.c = code_append($1.c,$3.c);
2738 $$.c = abc_modulo($$.c);
2741 E : E '+' E {$$.c = code_append($1.c,$3.c);
2742 if(BOTH_INT($1.t, $3.t)) {
2743 $$.c = abc_add_i($$.c);
2746 $$.c = abc_add($$.c);
2747 $$.t = join_types($1.t,$3.t,'+');
2750 E : E '-' E {$$.c = code_append($1.c,$3.c);
2751 if(BOTH_INT($1.t,$3.t)) {
2752 $$.c = abc_subtract_i($$.c);
2755 $$.c = abc_subtract($$.c);
2759 E : E '*' E {$$.c = code_append($1.c,$3.c);
2760 if(BOTH_INT($1.t,$3.t)) {
2761 $$.c = abc_multiply_i($$.c);
2764 $$.c = abc_multiply($$.c);
2769 E : E "in" E {$$.c = code_append($1.c,$3.c);
2770 $$.c = abc_in($$.c);
2771 $$.t = TYPE_BOOLEAN;
2774 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2775 if(use_astype && TYPE_IS_CLASS($3.t)) {
2776 MULTINAME(m,$3.t->cls);
2777 $$.c = abc_astype2($1.c, &m);
2780 $$.c = code_append($1.c, $3.c);
2781 $$.c = abc_astypelate($$.c);
2786 E : E "instanceof" E
2787 {$$.c = code_append($1.c, $3.c);
2788 $$.c = abc_instanceof($$.c);
2789 $$.t = TYPE_BOOLEAN;
2792 E : E "is" E {$$.c = code_append($1.c, $3.c);
2793 $$.c = abc_istypelate($$.c);
2794 $$.t = TYPE_BOOLEAN;
2797 E : "typeof" '(' E ')' {
2799 $$.c = abc_typeof($$.c);
2804 $$.c = cut_last_push($2.c);
2805 $$.c = abc_pushundefined($$.c);
2809 E : "void" { $$.c = abc_pushundefined(0);
2813 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2818 $$.c=abc_negate_i($$.c);
2821 $$.c=abc_negate($$.c);
2828 $$.c = code_append($$.c, $3.c);
2830 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2831 $$.c = abc_getproperty2($$.c, &m);
2832 $$.t = 0; // array elements have unknown type
2835 E : '[' MAYBE_EXPRESSION_LIST ']' {
2837 $$.c = code_append($$.c, $2.cc);
2838 $$.c = abc_newarray($$.c, $2.len);
2839 $$.t = registry_getarrayclass();
2842 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2843 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
2845 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2847 $$.cc = code_append($$.cc, $1.c);
2848 $$.cc = code_append($$.cc, $3.c);
2851 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2854 $$.cc = code_append($$.cc, $3.c);
2855 $$.cc = code_append($$.cc, $5.c);
2860 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2862 $$.c = code_append($$.c, $2.cc);
2863 $$.c = abc_newobject($$.c, $2.len/2);
2864 $$.t = registry_getobjectclass();
2869 if(BOTH_INT($1.t,$3.t)) {
2870 c=abc_multiply_i(c);
2874 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2875 $$.c = toreadwrite($1.c, c, 0, 0);
2880 code_t*c = abc_modulo($3.c);
2881 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2882 $$.c = toreadwrite($1.c, c, 0, 0);
2886 code_t*c = abc_lshift($3.c);
2887 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2888 $$.c = toreadwrite($1.c, c, 0, 0);
2892 code_t*c = abc_rshift($3.c);
2893 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2894 $$.c = toreadwrite($1.c, c, 0, 0);
2898 code_t*c = abc_urshift($3.c);
2899 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2900 $$.c = toreadwrite($1.c, c, 0, 0);
2904 code_t*c = abc_divide($3.c);
2905 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2906 $$.c = toreadwrite($1.c, c, 0, 0);
2910 code_t*c = abc_bitor($3.c);
2911 c=converttype(c, TYPE_INT, $1.t);
2912 $$.c = toreadwrite($1.c, c, 0, 0);
2918 if(TYPE_IS_INT($1.t)) {
2922 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2925 $$.c = toreadwrite($1.c, c, 0, 0);
2928 E : E "-=" E { code_t*c = $3.c;
2929 if(TYPE_IS_INT($1.t)) {
2930 c=abc_subtract_i(c);
2933 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2936 $$.c = toreadwrite($1.c, c, 0, 0);
2939 E : E '=' E { code_t*c = 0;
2940 c = code_append(c, $3.c);
2941 c = converttype(c, $3.t, $1.t);
2942 $$.c = toreadwrite($1.c, c, 1, 0);
2946 E : E '?' E ':' E %prec below_assignment {
2947 $$.t = join_types($3.t,$5.t,'?');
2949 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2950 $$.c = code_append($$.c, $3.c);
2951 $$.c = converttype($$.c, $3.t, $$.t);
2952 code_t*j2 = $$.c = abc_jump($$.c, 0);
2953 $$.c = j1->branch = abc_label($$.c);
2954 $$.c = code_append($$.c, $5.c);
2955 $$.c = converttype($$.c, $3.t, $$.t);
2956 $$.c = j2->branch = abc_label($$.c);
2959 E : E "++" { code_t*c = 0;
2960 classinfo_t*type = $1.t;
2961 if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
2962 int nr = getlocalnr($1.c);
2963 code_free($1.c);$1.c=0;
2964 if(TYPE_IS_INT($1.t)) {
2965 $$.c = abc_getlocal(0, nr);
2966 $$.c = abc_inclocal_i($$.c, nr);
2967 } else if(TYPE_IS_NUMBER($1.t)) {
2968 $$.c = abc_getlocal(0, nr);
2969 $$.c = abc_inclocal($$.c, nr);
2970 } else syntaxerror("internal error");
2972 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2973 c=abc_increment_i(c);
2979 c=converttype(c, type, $1.t);
2980 $$.c = toreadwrite($1.c, c, 0, 1);
2985 // TODO: use inclocal, like with ++
2986 E : E "--" { code_t*c = 0;
2987 classinfo_t*type = $1.t;
2988 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2989 c=abc_decrement_i(c);
2995 c=converttype(c, type, $1.t);
2996 $$.c = toreadwrite($1.c, c, 0, 1);
3000 E : "++" %prec plusplus_prefix E { code_t*c = 0;
3001 classinfo_t*type = $2.t;
3002 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3003 c=abc_increment_i(c);
3009 c=converttype(c, type, $2.t);
3010 $$.c = toreadwrite($2.c, c, 0, 0);
3014 E : "--" %prec minusminus_prefix E { code_t*c = 0;
3015 classinfo_t*type = $2.t;
3016 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3017 c=abc_decrement_i(c);
3023 c=converttype(c, type, $2.t);
3024 $$.c = toreadwrite($2.c, c, 0, 0);
3028 E : "super" '.' T_IDENTIFIER
3029 { if(!state->cls->info)
3030 syntaxerror("super keyword not allowed outside a class");
3031 classinfo_t*t = state->cls->info->superclass;
3032 if(!t) t = TYPE_OBJECT;
3034 memberinfo_t*f = registry_findmember(t, $3, 1);
3035 namespace_t ns = flags2namespace(f->flags, "");
3036 MEMBER_MULTINAME(m, f, $3);
3038 $$.c = abc_getlocal_0($$.c);
3039 $$.c = abc_getsuper2($$.c, &m);
3040 $$.t = memberinfo_gettype(f);
3043 E : E '.' T_IDENTIFIER
3045 classinfo_t*t = $1.t;
3047 if(TYPE_IS_CLASS(t) && t->cls) {
3052 memberinfo_t*f = registry_findmember(t, $3, 1);
3054 if(f && !is_static != !(f->flags&FLAG_STATIC))
3056 if(f && f->slot && !noslot) {
3057 $$.c = abc_getslot($$.c, f->slot);
3059 MEMBER_MULTINAME(m, f, $3);
3060 $$.c = abc_getproperty2($$.c, &m);
3062 /* determine type */
3063 $$.t = memberinfo_gettype(f);
3065 $$.c = abc_coerce_a($$.c);
3067 /* when resolving a property on an unknown type, we do know the
3068 name of the property (and don't seem to need the package), but
3069 we need to make avm2 try out all access modes */
3070 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3071 $$.c = abc_getproperty2($$.c, &m);
3072 $$.c = abc_coerce_a($$.c);
3073 $$.t = registry_getanytype();
3077 VAR_READ : T_IDENTIFIER {
3084 /* look at variables */
3085 if((v = find_variable($1))) {
3086 // $1 is a local variable
3087 $$.c = abc_getlocal($$.c, v->index);
3092 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3094 /* look at current class' members */
3095 if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
3096 (f->flags&FLAG_STATIC) >= i_am_static) {
3097 // $1 is a function in this class
3098 int var_is_static = (f->flags&FLAG_STATIC);
3100 if(f->kind == MEMBER_METHOD) {
3101 $$.t = TYPE_FUNCTION(f);
3105 if(var_is_static && !i_am_static) {
3106 /* access to a static member from a non-static location.
3107 do this via findpropstrict:
3108 there doesn't seem to be any non-lookup way to access
3109 static properties of a class */
3110 state->method->late_binding = 1;
3112 namespace_t ns = {flags2access(f->flags), ""};
3113 multiname_t m = {QNAME, &ns, 0, $1};
3114 $$.c = abc_findpropstrict2($$.c, &m);
3115 $$.c = abc_getproperty2($$.c, &m);
3117 } else if(f->slot>0) {
3118 $$.c = abc_getlocal_0($$.c);
3119 $$.c = abc_getslot($$.c, f->slot);
3122 namespace_t ns = {flags2access(f->flags), ""};
3123 multiname_t m = {QNAME, &ns, 0, $1};
3124 $$.c = abc_getlocal_0($$.c);
3125 $$.c = abc_getproperty2($$.c, &m);
3130 /* look at actual classes, in the current package and imported */
3131 if((a = find_class($1))) {
3132 if(a->flags & FLAG_METHOD) {
3134 $$.c = abc_findpropstrict2($$.c, &m);
3135 $$.c = abc_getproperty2($$.c, &m);
3136 if(a->function->kind == MEMBER_METHOD) {
3137 $$.t = TYPE_FUNCTION(a->function);
3139 $$.t = a->function->type;
3143 $$.c = abc_getglobalscope($$.c);
3144 $$.c = abc_getslot($$.c, a->slot);
3147 $$.c = abc_getlex2($$.c, &m);
3149 $$.t = TYPE_CLASS(a);
3154 /* unknown object, let the avm2 resolve it */
3156 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3157 state->method->late_binding = 1;
3159 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3162 $$.c = abc_findpropstrict2($$.c, &m);
3163 $$.c = abc_getproperty2($$.c, &m);
3168 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
3169 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
3170 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
3172 // ----------------- namespaces -------------------------------------------------
3174 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
3175 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
3176 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
3178 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}