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"
42 enum yytokentype token;
45 classinfo_t*classinfo;
46 classinfo_list_t*classinfo_list;
49 unsigned int number_uint;
53 //typedcode_list_t*value_list;
54 codeandnumber_t value_list;
60 for_start_t for_start;
61 abc_exception_t *exception;
64 abc_exception_list_t *l;
70 %token<id> T_IDENTIFIER
72 %token<regexp> T_REGEXP
74 %token<number_int> T_INT
75 %token<number_uint> T_UINT
76 %token<number_uint> T_BYTE
77 %token<number_uint> T_SHORT
78 %token<number_float> T_FLOAT
80 %token<id> T_FOR "for"
81 %token<id> T_WHILE "while"
83 %token<id> T_SWITCH "switch"
85 %token<token> KW_IMPLEMENTS "implements"
86 %token<token> KW_NAMESPACE "namespace"
87 %token<token> KW_PACKAGE "package"
88 %token<token> KW_PROTECTED "protected"
89 %token<token> KW_PUBLIC "public"
90 %token<token> KW_PRIVATE "private"
91 %token<token> KW_USE "use"
92 %token<token> KW_INTERNAL "internal"
93 %token<token> KW_NEW "new"
94 %token<token> KW_NATIVE "native"
95 %token<token> KW_FUNCTION "function"
96 %token<token> KW_FINALLY "finally"
97 %token<token> KW_UNDEFINED "undefined"
98 %token<token> KW_CONTINUE "continue"
99 %token<token> KW_CLASS "class"
100 %token<token> KW_CONST "const"
101 %token<token> KW_CATCH "catch"
102 %token<token> KW_CASE "case"
103 %token<token> KW_SET "set"
104 %token<token> KW_VOID "void"
105 %token<token> KW_THROW "throw"
106 %token<token> KW_STATIC "static"
107 %token<token> KW_WITH "with"
108 %token<token> KW_INSTANCEOF "instanceof"
109 %token<token> KW_IMPORT "import"
110 %token<token> KW_RETURN "return"
111 %token<token> KW_TYPEOF "typeof"
112 %token<token> KW_INTERFACE "interface"
113 %token<token> KW_NULL "null"
114 %token<token> KW_VAR "var"
115 %token<token> KW_DYNAMIC "dynamic"
116 %token<token> KW_OVERRIDE "override"
117 %token<token> KW_FINAL "final"
118 %token<token> KW_EACH "each"
119 %token<token> KW_GET "get"
120 %token<token> KW_TRY "try"
121 %token<token> KW_SUPER "super"
122 %token<token> KW_EXTENDS "extends"
123 %token<token> KW_FALSE "false"
124 %token<token> KW_TRUE "true"
125 %token<token> KW_BOOLEAN "Boolean"
126 %token<token> KW_UINT "uint"
127 %token<token> KW_INT "int"
128 %token<token> KW_NUMBER "Number"
129 %token<token> KW_STRING "String"
130 %token<token> KW_DEFAULT "default"
131 %token<token> KW_DELETE "delete"
132 %token<token> KW_IF "if"
133 %token<token> KW_ELSE "else"
134 %token<token> KW_BREAK "break"
135 %token<token> KW_IS "is"
136 %token<token> KW_IN "in"
137 %token<token> KW_AS "as"
139 %token<token> T_EQEQ "=="
140 %token<token> T_EQEQEQ "==="
141 %token<token> T_NE "!="
142 %token<token> T_NEE "!=="
143 %token<token> T_LE "<="
144 %token<token> T_GE ">="
145 %token<token> T_ORBY "|="
146 %token<token> T_DIVBY "/="
147 %token<token> T_MODBY "%="
148 %token<token> T_MULBY "*="
149 %token<token> T_PLUSBY "+="
150 %token<token> T_MINUSBY "-="
151 %token<token> T_SHRBY ">>="
152 %token<token> T_SHLBY "<<="
153 %token<token> T_USHRBY ">>>="
154 %token<token> T_OROR "||"
155 %token<token> T_ANDAND "&&"
156 %token<token> T_COLONCOLON "::"
157 %token<token> T_MINUSMINUS "--"
158 %token<token> T_PLUSPLUS "++"
159 %token<token> T_DOTDOT ".."
160 %token<token> T_DOTDOTDOT "..."
161 %token<token> T_SHL "<<"
162 %token<token> T_USHR ">>>"
163 %token<token> T_SHR ">>"
165 %type <for_start> FOR_START
166 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
167 %type <token> VARCONST
169 %type <code> CODEPIECE CODE_STATEMENT
170 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
171 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
172 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
173 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
174 %type <exception> CATCH FINALLY
175 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
176 %type <code> CLASS_DECLARATION
177 %type <code> NAMESPACE_DECLARATION
178 %type <code> INTERFACE_DECLARATION
179 %type <code> VOIDEXPRESSION
180 %type <value> EXPRESSION NONCOMMAEXPRESSION
181 %type <value> MAYBEEXPRESSION
182 %type <value> E DELETE
183 %type <value> CONSTANT
184 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
185 %type <value> INNERFUNCTION
186 %type <token> USE_NAMESPACE
187 %type <code> FOR_INIT
189 %type <classinfo> MAYBETYPE
192 %type <params> PARAM_LIST
193 %type <params> MAYBE_PARAM_LIST
194 %type <flags> MAYBE_MODIFIERS
195 %type <flags> MODIFIER_LIST
196 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
197 %type <classinfo_list> IMPLEMENTS_LIST
198 %type <classinfo> EXTENDS
199 %type <classinfo_list> EXTENDS_LIST
200 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
201 %type <classinfo_list> QNAME_LIST
202 %type <classinfo> TYPE
203 //%type <token> VARIABLE
204 %type <value> VAR_READ
206 //%type <token> T_IDENTIFIER
207 %type <token> MODIFIER
208 %type <value> FUNCTIONCALL
209 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
211 // precedence: from low to high
215 %left below_semicolon
218 %nonassoc below_assignment // for ?:, contrary to spec
219 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
226 %nonassoc "==" "!=" "===" "!=="
227 %nonassoc "is" "as" "in"
228 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
229 %left "<<" ">>" ">>>"
233 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
235 %nonassoc below_curly
236 %left '[' ']' '{' "new" '.' ".." "::"
237 %nonassoc T_IDENTIFIER
238 %left above_identifier
243 // needed for "return" precedence:
244 %nonassoc T_STRING T_REGEXP
245 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
246 %nonassoc "false" "true" "null" "undefined" "super" "function"
247 %nonassoc above_function
253 static int yyerror(char*s)
255 syntaxerror("%s", s);
256 return 0; //make gcc happy
259 static char* concat2(const char* t1, const char* t2)
263 char*text = malloc(l1+l2+1);
264 memcpy(text , t1, l1);
265 memcpy(text+l1, t2, l2);
269 static char* concat3(const char* t1, const char* t2, const char* t3)
274 char*text = malloc(l1+l2+l3+1);
275 memcpy(text , t1, l1);
276 memcpy(text+l1, t2, l2);
277 memcpy(text+l1+l2, t3, l3);
282 typedef struct _import {
286 DECLARE_LIST(import);
288 typedef struct _classstate {
294 char has_constructor;
297 typedef struct _methodstate {
304 abc_exception_list_t*exceptions;
307 typedef struct _state {
312 import_list_t*wildcard_imports;
314 char has_own_imports;
317 methodstate_t*method;
324 typedef struct _global {
331 static global_t*global = 0;
332 static state_t* state = 0;
336 #define MULTINAME(m,x) \
339 registry_fill_multiname(&m, &m##_ns, x);
341 #define MEMBER_MULTINAME(m,f,n) \
345 m##_ns = flags2namespace(f->flags, ""); \
348 m.namespace_set = 0; \
351 m.type = MULTINAME; \
353 m.namespace_set = &nopackage_namespace_set; \
357 /* warning: list length of namespace set is undefined */
358 #define MULTINAME_LATE(m, access, package) \
359 namespace_t m##_ns = {access, package}; \
360 namespace_set_t m##_nsset; \
361 namespace_list_t m##_l;m##_l.next = 0; \
362 m##_nsset.namespaces = &m##_l; \
363 m##_nsset = m##_nsset; \
364 m##_l.namespace = &m##_ns; \
365 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
367 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
368 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
369 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
370 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
371 static namespace_list_t nl4 = {&ns4,0};
372 static namespace_list_t nl3 = {&ns3,&nl4};
373 static namespace_list_t nl2 = {&ns2,&nl3};
374 static namespace_list_t nl1 = {&ns1,&nl2};
375 static namespace_set_t nopackage_namespace_set = {&nl1};
377 static void new_state()
380 state_t*oldstate = state;
382 memcpy(s, state, sizeof(state_t)); //shallow copy
384 s->imports = dict_new();
388 state->has_own_imports = 0;
389 state->vars = dict_new();
390 state->old = oldstate;
392 static void state_has_imports()
394 state->wildcard_imports = list_clone(state->wildcard_imports);
395 state->imports = dict_clone(state->imports);
396 state->has_own_imports = 1;
399 static void state_destroy(state_t*state)
401 if(state->has_own_imports) {
402 list_free(state->wildcard_imports);
403 dict_destroy(state->imports);state->imports=0;
405 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
406 dict_destroy(state->imports);state->imports=0;
410 for(t=0;t<state->vars->hashsize;t++) {
411 dictentry_t*e =state->vars->slots[t];
413 free(e->data);e->data=0;
417 dict_destroy(state->vars);state->vars=0;
423 static void old_state()
425 if(!state || !state->old)
426 syntaxerror("invalid nesting");
427 state_t*leaving = state;
431 if(leaving->method && leaving->method != state->method) {
432 free(leaving->method);
435 if(leaving->cls && leaving->cls != state->cls) {
440 state_destroy(leaving);
443 void initialize_parser()
445 global = rfx_calloc(sizeof(global_t));
446 global->file = abc_file_new();
447 global->file->flags &= ~ABCFILE_LAZY;
448 global->variable_count = 1;
449 global->init = abc_initscript(global->file);
450 code_t*c = global->init->method->body->code;
451 c = abc_getlocal_0(c);
452 c = abc_pushscope(c);
453 /*c = abc_findpropstrict(c, "[package]::trace");
454 c = abc_pushstring(c, "[entering global init function]");
455 c = abc_callpropvoid(c, "[package]::trace", 1);*/
456 global->init->method->body->code = c;
459 void initialize_file(char*filename)
462 state->package = filename;
463 // needed for state->method->late_binding:
464 state->method = rfx_calloc(sizeof(methodstate_t));
468 if(!state || state->level!=1) {
469 syntaxerror("unexpected end of file");
471 state_destroy(state);state=0;
474 void* finish_parser()
476 code_t*c = global->init->method->body->code;
477 /*c = abc_findpropstrict(c, "[package]::trace");
478 c = abc_pushstring(c, "[leaving global init function]");
479 c = abc_callpropvoid(c, "[package]::trace", 1);*/
480 c = abc_returnvoid(c);
481 global->init->method->body->code = c;
486 static void xx_scopetest()
488 /* findpropstrict doesn't just return a scope object- it
489 also makes it "active" somehow. Push local_0 on the
490 scope stack and read it back with findpropstrict, it'll
491 contain properties like "trace". Trying to find the same
492 property on a "vanilla" local_0 yields only a "undefined" */
493 //c = abc_findpropstrict(c, "[package]::trace");
495 /*c = abc_getlocal_0(c);
496 c = abc_findpropstrict(c, "[package]::trace");
498 c = abc_setlocal_1(c);
500 c = abc_pushbyte(c, 0);
501 c = abc_setlocal_2(c);
503 code_t*xx = c = abc_label(c);
504 c = abc_findpropstrict(c, "[package]::trace");
505 c = abc_pushstring(c, "prop:");
506 c = abc_hasnext2(c, 1, 2);
508 c = abc_setlocal_3(c);
509 c = abc_callpropvoid(c, "[package]::trace", 2);
510 c = abc_getlocal_3(c);
512 c = abc_iftrue(c,xx);*/
516 typedef struct _variable {
522 static variable_t* find_variable(char*name)
528 v = dict_lookup(s->vars, name);
536 static variable_t* find_variable_safe(char*name)
538 variable_t* v = find_variable(name);
540 syntaxerror("undefined variable: %s", name);
543 static char variable_exists(char*name)
545 return dict_lookup(state->vars, name)!=0;
547 code_t*defaultvalue(code_t*c, classinfo_t*type);
548 static int new_variable(char*name, classinfo_t*type, char init)
551 v->index = global->variable_count;
555 dict_put(state->vars, name, v);
557 return global->variable_count++;
559 #define TEMPVARNAME "__as3_temp__"
560 static int gettempvar()
562 variable_t*v = find_variable(TEMPVARNAME);
565 return new_variable(TEMPVARNAME, 0, 0);
568 code_t* var_block(code_t*body)
574 for(t=0;t<state->vars->hashsize;t++) {
575 dictentry_t*e = state->vars->slots[t];
577 variable_t*v = (variable_t*)e->data;
578 if(v->type && v->init) {
579 c = defaultvalue(c, v->type);
580 c = abc_setlocal(c, v->index);
581 k = abc_kill(k, v->index);
591 if(x->opcode== OPCODE___BREAK__ ||
592 x->opcode== OPCODE___CONTINUE__) {
593 /* link kill code before break/continue */
594 code_t*e = code_dup(k);
595 code_t*s = code_start(e);
607 c = code_append(c, body);
608 c = code_append(c, k);
612 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
614 c = code_append(c, header);
615 c = code_append(c, var_block(body));
616 /* append return if necessary */
617 if(!c || (c->opcode != OPCODE_RETURNVOID &&
618 c->opcode != OPCODE_RETURNVALUE)) {
619 c = abc_returnvoid(c);
625 static void startpackage(char*name)
628 /*printf("entering package \"%s\"\n", name);*/
629 state->package = strdup(name);
630 global->variable_count = 1;
632 static void endpackage()
634 /*printf("leaving package \"%s\"\n", state->package);*/
636 //used e.g. in classinfo_register:
637 //free(state->package);state->package=0;
642 void parserassert(int b)
644 if(!b) syntaxerror("internal error: assertion failed");
648 char*as3_globalclass=0;
649 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
652 syntaxerror("inner classes now allowed");
655 global->variable_count = 1;
656 state->cls = rfx_calloc(sizeof(classstate_t));
657 state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
660 classinfo_list_t*mlist=0;
662 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
663 syntaxerror("invalid modifier(s)");
665 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
666 syntaxerror("public and internal not supported at the same time.");
668 /* create the class name, together with the proper attributes */
672 if(!(flags&FLAG_PUBLIC) && !state->package) {
673 access = ACCESS_PRIVATE; package = current_filename;
674 } else if(!(flags&FLAG_PUBLIC) && state->package) {
675 access = ACCESS_PACKAGEINTERNAL; package = state->package;
676 } else if(state->package) {
677 access = ACCESS_PACKAGE; package = state->package;
679 syntaxerror("public classes only allowed inside a package");
683 if(registry_findclass(package, classname)) {
684 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
686 /* build info struct */
687 int num_interfaces = (list_length(implements));
688 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
692 state->cls->info = registry_findclass(package, classname);
693 parserassert((int)state->cls->info);
695 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
696 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
698 classinfo_list_t*l = implements;
699 for(l=implements;l;l=l->next) {
700 state->cls->info->interfaces[pos++] = l->classinfo;
703 /* generate the abc code for this class */
704 MULTINAME(classname2,state->cls->info);
705 multiname_t*extends2 = sig2mname(extends);
707 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
708 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
709 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
711 state->cls->info->flags |= CLASS_INTERFACE;
712 abc_class_interface(state->cls->abc);
715 abc_class_protectedNS(state->cls->abc, classname);
717 for(mlist=implements;mlist;mlist=mlist->next) {
718 MULTINAME(m, mlist->classinfo);
719 abc_class_add_interface(state->cls->abc, &m);
722 /* write the construction code for this class to the global init
724 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
726 abc_method_body_t*m = global->init->method->body;
727 __ getglobalscope(m);
728 classinfo_t*s = extends;
733 //TODO: take a look at the current scope stack, maybe
734 // we can re-use something
739 multiname_t*s2 = sig2mname(s);
741 multiname_destroy(s2);
743 __ pushscope(m); count++;
744 m->code = m->code->prev->prev; // invert
746 /* continue appending after last op end */
747 while(m->code && m->code->next) m->code = m->code->next;
749 /* TODO: if this is one of *our* classes, we can also
750 do a getglobalscope/getslot <nr> (which references
751 the init function's slots) */
753 __ getlex2(m, extends2);
755 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
756 stack is not the superclass */
757 __ pushscope(m);count++;
760 /* notice: we get a verify error #1107 if the top element on the scope
761 stack is not the global object */
763 __ pushscope(m);count++;
765 __ newclass(m,state->cls->abc);
769 __ setslot(m, slotindex);
770 multiname_destroy(extends2);
772 /* flash.display.MovieClip handling */
774 if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
775 if(state->package && state->package[0]) {
776 as3_globalclass = concat3(state->package, ".", classname);
778 as3_globalclass = strdup(classname);
784 static void endclass()
787 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
789 c = abc_getlocal_0(c);
790 c = abc_constructsuper(c, 0);
791 state->cls->init = code_append(state->cls->init, c);
793 if(!state->method->late_binding) {
794 // class initialization code uses late binding
796 c = abc_getlocal_0(c);
797 c = abc_pushscope(c);
798 state->cls->static_init = code_append(c, state->cls->static_init);
801 if(state->cls->init) {
802 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
803 m->body->code = wrap_function(0, state->cls->init, m->body->code);
805 if(state->cls->static_init) {
806 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
807 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
814 void check_code_for_break(code_t*c)
817 if(c->opcode == OPCODE___BREAK__) {
818 char*name = string_cstr(c->data[0]);
819 syntaxerror("Unresolved \"break %s\"", name);
821 if(c->opcode == OPCODE___CONTINUE__) {
822 char*name = string_cstr(c->data[0]);
823 syntaxerror("Unresolved \"continue %s\"", name);
830 static void check_constant_against_type(classinfo_t*t, constant_t*c)
832 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
833 if(TYPE_IS_NUMBER(t)) {
834 xassert(c->type == CONSTANT_FLOAT
835 || c->type == CONSTANT_INT
836 || c->type == CONSTANT_UINT);
837 } else if(TYPE_IS_UINT(t)) {
838 xassert(c->type == CONSTANT_UINT ||
839 (c->type == CONSTANT_INT && c->i>0));
840 } else if(TYPE_IS_INT(t)) {
841 xassert(c->type == CONSTANT_INT);
842 } else if(TYPE_IS_BOOLEAN(t)) {
843 xassert(c->type == CONSTANT_TRUE
844 || c->type == CONSTANT_FALSE);
849 static int flags2access(int flags)
852 if(flags&FLAG_PUBLIC) {
853 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
854 syntaxerror("invalid combination of access levels");
855 access = ACCESS_PACKAGE;
856 } else if(flags&FLAG_PRIVATE) {
857 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
858 syntaxerror("invalid combination of access levels");
859 access = ACCESS_PRIVATE;
860 } else if(flags&FLAG_PROTECTED) {
861 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
862 syntaxerror("invalid combination of access levels");
863 access = ACCESS_PROTECTED;
865 access = ACCESS_PACKAGEINTERNAL;
871 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
873 memberinfo_t*minfo = 0;
876 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
877 minfo->return_type = return_type;
878 } else if(getset != KW_GET && getset != KW_SET) {
880 if((minfo = registry_findmember(state->cls->info, name, 0))) {
881 if(minfo->parent == state->cls->info) {
882 syntaxerror("class already contains a member/method called '%s'", name);
883 } else if(!minfo->parent) {
884 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
886 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
887 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
890 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
891 minfo->return_type = return_type;
892 // getslot on a member slot only returns "undefined", so no need
893 // to actually store these
894 //state->minfo->slot = state->method->abc->method->trait->slot_id;
896 //class getter/setter
897 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
901 else if(params->list)
902 type = params->list->param->type;
903 // not sure wether to look into superclasses here, too
904 if((minfo=registry_findmember(state->cls->info, name, 0))) {
905 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
906 syntaxerror("class already contains a member or method called '%s'", name);
908 syntaxerror("getter/setter for '%s' already defined", name);
909 /* make a setter or getter into a getset */
914 if(type && minfo->type != type)
915 syntaxerror("different type in getter and setter");
917 minfo = memberinfo_register(state->cls->info, name, gs);
920 /* can't assign a slot as getter and setter might have different slots */
921 //minfo->slot = slot;
923 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
924 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
925 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
926 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
927 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
928 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
932 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
933 params_t*params, classinfo_t*return_type)
935 if(state->method && state->method->info) {
936 syntaxerror("not able to start another method scope");
939 state->method = rfx_calloc(sizeof(methodstate_t));
940 state->method->has_super = 0;
943 state->method->is_constructor = !strcmp(state->cls->info->name,name);
944 state->cls->has_constructor |= state->method->is_constructor;
946 state->method->is_global = 1;
947 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
949 if(state->method->is_constructor)
950 name = "__as3_constructor__";
954 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
958 /* retrieve the member info that we stored in the first pass.
959 TODO: better getter/setter support? */
960 if(!state->cls) state->method->info = registry_findclass(state->package, name)->function;
961 else state->method->info = registry_findmember(state->cls->info, name, 0);
962 state->method->info->return_type = return_type;
964 global->variable_count = 0;
965 /* state->vars is initialized by state_new */
966 if(!state->method->is_global)
967 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
969 new_variable("globalscope", 0, 0);
971 for(p=params->list;p;p=p->next) {
972 new_variable(p->param->name, p->param->type, 0);
977 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
978 params_t*params, classinfo_t*return_type, code_t*body)
987 multiname_t*type2 = sig2mname(return_type);
989 if(state->method->is_constructor) {
990 f = abc_class_getconstructor(state->cls->abc, type2);
991 } else if(!state->method->is_global) {
992 namespace_t mname_ns = flags2namespace(flags, "");
993 multiname_t mname = {QNAME, &mname_ns, 0, name};
995 if(flags&FLAG_STATIC)
996 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
998 f = abc_class_method(state->cls->abc, type2, &mname);
999 slot = f->trait->slot_id;
1001 namespace_t mname_ns = flags2namespace(flags, state->package);
1002 multiname_t mname = {QNAME, &mname_ns, 0, name};
1004 f = abc_method_new(global->file, type2, 1);
1005 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1006 //abc_code_t*c = global->init->method->body->code;
1008 //flash doesn't seem to allow us to access function slots
1009 //state->method->info->slot = slot;
1011 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1012 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1013 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1014 if(params->varargs) f->flags |= METHOD_NEED_REST;
1018 for(p=params->list;p;p=p->next) {
1019 if(params->varargs && !p->next) {
1020 break; //varargs: omit last parameter in function signature
1022 multiname_t*m = sig2mname(p->param->type);
1023 list_append(f->parameters, m);
1024 if(p->param->value) {
1025 check_constant_against_type(p->param->type, p->param->value);
1026 opt=1;list_append(f->optional_parameters, p->param->value);
1028 syntaxerror("non-optional parameter not allowed after optional parameters");
1031 check_code_for_break(body);
1034 f->body->code = body;
1035 f->body->exceptions = state->method->exceptions;
1036 } else { //interface
1038 syntaxerror("interface methods can't have a method body");
1046 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1051 void breakjumpsto(code_t*c, char*name, code_t*jump)
1054 if(c->opcode == OPCODE___BREAK__) {
1055 string_t*name2 = c->data[0];
1056 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1057 c->opcode = OPCODE_JUMP;
1064 void continuejumpsto(code_t*c, char*name, code_t*jump)
1067 if(c->opcode == OPCODE___CONTINUE__) {
1068 string_t*name2 = c->data[0];
1069 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1070 c->opcode = OPCODE_JUMP;
1078 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1079 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1080 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1082 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1084 if(!type1 || !type2)
1085 return registry_getanytype();
1086 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1087 return registry_getanytype();
1090 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1099 return registry_getanytype();
1101 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1106 return abc_coerce_a(c);
1110 // cast an "any" type to a specific type. subject to
1111 // runtime exceptions
1112 return abc_coerce2(c, &m);
1115 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1116 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1117 // allow conversion between number types
1118 return abc_coerce2(c, &m);
1120 //printf("%s.%s\n", from.package, from.name);
1121 //printf("%s.%s\n", to.package, to.name);
1123 classinfo_t*supertype = from;
1125 if(supertype == to) {
1126 // target type is one of from's superclasses
1127 return abc_coerce2(c, &m);
1130 while(supertype->interfaces[t]) {
1131 if(supertype->interfaces[t]==to) {
1132 // target type is one of from's interfaces
1133 return abc_coerce2(c, &m);
1137 supertype = supertype->superclass;
1139 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1141 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1143 syntaxerror("can't convert type %s to %s", from->name, to->name);
1144 return 0; // make gcc happy
1147 code_t*defaultvalue(code_t*c, classinfo_t*type)
1149 if(TYPE_IS_INT(type)) {
1150 c = abc_pushbyte(c, 0);
1151 } else if(TYPE_IS_UINT(type)) {
1152 c = abc_pushuint(c, 0);
1153 } else if(TYPE_IS_FLOAT(type)) {
1155 } else if(TYPE_IS_BOOLEAN(type)) {
1156 c = abc_pushfalse(c);
1158 //c = abc_pushundefined(c);
1160 c = abc_pushnull(c);
1162 c = abc_coerce2(c, &m);
1167 char is_pushundefined(code_t*c)
1169 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1172 static classinfo_t* find_class(char*name)
1176 c = registry_findclass(state->package, name);
1179 /* try explicit imports */
1180 dictentry_t* e = dict_get_slot(state->imports, name);
1183 if(!strcmp(e->key, name)) {
1184 c = (classinfo_t*)e->data;
1190 /* try package.* imports */
1191 import_list_t*l = state->wildcard_imports;
1193 //printf("does package %s contain a class %s?\n", l->import->package, name);
1194 c = registry_findclass(l->import->package, name);
1199 /* try global package */
1200 c = registry_findclass("", name);
1203 /* try local "filename" package */
1204 c = registry_findclass(current_filename_short, name);
1210 static char is_getlocal(code_t*c)
1212 if(!c || c->prev || c->next)
1214 return(c->opcode == OPCODE_GETLOCAL
1215 || c->opcode == OPCODE_GETLOCAL_0
1216 || c->opcode == OPCODE_GETLOCAL_1
1217 || c->opcode == OPCODE_GETLOCAL_2
1218 || c->opcode == OPCODE_GETLOCAL_3);
1220 static int getlocalnr(code_t*c)
1222 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1223 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1224 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1225 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1226 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1227 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1231 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1235 [prefix code] [read instruction]
1239 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1242 if(in && in->opcode == OPCODE_COERCE_A) {
1243 in = code_cutlast(in);
1246 syntaxerror("internal error");
1248 /* chop off read instruction */
1252 prefix = r->prev;r->prev = 0;
1258 char use_temp_var = readbefore;
1260 /* generate the write instruction, and maybe append a dup to the prefix code */
1261 code_t* write = abc_nop(0);
1262 if(r->opcode == OPCODE_GETPROPERTY) {
1263 write->opcode = OPCODE_SETPROPERTY;
1264 multiname_t*m = (multiname_t*)r->data[0];
1265 write->data[0] = multiname_clone(m);
1266 if(m->type == QNAME || m->type == MULTINAME) {
1268 prefix = abc_dup(prefix); // we need the object, too
1271 } else if(m->type == MULTINAMEL) {
1273 /* dupping two values on the stack requires 5 operations and one register-
1274 couldn't adobe just have given us a dup2? */
1275 int temp = gettempvar();
1276 prefix = abc_setlocal(prefix, temp);
1277 prefix = abc_dup(prefix);
1278 prefix = abc_getlocal(prefix, temp);
1279 prefix = abc_swap(prefix);
1280 prefix = abc_getlocal(prefix, temp);
1282 prefix = abc_kill(prefix, temp);
1286 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1288 } else if(r->opcode == OPCODE_GETSLOT) {
1289 write->opcode = OPCODE_SETSLOT;
1290 write->data[0] = r->data[0];
1292 prefix = abc_dup(prefix); // we need the object, too
1295 } else if(r->opcode == OPCODE_GETLOCAL) {
1296 write->opcode = OPCODE_SETLOCAL;
1297 write->data[0] = r->data[0];
1298 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1299 write->opcode = OPCODE_SETLOCAL_0;
1300 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1301 write->opcode = OPCODE_SETLOCAL_1;
1302 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1303 write->opcode = OPCODE_SETLOCAL_2;
1304 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1305 write->opcode = OPCODE_SETLOCAL_3;
1308 syntaxerror("illegal lvalue: can't assign a value to this expression");
1315 /* with getproperty/getslot, we have to be extra careful not
1316 to execute the read code twice, as it might have side-effects
1317 (e.g. if the property is in fact a setter/getter combination)
1319 So read the value, modify it, and write it again,
1320 using prefix only once and making sure (by using a temporary
1321 register) that the return value is what we just wrote */
1322 temp = gettempvar();
1323 c = code_append(c, prefix);
1324 c = code_append(c, r);
1327 c = abc_setlocal(c, temp);
1329 c = code_append(c, middlepart);
1332 c = abc_setlocal(c, temp);
1334 c = code_append(c, write);
1335 c = abc_getlocal(c, temp);
1336 c = abc_kill(c, temp);
1338 /* if we're allowed to execute the read code twice *and*
1339 the middlepart doesn't modify the code, things are easier.
1341 code_t* r2 = code_dup(r);
1342 //c = code_append(c, prefix);
1343 parserassert(!prefix);
1344 c = code_append(c, r);
1345 c = code_append(c, middlepart);
1346 c = code_append(c, write);
1347 c = code_append(c, r2);
1350 /* even smaller version: overwrite the value without reading
1354 c = code_append(c, prefix);
1357 c = code_append(c, middlepart);
1358 c = code_append(c, write);
1359 c = code_append(c, r);
1361 temp = gettempvar();
1363 c = code_append(c, prefix);
1365 c = code_append(c, middlepart);
1367 c = abc_setlocal(c, temp);
1368 c = code_append(c, write);
1369 c = abc_getlocal(c, temp);
1370 c = abc_kill(c, temp);
1376 char is_break_or_jump(code_t*c)
1380 if(c->opcode == OPCODE_JUMP ||
1381 c->opcode == OPCODE___BREAK__ ||
1382 c->opcode == OPCODE___CONTINUE__ ||
1383 c->opcode == OPCODE_THROW ||
1384 c->opcode == OPCODE_RETURNVOID ||
1385 c->opcode == OPCODE_RETURNVALUE) {
1392 #define IS_FINALLY_TARGET(op) \
1393 ((op) == OPCODE___CONTINUE__ || \
1394 (op) == OPCODE___BREAK__ || \
1395 (op) == OPCODE_RETURNVOID || \
1396 (op) == OPCODE_RETURNVALUE || \
1397 (op) == OPCODE___RETHROW__)
1399 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1401 #define NEED_EXTRA_STACK_ARG
1402 code_t*finally_label = abc_nop(0);
1403 NEW(lookupswitch_t, l);
1409 code_t*prev = i->prev;
1410 if(IS_FINALLY_TARGET(i->opcode)) {
1413 if(i->opcode == OPCODE___RETHROW__ ||
1414 i->opcode == OPCODE_RETURNVALUE) {
1415 if(i->opcode == OPCODE___RETHROW__)
1416 i->opcode = OPCODE_THROW;
1418 p = abc_coerce_a(p);
1419 p = abc_setlocal(p, tempvar);
1421 p = abc_pushbyte(p, count++);
1422 p = abc_jump(p, finally_label);
1423 code_t*target = p = abc_label(p);
1424 #ifdef NEED_EXTRA_STACK_ARG
1428 p = abc_getlocal(p, tempvar);
1431 p->next = i;i->prev = p;
1432 list_append(l->targets, target);
1438 c = abc_pushbyte(c, -1);
1439 c = code_append(c, finally_label);
1440 c = code_append(c, finally);
1442 #ifdef NEED_EXTRA_STACK_ARG
1445 c = abc_lookupswitch(c, l);
1446 c = l->def = abc_label(c);
1447 #ifdef NEED_EXTRA_STACK_ARG
1454 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1458 code_t*prev = i->prev;
1459 if(IS_FINALLY_TARGET(i->opcode)) {
1460 if(i->opcode == OPCODE___RETHROW__)
1461 i->opcode = OPCODE_THROW;
1462 code_t*end = code_dup(finally);
1463 code_t*start = code_start(end);
1464 if(prev) prev->next = start;
1471 return code_append(c, finally);
1474 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1480 int num_insertion_points=0;
1482 if(IS_FINALLY_TARGET(i->opcode))
1483 num_insertion_points++;
1490 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1495 int simple_version_cost = (1+num_insertion_points)*code_size;
1496 int lookup_version_cost = 4*num_insertion_points + 5;
1498 if(cantdup || simple_version_cost > lookup_version_cost) {
1499 printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
1500 return insert_finally_lookup(c, finally, tempvar);
1502 printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
1503 return insert_finally_simple(c, finally, tempvar);
1507 #define PASS1 }} if(as3_pass == 1) {{
1508 #define PASS1END }} if(as3_pass == 2) {{
1509 #define PASS2 }} if(as3_pass == 2) {{
1510 #define PASS12 }} {{
1511 #define PASS12END }} if(as3_pass == 2) {{
1517 /* ------------ code blocks / statements ---------------- */
1519 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1521 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1522 PROGRAM_CODE_LIST: PROGRAM_CODE
1523 | PROGRAM_CODE_LIST PROGRAM_CODE
1525 PROGRAM_CODE: PACKAGE_DECLARATION
1526 | INTERFACE_DECLARATION
1528 | FUNCTION_DECLARATION
1533 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1534 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1535 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1537 INPACKAGE_CODE: INTERFACE_DECLARATION
1539 | FUNCTION_DECLARATION
1544 MAYBECODE: CODE {$$=$1;}
1545 MAYBECODE: {$$=code_new();}
1547 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1548 CODE: CODEPIECE {$$=$1;}
1550 // code which also may appear outside a method
1551 CODE_STATEMENT: IMPORT
1553 CODE_STATEMENT: FOR_IN
1554 CODE_STATEMENT: WHILE
1555 CODE_STATEMENT: DO_WHILE
1556 CODE_STATEMENT: SWITCH
1558 CODE_STATEMENT: WITH
1560 CODE_STATEMENT: VOIDEXPRESSION
1562 // code which may appear anywhere
1563 CODEPIECE: ';' {$$=0;}
1564 CODEPIECE: CODE_STATEMENT
1565 CODEPIECE: VARIABLE_DECLARATION
1571 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1572 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1574 CODEBLOCK : '{' CODE '}' {$$=$2;}
1575 CODEBLOCK : '{' '}' {$$=0;}
1576 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1577 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1579 /* ------------ package init code ------------------- */
1581 PACKAGE_INITCODE: CODE_STATEMENT {
1582 code_t**cc = &global->init->method->body->code;
1583 *cc = code_append(*cc, $1);
1586 /* ------------ variables --------------------------- */
1588 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1589 | {$$.c=abc_pushundefined(0);
1593 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1594 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1596 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1597 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1599 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1601 if(variable_exists($1))
1602 syntaxerror("Variable %s already defined", $1);
1604 if(!is_subtype_of($3.t, $2)) {
1605 syntaxerror("Can't convert %s to %s", $3.t->name,
1609 int index = new_variable($1, $2, 1);
1612 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1614 $$ = converttype($$, $3.t, $2);
1615 $$ = abc_setlocal($$, index);
1617 $$ = defaultvalue(0, $2);
1618 $$ = abc_setlocal($$, index);
1621 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1623 $$ = abc_coerce_a($$);
1624 $$ = abc_setlocal($$, index);
1630 /* that's the default for a local register, anyway
1632 state->method->initcode = abc_pushundefined(state->method->initcode);
1633 state->method->initcode = abc_setlocal(state->method->initcode, index);
1635 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1638 /* ------------ control flow ------------------------- */
1640 MAYBEELSE: %prec below_else {$$ = code_new();}
1641 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1642 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1644 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1647 $$ = code_append($$, $4.c);
1648 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1650 $$ = code_append($$, $6);
1652 myjmp = $$ = abc_jump($$, 0);
1654 myif->branch = $$ = abc_nop($$);
1656 $$ = code_append($$, $7);
1657 myjmp->branch = $$ = abc_nop($$);
1663 FOR_INIT : {$$=code_new();}
1664 FOR_INIT : VARIABLE_DECLARATION
1665 FOR_INIT : VOIDEXPRESSION
1667 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1668 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1669 $$=$2;new_variable($2,$3,1);
1671 FOR_IN_INIT : T_IDENTIFIER {
1675 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1676 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1678 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1679 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1681 $$ = code_append($$, $2);
1682 code_t*loopstart = $$ = abc_label($$);
1683 $$ = code_append($$, $4.c);
1684 code_t*myif = $$ = abc_iffalse($$, 0);
1685 $$ = code_append($$, $8);
1686 code_t*cont = $$ = abc_nop($$);
1687 $$ = code_append($$, $6);
1688 $$ = abc_jump($$, loopstart);
1689 code_t*out = $$ = abc_nop($$);
1690 breakjumpsto($$, $1.name, out);
1691 continuejumpsto($$, $1.name, cont);
1698 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1699 variable_t*var = find_variable($2);
1700 char*tmp1name = concat2($2, "__tmp1__");
1701 int it = new_variable(tmp1name, TYPE_INT, 0);
1702 char*tmp2name = concat2($2, "__array__");
1703 int array = new_variable(tmp1name, 0, 0);
1706 $$ = code_append($$, $4.c);
1707 $$ = abc_coerce_a($$);
1708 $$ = abc_setlocal($$, array);
1709 $$ = abc_pushbyte($$, 0);
1710 $$ = abc_setlocal($$, it);
1712 code_t*loopstart = $$ = abc_label($$);
1714 $$ = abc_hasnext2($$, array, it);
1715 code_t*myif = $$ = abc_iffalse($$, 0);
1716 $$ = abc_getlocal($$, array);
1717 $$ = abc_getlocal($$, it);
1719 $$ = abc_nextname($$);
1721 $$ = abc_nextvalue($$);
1722 $$ = converttype($$, 0, var->type);
1723 $$ = abc_setlocal($$, var->index);
1725 $$ = code_append($$, $6);
1726 $$ = abc_jump($$, loopstart);
1728 code_t*out = $$ = abc_nop($$);
1729 breakjumpsto($$, $1.name, out);
1730 continuejumpsto($$, $1.name, loopstart);
1741 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1745 code_t*myjmp = $$ = abc_jump($$, 0);
1746 code_t*loopstart = $$ = abc_label($$);
1747 $$ = code_append($$, $6);
1748 code_t*cont = $$ = abc_nop($$);
1749 myjmp->branch = cont;
1750 $$ = code_append($$, $4.c);
1751 $$ = abc_iftrue($$, loopstart);
1752 code_t*out = $$ = abc_nop($$);
1753 breakjumpsto($$, $1, out);
1754 continuejumpsto($$, $1, cont);
1760 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1762 code_t*loopstart = $$ = abc_label($$);
1763 $$ = code_append($$, $3);
1764 code_t*cont = $$ = abc_nop($$);
1765 $$ = code_append($$, $6.c);
1766 $$ = abc_iftrue($$, loopstart);
1767 code_t*out = $$ = abc_nop($$);
1768 breakjumpsto($$, $1, out);
1769 continuejumpsto($$, $1, cont);
1775 BREAK : "break" %prec prec_none {
1776 $$ = abc___break__(0, "");
1778 BREAK : "break" T_IDENTIFIER {
1779 $$ = abc___break__(0, $2);
1781 CONTINUE : "continue" %prec prec_none {
1782 $$ = abc___continue__(0, "");
1784 CONTINUE : "continue" T_IDENTIFIER {
1785 $$ = abc___continue__(0, $2);
1788 MAYBE_CASE_LIST : {$$=0;}
1789 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1790 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1791 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1792 CASE_LIST: CASE {$$=$1;}
1793 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1795 CASE: "case" E ':' MAYBECODE {
1797 $$ = code_append($$, $2.c);
1798 code_t*j = $$ = abc_ifne($$, 0);
1799 $$ = code_append($$, $4);
1800 if($$->opcode != OPCODE___BREAK__) {
1801 $$ = abc___fallthrough__($$, "");
1803 code_t*e = $$ = abc_nop($$);
1806 DEFAULT: "default" ':' MAYBECODE {
1809 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1811 $$ = code_append($$, $7);
1812 code_t*out = $$ = abc_pop($$);
1813 breakjumpsto($$, $1, out);
1815 code_t*c = $$,*lastblock=0;
1817 if(c->opcode == OPCODE_IFNE) {
1818 if(!c->next) syntaxerror("internal error in fallthrough handling");
1820 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1822 c->opcode = OPCODE_JUMP;
1823 c->branch = lastblock;
1825 /* fall through end of switch */
1826 c->opcode = OPCODE_NOP;
1836 /* ------------ try / catch /finally ---------------- */
1838 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1840 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1841 multiname_t name = {QNAME, &name_ns, 0, $3};
1843 NEW(abc_exception_t, e)
1844 e->exc_type = sig2mname($4);
1845 e->var_name = multiname_clone(&name);
1849 int i = find_variable_safe($3)->index;
1850 e->target = c = abc_nop(0);
1851 c = abc_setlocal(c, i);
1852 c = code_append(c, $8);
1858 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
1864 NEW(abc_exception_t, e)
1865 e->exc_type = 0; //all exceptions
1866 e->var_name = 0; //no name
1869 e->to = code_append(e->to, $4);
1875 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
1876 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
1877 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
1878 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
1882 list_append($$.l,$2);
1883 $$.finally = $2->to;$2->to=0;
1886 CATCH_FINALLY_LIST: FINALLY {
1890 list_append($$.l,$1);
1891 $$.finally = $1->to;$1->to=0;
1895 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
1896 code_t*out = abc_nop(0);
1898 code_t*start = abc_nop(0);
1899 $$ = code_append(start, $4);
1900 if(!is_break_or_jump($4)) {
1901 $$ = abc_jump($$, out);
1903 code_t*end = $$ = abc_nop($$);
1907 tmp = new_variable("__finally__", 0, 0);
1909 abc_exception_list_t*l = $6.l;
1912 abc_exception_t*e = l->abc_exception;
1914 $$ = code_append($$, e->target);
1915 $$ = abc_jump($$, out);
1917 parserassert((ptroff_t)$6.finally);
1919 e->target = $$ = abc_nop($$);
1920 $$ = abc___rethrow__($$);
1928 $$ = code_append($$, out);
1930 $$ = insert_finally($$, $6.finally, tmp);
1932 list_concat(state->method->exceptions, $6.l);
1938 /* ------------ throw ------------------------------- */
1940 THROW : "throw" EXPRESSION {
1944 THROW : "throw" %prec prec_none {
1945 if(!state->exception_name)
1946 syntaxerror("re-throw only possible within a catch block");
1947 variable_t*v = find_variable(state->exception_name);
1949 $$=abc_getlocal($$, v->index);
1953 /* ------------ with -------------------------------- */
1955 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1957 $$ = abc_pushscope($$);
1958 $$ = code_append($$, $5);
1959 $$ = abc_popscope($$);
1962 /* ------------ packages and imports ---------------- */
1964 X_IDENTIFIER: T_IDENTIFIER
1965 | "package" {PASS12 $$="package";}
1967 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
1968 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
1970 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
1971 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
1972 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
1973 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
1975 IMPORT : "import" QNAME {
1978 syntaxerror("Couldn't import class\n");
1979 state_has_imports();
1980 dict_put(state->imports, c->name, c);
1983 IMPORT : "import" PACKAGE '.' '*' {
1986 state_has_imports();
1987 list_append(state->wildcard_imports, i);
1991 /* ------------ classes and interfaces (header) -------------- */
1993 MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
1994 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
1995 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
1996 MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
1998 MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
1999 | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
2000 | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
2001 | KW_STATIC {PASS12 $$=FLAG_STATIC;}
2002 | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
2003 | KW_FINAL {PASS12 $$=FLAG_FINAL;}
2004 | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
2005 | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
2006 | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
2008 EXTENDS : {$$=registry_getobjectclass();}
2009 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
2011 EXTENDS_LIST : {$$=list_new();}
2012 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
2014 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2015 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {PASS12 $$=$2;}
2017 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2018 EXTENDS IMPLEMENTS_LIST
2019 '{' {PASS12 startclass($1,$3,$4,$5, 0);}
2021 '}' {PASS12 endclass();$$=0;}
2023 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2025 '{' {PASS12 startclass($1,$3,0,$4,1);}
2026 MAYBE_INTERFACE_BODY
2027 '}' {PASS12 endclass();$$=0;}
2029 /* ------------ classes and interfaces (body) -------------- */
2032 MAYBE_CLASS_BODY : CLASS_BODY
2033 CLASS_BODY : CLASS_BODY_ITEM
2034 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2035 CLASS_BODY_ITEM : ';'
2036 CLASS_BODY_ITEM : SLOT_DECLARATION
2037 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2039 CLASS_BODY_ITEM : CODE_STATEMENT {
2040 code_t*c = state->cls->static_init;
2041 c = code_append(c, $1);
2042 state->cls->static_init = c;
2045 MAYBE_INTERFACE_BODY :
2046 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2047 INTERFACE_BODY : IDECLARATION
2048 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2050 IDECLARATION : "var" T_IDENTIFIER {
2051 syntaxerror("variable declarations not allowed in interfaces");
2053 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2056 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2057 syntaxerror("invalid method modifiers: interface methods always need to be public");
2059 startfunction(0,$1,$3,$4,&$6,$8);
2060 endfunction(0,$1,$3,$4,&$6,$8, 0);
2063 /* ------------ classes and interfaces (body, slots ) ------- */
2065 VARCONST: "var" | "const"
2067 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
2069 memberinfo_t* info = state->cls?
2070 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
2071 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
2074 info->flags = flags;
2077 namespace_t mname_ns = {flags2access(flags), ""};
2078 multiname_t mname = {QNAME, &mname_ns, 0, $3};
2080 trait_list_t**traits;
2084 mname_ns.name = state->package;
2085 traits = &global->init->traits;
2086 code = &global->init->method->body->code;
2087 } else if(flags&FLAG_STATIC) {
2089 traits = &state->cls->abc->static_traits;
2090 code = &state->cls->static_init;
2092 // instance variable
2093 traits = &state->cls->abc->traits;
2094 code = &state->cls->init;
2100 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2102 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2104 info->slot = t->slot_id;
2106 /* initalization code (if needed) */
2108 if($5.c && !is_pushundefined($5.c)) {
2109 c = abc_getlocal_0(c);
2110 c = code_append(c, $5.c);
2111 c = converttype(c, $5.t, $4);
2112 c = abc_setslot(c, t->slot_id);
2115 *code = code_append(*code, c);
2118 t->kind= TRAIT_CONST;
2124 /* ------------ constants -------------------------------------- */
2126 MAYBESTATICCONSTANT: {$$=0;}
2127 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2129 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2130 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2131 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2132 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2133 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
2134 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2135 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2136 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2137 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2139 /* ------------ classes and interfaces (body, functions) ------- */
2141 // non-vararg version
2143 memset(&$$,0,sizeof($$));
2145 MAYBE_PARAM_LIST: PARAM_LIST {
2150 MAYBE_PARAM_LIST: "..." PARAM {
2151 memset(&$$,0,sizeof($$));
2153 list_append($$.list, $2);
2155 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2158 list_append($$.list, $4);
2162 PARAM_LIST: PARAM_LIST ',' PARAM {
2164 list_append($$.list, $3);
2167 memset(&$$,0,sizeof($$));
2168 list_append($$.list, $1);
2171 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2172 $$ = malloc(sizeof(param_t));
2177 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2178 $$ = malloc(sizeof(param_t));
2180 $$->type = TYPE_ANY;
2183 GETSET : "get" {$$=$1;}
2187 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2188 MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}'
2193 if(state->method->late_binding) {
2194 c = abc_getlocal_0(c);
2195 c = abc_pushscope(c);
2197 if(state->method->is_constructor && !state->method->has_super) {
2198 // call default constructor
2199 c = abc_getlocal_0(c);
2200 c = abc_constructsuper(c, 0);
2202 c = wrap_function(c, 0, $11);
2204 endfunction(0,$1,$3,$4,&$6,$8,c);
2208 MAYBE_IDENTIFIER: T_IDENTIFIER
2209 MAYBE_IDENTIFIER: {$$=0;}
2210 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
2212 syntaxerror("nested functions not supported yet");
2216 /* ------------- package + class ids --------------- */
2218 CLASS: T_IDENTIFIER {
2221 /* try current package */
2222 $$ = find_class($1);
2223 if(!$$) syntaxerror("Could not find class %s\n", $1);
2226 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2229 $$ = registry_findclass($1, $3);
2230 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
2234 QNAME: PACKAGEANDCLASS
2237 QNAME_LIST : QNAME {PASS12 $$=list_new();list_append($$, $1);}
2238 QNAME_LIST : QNAME_LIST ',' QNAME {PASS12 $$=$1;list_append($$,$3);}
2240 TYPE : QNAME {$$=$1;}
2241 | '*' {$$=registry_getanytype();}
2242 | "void" {$$=registry_getanytype();}
2244 | "String" {$$=registry_getstringclass();}
2245 | "int" {$$=registry_getintclass();}
2246 | "uint" {$$=registry_getuintclass();}
2247 | "Boolean" {$$=registry_getbooleanclass();}
2248 | "Number" {$$=registry_getnumberclass();}
2251 MAYBETYPE: ':' TYPE {$$=$2;}
2254 /* ----------function calls, delete, constructor calls ------ */
2256 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2257 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2259 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2260 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2261 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2264 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2266 $$.cc = code_append($1.cc, $3.c);
2269 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2274 $$.c = abc_getglobalscope($$.c);
2275 $$.c = abc_getslot($$.c, $2->slot);
2277 $$.c = abc_findpropstrict2($$.c, &m);
2280 $$.c = code_append($$.c, $3.cc);
2283 $$.c = abc_construct($$.c, $3.len);
2285 $$.c = abc_constructprop2($$.c, &m, $3.len);
2289 /* TODO: use abc_call (for calling local variables),
2290 abc_callstatic (for calling own methods)
2293 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2296 if($$.c->opcode == OPCODE_COERCE_A) {
2297 $$.c = code_cutlast($$.c);
2299 code_t*paramcode = $3.cc;
2302 if($$.c->opcode == OPCODE_GETPROPERTY) {
2303 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2304 $$.c = code_cutlast($$.c);
2305 $$.c = code_append($$.c, paramcode);
2306 $$.c = abc_callproperty2($$.c, name, $3.len);
2307 multiname_destroy(name);
2308 } else if($$.c->opcode == OPCODE_GETSLOT) {
2309 int slot = (int)(ptroff_t)$$.c->data[0];
2310 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2311 if(t->kind!=TRAIT_METHOD) {
2312 //ok: flash allows to assign closures to members.
2314 multiname_t*name = t->name;
2315 $$.c = code_cutlast($$.c);
2316 $$.c = code_append($$.c, paramcode);
2317 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2318 $$.c = abc_callproperty2($$.c, name, $3.len);
2319 } else if($$.c->opcode == OPCODE_GETSUPER) {
2320 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2321 $$.c = code_cutlast($$.c);
2322 $$.c = code_append($$.c, paramcode);
2323 $$.c = abc_callsuper2($$.c, name, $3.len);
2324 multiname_destroy(name);
2326 $$.c = abc_getlocal_0($$.c);
2327 $$.c = code_append($$.c, paramcode);
2328 $$.c = abc_call($$.c, $3.len);
2333 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2334 $$.t = $1.t->function->return_type;
2336 $$.c = abc_coerce_a($$.c);
2341 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2342 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2343 if(!state->method) syntaxerror("super() not allowed outside of a function");
2344 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2347 $$.c = abc_getlocal_0($$.c);
2349 $$.c = code_append($$.c, $3.cc);
2351 this is dependent on the control path, check this somewhere else
2352 if(state->method->has_super)
2353 syntaxerror("constructor may call super() only once");
2355 state->method->has_super = 1;
2356 $$.c = abc_constructsuper($$.c, $3.len);
2357 $$.c = abc_pushundefined($$.c);
2361 DELETE: "delete" E {
2363 if($$.c->opcode == OPCODE_COERCE_A) {
2364 $$.c = code_cutlast($$.c);
2366 multiname_t*name = 0;
2367 if($$.c->opcode == OPCODE_GETPROPERTY) {
2368 $$.c->opcode = OPCODE_DELETEPROPERTY;
2369 } else if($$.c->opcode == OPCODE_GETSLOT) {
2370 int slot = (int)(ptroff_t)$$.c->data[0];
2371 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2372 $$.c = code_cutlast($$.c);
2373 $$.c = abc_deleteproperty2($$.c, name);
2375 $$.c = abc_getlocal_0($$.c);
2376 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2377 $$.c = abc_deleteproperty2($$.c, &m);
2379 $$.t = TYPE_BOOLEAN;
2382 RETURN: "return" %prec prec_none {
2383 $$ = abc_returnvoid(0);
2385 RETURN: "return" EXPRESSION {
2387 $$ = abc_returnvalue($$);
2390 // ----------------------- expression types -------------------------------------
2392 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2393 EXPRESSION : E %prec below_minus {$$ = $1;}
2394 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2396 $$.c = cut_last_push($$.c);
2397 $$.c = code_append($$.c,$3.c);
2400 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2401 $$=cut_last_push($1.c);
2404 // ----------------------- expression evaluation -------------------------------------
2406 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2407 //V : CONSTANT {$$ = 0;}
2409 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2410 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2411 //V : NEW {$$ = $1.c;}
2413 //V : DELETE {$$ = $1.c;}
2414 E : DELETE {$$ = $1;}
2418 namespace_t ns = {ACCESS_PACKAGE, ""};
2419 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2421 $$.c = abc_getlex2($$.c, &m);
2422 $$.c = abc_pushstring($$.c, $1.pattern);
2423 $$.c = abc_construct($$.c, 1);
2425 $$.c = abc_getlex2($$.c, &m);
2426 $$.c = abc_pushstring($$.c, $1.pattern);
2427 $$.c = abc_pushstring($$.c, $1.options);
2428 $$.c = abc_construct($$.c, 2);
2433 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2434 //MULTINAME(m, registry_getintclass());
2435 //$$.c = abc_coerce2($$.c, &m); // FIXME
2438 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2441 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2444 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2447 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2450 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2453 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2456 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2457 $$.t = TYPE_BOOLEAN;
2459 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2460 $$.t = TYPE_BOOLEAN;
2462 CONSTANT : "null" {$$.c = abc_pushnull(0);
2467 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2468 $$.t = TYPE_BOOLEAN;
2470 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2471 $$.t = TYPE_BOOLEAN;
2473 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2474 $$.t = TYPE_BOOLEAN;
2476 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2477 $$.t = TYPE_BOOLEAN;
2479 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2480 $$.t = TYPE_BOOLEAN;
2482 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2483 $$.t = TYPE_BOOLEAN;
2485 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2486 $$.t = TYPE_BOOLEAN;
2488 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2489 $$.t = TYPE_BOOLEAN;
2492 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2494 $$.c = converttype($$.c, $1.t, $$.t);
2495 $$.c = abc_dup($$.c);
2496 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2497 $$.c = cut_last_push($$.c);
2498 $$.c = code_append($$.c,$3.c);
2499 $$.c = converttype($$.c, $3.t, $$.t);
2500 code_t*label = $$.c = abc_label($$.c);
2501 jmp->branch = label;
2504 $$.t = join_types($1.t, $3.t, 'A');
2505 /*printf("%08x:\n",$1.t);
2506 code_dump($1.c, 0, 0, "", stdout);
2507 printf("%08x:\n",$3.t);
2508 code_dump($3.c, 0, 0, "", stdout);
2509 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2511 $$.c = converttype($$.c, $1.t, $$.t);
2512 $$.c = abc_dup($$.c);
2513 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2514 $$.c = cut_last_push($$.c);
2515 $$.c = code_append($$.c,$3.c);
2516 $$.c = converttype($$.c, $3.t, $$.t);
2517 code_t*label = $$.c = abc_label($$.c);
2518 jmp->branch = label;
2521 E : '!' E {$$.c=$2.c;
2522 $$.c = abc_not($$.c);
2523 $$.t = TYPE_BOOLEAN;
2526 E : '~' E {$$.c=$2.c;
2527 $$.c = abc_bitnot($$.c);
2531 E : E '&' E {$$.c = code_append($1.c,$3.c);
2532 $$.c = abc_bitand($$.c);
2536 E : E '^' E {$$.c = code_append($1.c,$3.c);
2537 $$.c = abc_bitxor($$.c);
2541 E : E '|' E {$$.c = code_append($1.c,$3.c);
2542 $$.c = abc_bitor($$.c);
2546 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2547 $$.c = abc_rshift($$.c);
2550 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2551 $$.c = abc_urshift($$.c);
2554 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2555 $$.c = abc_lshift($$.c);
2559 E : E '/' E {$$.c = code_append($1.c,$3.c);
2560 $$.c = abc_divide($$.c);
2563 E : E '%' E {$$.c = code_append($1.c,$3.c);
2564 $$.c = abc_modulo($$.c);
2567 E : E '+' E {$$.c = code_append($1.c,$3.c);
2568 if(BOTH_INT($1.t, $3.t)) {
2569 $$.c = abc_add_i($$.c);
2572 $$.c = abc_add($$.c);
2573 $$.t = join_types($1.t,$3.t,'+');
2576 E : E '-' E {$$.c = code_append($1.c,$3.c);
2577 if(BOTH_INT($1.t,$3.t)) {
2578 $$.c = abc_subtract_i($$.c);
2581 $$.c = abc_subtract($$.c);
2585 E : E '*' E {$$.c = code_append($1.c,$3.c);
2586 if(BOTH_INT($1.t,$3.t)) {
2587 $$.c = abc_multiply_i($$.c);
2590 $$.c = abc_multiply($$.c);
2595 E : E "in" E {$$.c = code_append($1.c,$3.c);
2596 $$.c = abc_in($$.c);
2597 $$.t = TYPE_BOOLEAN;
2600 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2601 if(use_astype && TYPE_IS_CLASS($3.t)) {
2602 MULTINAME(m,$3.t->cls);
2603 $$.c = abc_astype2($1.c, &m);
2606 $$.c = code_append($1.c, $3.c);
2607 $$.c = abc_astypelate($$.c);
2612 E : E "instanceof" E
2613 {$$.c = code_append($1.c, $3.c);
2614 $$.c = abc_instanceof($$.c);
2615 $$.t = TYPE_BOOLEAN;
2618 E : E "is" E {$$.c = code_append($1.c, $3.c);
2619 $$.c = abc_istypelate($$.c);
2620 $$.t = TYPE_BOOLEAN;
2623 E : "typeof" '(' E ')' {
2625 $$.c = abc_typeof($$.c);
2630 $$.c = cut_last_push($2.c);
2631 $$.c = abc_pushundefined($$.c);
2635 E : "void" { $$.c = abc_pushundefined(0);
2639 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2644 $$.c=abc_negate_i($$.c);
2647 $$.c=abc_negate($$.c);
2654 $$.c = code_append($$.c, $3.c);
2656 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2657 $$.c = abc_getproperty2($$.c, &m);
2658 $$.t = 0; // array elements have unknown type
2661 E : '[' MAYBE_EXPRESSION_LIST ']' {
2663 $$.c = code_append($$.c, $2.cc);
2664 $$.c = abc_newarray($$.c, $2.len);
2665 $$.t = registry_getarrayclass();
2668 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2669 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
2671 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2673 $$.cc = code_append($$.cc, $1.c);
2674 $$.cc = code_append($$.cc, $3.c);
2677 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2680 $$.cc = code_append($$.cc, $3.c);
2681 $$.cc = code_append($$.cc, $5.c);
2686 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2688 $$.c = code_append($$.c, $2.cc);
2689 $$.c = abc_newobject($$.c, $2.len/2);
2690 $$.t = registry_getobjectclass();
2695 if(BOTH_INT($1.t,$3.t)) {
2696 c=abc_multiply_i(c);
2700 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2701 $$.c = toreadwrite($1.c, c, 0, 0);
2706 code_t*c = abc_modulo($3.c);
2707 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2708 $$.c = toreadwrite($1.c, c, 0, 0);
2712 code_t*c = abc_lshift($3.c);
2713 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2714 $$.c = toreadwrite($1.c, c, 0, 0);
2718 code_t*c = abc_rshift($3.c);
2719 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2720 $$.c = toreadwrite($1.c, c, 0, 0);
2724 code_t*c = abc_urshift($3.c);
2725 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2726 $$.c = toreadwrite($1.c, c, 0, 0);
2730 code_t*c = abc_divide($3.c);
2731 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2732 $$.c = toreadwrite($1.c, c, 0, 0);
2736 code_t*c = abc_bitor($3.c);
2737 c=converttype(c, TYPE_INT, $1.t);
2738 $$.c = toreadwrite($1.c, c, 0, 0);
2744 if(TYPE_IS_INT($1.t)) {
2748 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2751 $$.c = toreadwrite($1.c, c, 0, 0);
2754 E : E "-=" E { code_t*c = $3.c;
2755 if(TYPE_IS_INT($1.t)) {
2756 c=abc_subtract_i(c);
2759 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2762 $$.c = toreadwrite($1.c, c, 0, 0);
2765 E : E '=' E { code_t*c = 0;
2766 c = code_append(c, $3.c);
2767 c = converttype(c, $3.t, $1.t);
2768 $$.c = toreadwrite($1.c, c, 1, 0);
2772 E : E '?' E ':' E %prec below_assignment {
2773 $$.t = join_types($3.t,$5.t,'?');
2775 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2776 $$.c = code_append($$.c, $3.c);
2777 $$.c = converttype($$.c, $3.t, $$.t);
2778 code_t*j2 = $$.c = abc_jump($$.c, 0);
2779 $$.c = j1->branch = abc_label($$.c);
2780 $$.c = code_append($$.c, $5.c);
2781 $$.c = converttype($$.c, $3.t, $$.t);
2782 $$.c = j2->branch = abc_label($$.c);
2785 E : E "++" { code_t*c = 0;
2786 classinfo_t*type = $1.t;
2787 if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
2788 int nr = getlocalnr($1.c);
2789 code_free($1.c);$1.c=0;
2790 if(TYPE_IS_INT($1.t)) {
2791 $$.c = abc_getlocal(0, nr);
2792 $$.c = abc_inclocal_i($$.c, nr);
2793 } else if(TYPE_IS_NUMBER($1.t)) {
2794 $$.c = abc_getlocal(0, nr);
2795 $$.c = abc_inclocal($$.c, nr);
2796 } else syntaxerror("internal error");
2798 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2799 c=abc_increment_i(c);
2805 c=converttype(c, type, $1.t);
2806 $$.c = toreadwrite($1.c, c, 0, 1);
2811 // TODO: use inclocal, like with ++
2812 E : E "--" { code_t*c = 0;
2813 classinfo_t*type = $1.t;
2814 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2815 c=abc_decrement_i(c);
2821 c=converttype(c, type, $1.t);
2822 $$.c = toreadwrite($1.c, c, 0, 1);
2826 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2827 classinfo_t*type = $2.t;
2828 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2829 c=abc_increment_i(c);
2835 c=converttype(c, type, $2.t);
2836 $$.c = toreadwrite($2.c, c, 0, 0);
2840 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2841 classinfo_t*type = $2.t;
2842 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2843 c=abc_decrement_i(c);
2849 c=converttype(c, type, $2.t);
2850 $$.c = toreadwrite($2.c, c, 0, 0);
2854 E : "super" '.' T_IDENTIFIER
2855 { if(!state->cls->info)
2856 syntaxerror("super keyword not allowed outside a class");
2857 classinfo_t*t = state->cls->info->superclass;
2858 if(!t) t = TYPE_OBJECT;
2860 memberinfo_t*f = registry_findmember(t, $3, 1);
2861 namespace_t ns = flags2namespace(f->flags, "");
2862 MEMBER_MULTINAME(m, f, $3);
2864 $$.c = abc_getlocal_0($$.c);
2865 $$.c = abc_getsuper2($$.c, &m);
2866 $$.t = memberinfo_gettype(f);
2869 E : E '.' T_IDENTIFIER
2871 classinfo_t*t = $1.t;
2873 if(TYPE_IS_CLASS(t) && t->cls) {
2878 memberinfo_t*f = registry_findmember(t, $3, 1);
2880 if(f && !is_static != !(f->flags&FLAG_STATIC))
2882 if(f && f->slot && !noslot) {
2883 $$.c = abc_getslot($$.c, f->slot);
2885 MEMBER_MULTINAME(m, f, $3);
2886 $$.c = abc_getproperty2($$.c, &m);
2888 /* determine type */
2889 $$.t = memberinfo_gettype(f);
2891 $$.c = abc_coerce_a($$.c);
2893 /* when resolving a property on an unknown type, we do know the
2894 name of the property (and don't seem to need the package), but
2895 we need to make avm2 try out all access modes */
2896 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2897 $$.c = abc_getproperty2($$.c, &m);
2898 $$.c = abc_coerce_a($$.c);
2899 $$.t = registry_getanytype();
2903 VAR_READ : T_IDENTIFIER {
2910 /* look at variables */
2911 if((v = find_variable($1))) {
2912 // $1 is a local variable
2913 $$.c = abc_getlocal($$.c, v->index);
2918 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
2920 /* look at current class' members */
2921 if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
2922 (f->flags&FLAG_STATIC) >= i_am_static) {
2923 // $1 is a function in this class
2924 int var_is_static = (f->flags&FLAG_STATIC);
2926 if(f->kind == MEMBER_METHOD) {
2927 $$.t = TYPE_FUNCTION(f);
2931 if(var_is_static && !i_am_static) {
2932 /* access to a static member from a non-static location.
2933 do this via findpropstrict:
2934 there doesn't seem to be any non-lookup way to access
2935 static properties of a class */
2936 state->method->late_binding = 1;
2938 namespace_t ns = {flags2access(f->flags), ""};
2939 multiname_t m = {QNAME, &ns, 0, $1};
2940 $$.c = abc_findpropstrict2($$.c, &m);
2941 $$.c = abc_getproperty2($$.c, &m);
2943 } else if(f->slot>0) {
2944 $$.c = abc_getlocal_0($$.c);
2945 $$.c = abc_getslot($$.c, f->slot);
2948 namespace_t ns = {flags2access(f->flags), ""};
2949 multiname_t m = {QNAME, &ns, 0, $1};
2950 $$.c = abc_getlocal_0($$.c);
2951 $$.c = abc_getproperty2($$.c, &m);
2956 /* look at actual classes, in the current package and imported */
2957 if((a = find_class($1))) {
2958 if(a->flags & FLAG_METHOD) {
2960 $$.c = abc_findpropstrict2($$.c, &m);
2961 $$.c = abc_getproperty2($$.c, &m);
2962 if(a->function->kind == MEMBER_METHOD) {
2963 $$.t = TYPE_FUNCTION(a->function);
2965 $$.t = a->function->type;
2969 $$.c = abc_getglobalscope($$.c);
2970 $$.c = abc_getslot($$.c, a->slot);
2973 $$.c = abc_getlex2($$.c, &m);
2975 $$.t = TYPE_CLASS(a);
2980 /* unknown object, let the avm2 resolve it */
2982 if(strcmp($1,"trace"))
2983 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
2984 state->method->late_binding = 1;
2986 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2989 $$.c = abc_findpropstrict2($$.c, &m);
2990 $$.c = abc_getproperty2($$.c, &m);
2995 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2996 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2997 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2999 // ----------------- namespaces -------------------------------------------------
3001 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
3002 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
3003 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
3005 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}