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__";
953 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
957 /* retrieve the member info that we stored in the first pass.
958 TODO: better getter/setter support? */
959 if(!state->cls) state->method->info = registry_findclass(state->package, name)->function;
960 else state->method->info = registry_findmember(state->cls->info, name, 0);
962 global->variable_count = 0;
963 /* state->vars is initialized by state_new */
964 if(!state->method->is_global)
965 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
967 new_variable("globalscope", 0, 0);
969 for(p=params->list;p;p=p->next) {
970 new_variable(p->param->name, p->param->type, 0);
975 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
976 params_t*params, classinfo_t*return_type, code_t*body)
985 multiname_t*type2 = sig2mname(return_type);
987 if(state->method->is_constructor) {
988 f = abc_class_getconstructor(state->cls->abc, type2);
989 } else if(!state->method->is_global) {
990 namespace_t mname_ns = flags2namespace(flags, "");
991 multiname_t mname = {QNAME, &mname_ns, 0, name};
993 if(flags&FLAG_STATIC)
994 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
996 f = abc_class_method(state->cls->abc, type2, &mname);
997 slot = f->trait->slot_id;
999 namespace_t mname_ns = flags2namespace(flags, state->package);
1000 multiname_t mname = {QNAME, &mname_ns, 0, name};
1002 f = abc_method_new(global->file, type2, 1);
1003 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1004 //abc_code_t*c = global->init->method->body->code;
1006 //flash doesn't seem to allow us to access function slots
1007 //state->method->info->slot = slot;
1009 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1010 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1011 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1012 if(params->varargs) f->flags |= METHOD_NEED_REST;
1016 for(p=params->list;p;p=p->next) {
1017 if(params->varargs && !p->next) {
1018 break; //varargs: omit last parameter in function signature
1020 multiname_t*m = sig2mname(p->param->type);
1021 list_append(f->parameters, m);
1022 if(p->param->value) {
1023 check_constant_against_type(p->param->type, p->param->value);
1024 opt=1;list_append(f->optional_parameters, p->param->value);
1026 syntaxerror("non-optional parameter not allowed after optional parameters");
1029 check_code_for_break(body);
1032 f->body->code = body;
1033 f->body->exceptions = state->method->exceptions;
1034 } else { //interface
1036 syntaxerror("interface methods can't have a method body");
1044 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1049 void breakjumpsto(code_t*c, char*name, code_t*jump)
1052 if(c->opcode == OPCODE___BREAK__) {
1053 string_t*name2 = c->data[0];
1054 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1055 c->opcode = OPCODE_JUMP;
1062 void continuejumpsto(code_t*c, char*name, code_t*jump)
1065 if(c->opcode == OPCODE___CONTINUE__) {
1066 string_t*name2 = c->data[0];
1067 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1068 c->opcode = OPCODE_JUMP;
1076 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1077 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1078 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1080 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1082 if(!type1 || !type2)
1083 return registry_getanytype();
1084 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1085 return registry_getanytype();
1088 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1097 return registry_getanytype();
1099 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1104 return abc_coerce_a(c);
1108 // cast an "any" type to a specific type. subject to
1109 // runtime exceptions
1110 return abc_coerce2(c, &m);
1113 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1114 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1115 // allow conversion between number types
1116 return abc_coerce2(c, &m);
1118 //printf("%s.%s\n", from.package, from.name);
1119 //printf("%s.%s\n", to.package, to.name);
1121 classinfo_t*supertype = from;
1123 if(supertype == to) {
1124 // target type is one of from's superclasses
1125 return abc_coerce2(c, &m);
1128 while(supertype->interfaces[t]) {
1129 if(supertype->interfaces[t]==to) {
1130 // target type is one of from's interfaces
1131 return abc_coerce2(c, &m);
1135 supertype = supertype->superclass;
1137 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1139 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1141 syntaxerror("can't convert type %s to %s", from->name, to->name);
1142 return 0; // make gcc happy
1145 code_t*defaultvalue(code_t*c, classinfo_t*type)
1147 if(TYPE_IS_INT(type)) {
1148 c = abc_pushbyte(c, 0);
1149 } else if(TYPE_IS_UINT(type)) {
1150 c = abc_pushuint(c, 0);
1151 } else if(TYPE_IS_FLOAT(type)) {
1153 } else if(TYPE_IS_BOOLEAN(type)) {
1154 c = abc_pushfalse(c);
1156 //c = abc_pushundefined(c);
1158 c = abc_pushnull(c);
1160 c = abc_coerce2(c, &m);
1165 char is_pushundefined(code_t*c)
1167 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1170 static classinfo_t* find_class(char*name)
1174 c = registry_findclass(state->package, name);
1177 /* try explicit imports */
1178 dictentry_t* e = dict_get_slot(state->imports, name);
1181 if(!strcmp(e->key, name)) {
1182 c = (classinfo_t*)e->data;
1188 /* try package.* imports */
1189 import_list_t*l = state->wildcard_imports;
1191 //printf("does package %s contain a class %s?\n", l->import->package, name);
1192 c = registry_findclass(l->import->package, name);
1197 /* try global package */
1198 c = registry_findclass("", name);
1201 /* try local "filename" package */
1202 c = registry_findclass(current_filename_short, name);
1208 static char is_getlocal(code_t*c)
1210 if(!c || c->prev || c->next)
1212 return(c->opcode == OPCODE_GETLOCAL
1213 || c->opcode == OPCODE_GETLOCAL_0
1214 || c->opcode == OPCODE_GETLOCAL_1
1215 || c->opcode == OPCODE_GETLOCAL_2
1216 || c->opcode == OPCODE_GETLOCAL_3);
1218 static int getlocalnr(code_t*c)
1220 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1221 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1222 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1223 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1224 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1225 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1229 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1233 [prefix code] [read instruction]
1237 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1240 if(in && in->opcode == OPCODE_COERCE_A) {
1241 in = code_cutlast(in);
1244 syntaxerror("internal error");
1246 /* chop off read instruction */
1250 prefix = r->prev;r->prev = 0;
1256 char use_temp_var = readbefore;
1258 /* generate the write instruction, and maybe append a dup to the prefix code */
1259 code_t* write = abc_nop(0);
1260 if(r->opcode == OPCODE_GETPROPERTY) {
1261 write->opcode = OPCODE_SETPROPERTY;
1262 multiname_t*m = (multiname_t*)r->data[0];
1263 write->data[0] = multiname_clone(m);
1264 if(m->type == QNAME || m->type == MULTINAME) {
1266 prefix = abc_dup(prefix); // we need the object, too
1269 } else if(m->type == MULTINAMEL) {
1271 /* dupping two values on the stack requires 5 operations and one register-
1272 couldn't adobe just have given us a dup2? */
1273 int temp = gettempvar();
1274 prefix = abc_setlocal(prefix, temp);
1275 prefix = abc_dup(prefix);
1276 prefix = abc_getlocal(prefix, temp);
1277 prefix = abc_swap(prefix);
1278 prefix = abc_getlocal(prefix, temp);
1280 prefix = abc_kill(prefix, temp);
1284 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1286 } else if(r->opcode == OPCODE_GETSLOT) {
1287 write->opcode = OPCODE_SETSLOT;
1288 write->data[0] = r->data[0];
1290 prefix = abc_dup(prefix); // we need the object, too
1293 } else if(r->opcode == OPCODE_GETLOCAL) {
1294 write->opcode = OPCODE_SETLOCAL;
1295 write->data[0] = r->data[0];
1296 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1297 write->opcode = OPCODE_SETLOCAL_0;
1298 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1299 write->opcode = OPCODE_SETLOCAL_1;
1300 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1301 write->opcode = OPCODE_SETLOCAL_2;
1302 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1303 write->opcode = OPCODE_SETLOCAL_3;
1306 syntaxerror("illegal lvalue: can't assign a value to this expression");
1313 /* with getproperty/getslot, we have to be extra careful not
1314 to execute the read code twice, as it might have side-effects
1315 (e.g. if the property is in fact a setter/getter combination)
1317 So read the value, modify it, and write it again,
1318 using prefix only once and making sure (by using a temporary
1319 register) that the return value is what we just wrote */
1320 temp = gettempvar();
1321 c = code_append(c, prefix);
1322 c = code_append(c, r);
1325 c = abc_setlocal(c, temp);
1327 c = code_append(c, middlepart);
1330 c = abc_setlocal(c, temp);
1332 c = code_append(c, write);
1333 c = abc_getlocal(c, temp);
1334 c = abc_kill(c, temp);
1336 /* if we're allowed to execute the read code twice *and*
1337 the middlepart doesn't modify the code, things are easier.
1339 code_t* r2 = code_dup(r);
1340 //c = code_append(c, prefix);
1341 parserassert(!prefix);
1342 c = code_append(c, r);
1343 c = code_append(c, middlepart);
1344 c = code_append(c, write);
1345 c = code_append(c, r2);
1348 /* even smaller version: overwrite the value without reading
1352 c = code_append(c, prefix);
1355 c = code_append(c, middlepart);
1356 c = code_append(c, write);
1357 c = code_append(c, r);
1359 temp = gettempvar();
1361 c = code_append(c, prefix);
1363 c = code_append(c, middlepart);
1365 c = abc_setlocal(c, temp);
1366 c = code_append(c, write);
1367 c = abc_getlocal(c, temp);
1368 c = abc_kill(c, temp);
1374 char is_break_or_jump(code_t*c)
1378 if(c->opcode == OPCODE_JUMP ||
1379 c->opcode == OPCODE___BREAK__ ||
1380 c->opcode == OPCODE___CONTINUE__ ||
1381 c->opcode == OPCODE_THROW ||
1382 c->opcode == OPCODE_RETURNVOID ||
1383 c->opcode == OPCODE_RETURNVALUE) {
1390 #define IS_FINALLY_TARGET(op) \
1391 ((op) == OPCODE___CONTINUE__ || \
1392 (op) == OPCODE___BREAK__ || \
1393 (op) == OPCODE_RETURNVOID || \
1394 (op) == OPCODE_RETURNVALUE || \
1395 (op) == OPCODE___RETHROW__)
1397 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1399 #define NEED_EXTRA_STACK_ARG
1400 code_t*finally_label = abc_nop(0);
1401 NEW(lookupswitch_t, l);
1407 code_t*prev = i->prev;
1408 if(IS_FINALLY_TARGET(i->opcode)) {
1411 if(i->opcode == OPCODE___RETHROW__ ||
1412 i->opcode == OPCODE_RETURNVALUE) {
1413 if(i->opcode == OPCODE___RETHROW__)
1414 i->opcode = OPCODE_THROW;
1416 p = abc_coerce_a(p);
1417 p = abc_setlocal(p, tempvar);
1419 p = abc_pushbyte(p, count++);
1420 p = abc_jump(p, finally_label);
1421 code_t*target = p = abc_label(p);
1422 #ifdef NEED_EXTRA_STACK_ARG
1426 p = abc_getlocal(p, tempvar);
1429 p->next = i;i->prev = p;
1430 list_append(l->targets, target);
1436 c = abc_pushbyte(c, -1);
1437 c = code_append(c, finally_label);
1438 c = code_append(c, finally);
1440 #ifdef NEED_EXTRA_STACK_ARG
1443 c = abc_lookupswitch(c, l);
1444 c = l->def = abc_label(c);
1445 #ifdef NEED_EXTRA_STACK_ARG
1452 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1456 code_t*prev = i->prev;
1457 if(IS_FINALLY_TARGET(i->opcode)) {
1458 if(i->opcode == OPCODE___RETHROW__)
1459 i->opcode = OPCODE_THROW;
1460 code_t*end = code_dup(finally);
1461 code_t*start = code_start(end);
1462 if(prev) prev->next = start;
1469 return code_append(c, finally);
1472 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1478 int num_insertion_points=0;
1480 if(IS_FINALLY_TARGET(i->opcode))
1481 num_insertion_points++;
1488 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1493 int simple_version_cost = (1+num_insertion_points)*code_size;
1494 int lookup_version_cost = 4*num_insertion_points + 5;
1496 if(cantdup || simple_version_cost > lookup_version_cost) {
1497 printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
1498 return insert_finally_lookup(c, finally, tempvar);
1500 printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
1501 return insert_finally_simple(c, finally, tempvar);
1505 #define PASS1 }} if(as3_pass == 1) {{
1506 #define PASS1END }} if(as3_pass == 2) {{
1507 #define PASS2 }} if(as3_pass == 2) {{
1508 #define PASS12 }} {{
1509 #define PASS12END }} if(as3_pass == 2) {{
1515 /* ------------ code blocks / statements ---------------- */
1517 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1519 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1520 PROGRAM_CODE_LIST: PROGRAM_CODE
1521 | PROGRAM_CODE_LIST PROGRAM_CODE
1523 PROGRAM_CODE: PACKAGE_DECLARATION
1524 | INTERFACE_DECLARATION
1526 | FUNCTION_DECLARATION
1531 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1532 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1533 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1535 INPACKAGE_CODE: INTERFACE_DECLARATION
1537 | FUNCTION_DECLARATION
1542 MAYBECODE: CODE {$$=$1;}
1543 MAYBECODE: {$$=code_new();}
1545 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1546 CODE: CODEPIECE {$$=$1;}
1548 // code which also may appear outside a method
1549 CODE_STATEMENT: IMPORT
1551 CODE_STATEMENT: FOR_IN
1552 CODE_STATEMENT: WHILE
1553 CODE_STATEMENT: DO_WHILE
1554 CODE_STATEMENT: SWITCH
1556 CODE_STATEMENT: WITH
1558 CODE_STATEMENT: VOIDEXPRESSION
1560 // code which may appear anywhere
1561 CODEPIECE: ';' {$$=0;}
1562 CODEPIECE: CODE_STATEMENT
1563 CODEPIECE: VARIABLE_DECLARATION
1569 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1570 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1572 CODEBLOCK : '{' CODE '}' {$$=$2;}
1573 CODEBLOCK : '{' '}' {$$=0;}
1574 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1575 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1577 /* ------------ package init code ------------------- */
1579 PACKAGE_INITCODE: CODE_STATEMENT {
1580 code_t**cc = &global->init->method->body->code;
1581 *cc = code_append(*cc, $1);
1584 /* ------------ variables --------------------------- */
1586 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1587 | {$$.c=abc_pushundefined(0);
1591 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1592 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1594 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1595 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1597 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1599 if(variable_exists($1))
1600 syntaxerror("Variable %s already defined", $1);
1602 if(!is_subtype_of($3.t, $2)) {
1603 syntaxerror("Can't convert %s to %s", $3.t->name,
1607 int index = new_variable($1, $2, 1);
1610 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1612 $$ = converttype($$, $3.t, $2);
1613 $$ = abc_setlocal($$, index);
1615 $$ = defaultvalue(0, $2);
1616 $$ = abc_setlocal($$, index);
1619 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1621 $$ = abc_coerce_a($$);
1622 $$ = abc_setlocal($$, index);
1628 /* that's the default for a local register, anyway
1630 state->method->initcode = abc_pushundefined(state->method->initcode);
1631 state->method->initcode = abc_setlocal(state->method->initcode, index);
1633 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1636 /* ------------ control flow ------------------------- */
1638 MAYBEELSE: %prec below_else {$$ = code_new();}
1639 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1640 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1642 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1645 $$ = code_append($$, $4.c);
1646 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1648 $$ = code_append($$, $6);
1650 myjmp = $$ = abc_jump($$, 0);
1652 myif->branch = $$ = abc_nop($$);
1654 $$ = code_append($$, $7);
1655 myjmp->branch = $$ = abc_nop($$);
1661 FOR_INIT : {$$=code_new();}
1662 FOR_INIT : VARIABLE_DECLARATION
1663 FOR_INIT : VOIDEXPRESSION
1665 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1666 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1667 $$=$2;new_variable($2,$3,1);
1669 FOR_IN_INIT : T_IDENTIFIER {
1673 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1674 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1676 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1677 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1679 $$ = code_append($$, $2);
1680 code_t*loopstart = $$ = abc_label($$);
1681 $$ = code_append($$, $4.c);
1682 code_t*myif = $$ = abc_iffalse($$, 0);
1683 $$ = code_append($$, $8);
1684 code_t*cont = $$ = abc_nop($$);
1685 $$ = code_append($$, $6);
1686 $$ = abc_jump($$, loopstart);
1687 code_t*out = $$ = abc_nop($$);
1688 breakjumpsto($$, $1.name, out);
1689 continuejumpsto($$, $1.name, cont);
1696 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1697 variable_t*var = find_variable($2);
1698 char*tmp1name = concat2($2, "__tmp1__");
1699 int it = new_variable(tmp1name, TYPE_INT, 0);
1700 char*tmp2name = concat2($2, "__array__");
1701 int array = new_variable(tmp1name, 0, 0);
1704 $$ = code_append($$, $4.c);
1705 $$ = abc_coerce_a($$);
1706 $$ = abc_setlocal($$, array);
1707 $$ = abc_pushbyte($$, 0);
1708 $$ = abc_setlocal($$, it);
1710 code_t*loopstart = $$ = abc_label($$);
1712 $$ = abc_hasnext2($$, array, it);
1713 code_t*myif = $$ = abc_iffalse($$, 0);
1714 $$ = abc_getlocal($$, array);
1715 $$ = abc_getlocal($$, it);
1717 $$ = abc_nextname($$);
1719 $$ = abc_nextvalue($$);
1720 $$ = converttype($$, 0, var->type);
1721 $$ = abc_setlocal($$, var->index);
1723 $$ = code_append($$, $6);
1724 $$ = abc_jump($$, loopstart);
1726 code_t*out = $$ = abc_nop($$);
1727 breakjumpsto($$, $1.name, out);
1728 continuejumpsto($$, $1.name, loopstart);
1739 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1743 code_t*myjmp = $$ = abc_jump($$, 0);
1744 code_t*loopstart = $$ = abc_label($$);
1745 $$ = code_append($$, $6);
1746 code_t*cont = $$ = abc_nop($$);
1747 myjmp->branch = cont;
1748 $$ = code_append($$, $4.c);
1749 $$ = abc_iftrue($$, loopstart);
1750 code_t*out = $$ = abc_nop($$);
1751 breakjumpsto($$, $1, out);
1752 continuejumpsto($$, $1, cont);
1758 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1760 code_t*loopstart = $$ = abc_label($$);
1761 $$ = code_append($$, $3);
1762 code_t*cont = $$ = abc_nop($$);
1763 $$ = code_append($$, $6.c);
1764 $$ = abc_iftrue($$, loopstart);
1765 code_t*out = $$ = abc_nop($$);
1766 breakjumpsto($$, $1, out);
1767 continuejumpsto($$, $1, cont);
1773 BREAK : "break" %prec prec_none {
1774 $$ = abc___break__(0, "");
1776 BREAK : "break" T_IDENTIFIER {
1777 $$ = abc___break__(0, $2);
1779 CONTINUE : "continue" %prec prec_none {
1780 $$ = abc___continue__(0, "");
1782 CONTINUE : "continue" T_IDENTIFIER {
1783 $$ = abc___continue__(0, $2);
1786 MAYBE_CASE_LIST : {$$=0;}
1787 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1788 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1789 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1790 CASE_LIST: CASE {$$=$1;}
1791 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1793 CASE: "case" E ':' MAYBECODE {
1795 $$ = code_append($$, $2.c);
1796 code_t*j = $$ = abc_ifne($$, 0);
1797 $$ = code_append($$, $4);
1798 if($$->opcode != OPCODE___BREAK__) {
1799 $$ = abc___fallthrough__($$, "");
1801 code_t*e = $$ = abc_nop($$);
1804 DEFAULT: "default" ':' MAYBECODE {
1807 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1809 $$ = code_append($$, $7);
1810 code_t*out = $$ = abc_pop($$);
1811 breakjumpsto($$, $1, out);
1813 code_t*c = $$,*lastblock=0;
1815 if(c->opcode == OPCODE_IFNE) {
1816 if(!c->next) syntaxerror("internal error in fallthrough handling");
1818 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1820 c->opcode = OPCODE_JUMP;
1821 c->branch = lastblock;
1823 /* fall through end of switch */
1824 c->opcode = OPCODE_NOP;
1834 /* ------------ try / catch /finally ---------------- */
1836 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1838 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1839 multiname_t name = {QNAME, &name_ns, 0, $3};
1841 NEW(abc_exception_t, e)
1842 e->exc_type = sig2mname($4);
1843 e->var_name = multiname_clone(&name);
1847 int i = find_variable_safe($3)->index;
1848 e->target = c = abc_nop(0);
1849 c = abc_setlocal(c, i);
1850 c = code_append(c, $8);
1856 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
1862 NEW(abc_exception_t, e)
1863 e->exc_type = 0; //all exceptions
1864 e->var_name = 0; //no name
1867 e->to = code_append(e->to, $4);
1873 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
1874 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
1875 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
1876 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
1880 list_append($$.l,$2);
1881 $$.finally = $2->to;$2->to=0;
1884 CATCH_FINALLY_LIST: FINALLY {
1888 list_append($$.l,$1);
1889 $$.finally = $1->to;$1->to=0;
1893 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
1894 code_t*out = abc_nop(0);
1896 code_t*start = abc_nop(0);
1897 $$ = code_append(start, $4);
1898 if(!is_break_or_jump($4)) {
1899 $$ = abc_jump($$, out);
1901 code_t*end = $$ = abc_nop($$);
1905 tmp = new_variable("__finally__", 0, 0);
1907 abc_exception_list_t*l = $6.l;
1910 abc_exception_t*e = l->abc_exception;
1912 $$ = code_append($$, e->target);
1913 $$ = abc_jump($$, out);
1915 parserassert((ptroff_t)$6.finally);
1917 e->target = $$ = abc_nop($$);
1918 $$ = abc___rethrow__($$);
1926 $$ = code_append($$, out);
1928 $$ = insert_finally($$, $6.finally, tmp);
1930 list_concat(state->method->exceptions, $6.l);
1936 /* ------------ throw ------------------------------- */
1938 THROW : "throw" EXPRESSION {
1942 THROW : "throw" %prec prec_none {
1943 if(!state->exception_name)
1944 syntaxerror("re-throw only possible within a catch block");
1945 variable_t*v = find_variable(state->exception_name);
1947 $$=abc_getlocal($$, v->index);
1951 /* ------------ with -------------------------------- */
1953 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1955 $$ = abc_pushscope($$);
1956 $$ = code_append($$, $5);
1957 $$ = abc_popscope($$);
1960 /* ------------ packages and imports ---------------- */
1962 X_IDENTIFIER: T_IDENTIFIER
1963 | "package" {PASS12 $$="package";}
1965 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
1966 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
1968 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
1969 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
1970 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
1971 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
1973 IMPORT : "import" QNAME {
1976 syntaxerror("Couldn't import class\n");
1977 state_has_imports();
1978 dict_put(state->imports, c->name, c);
1981 IMPORT : "import" PACKAGE '.' '*' {
1984 state_has_imports();
1985 list_append(state->wildcard_imports, i);
1989 /* ------------ classes and interfaces (header) -------------- */
1991 MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
1992 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
1993 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
1994 MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
1996 MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
1997 | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
1998 | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
1999 | KW_STATIC {PASS12 $$=FLAG_STATIC;}
2000 | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
2001 | KW_FINAL {PASS12 $$=FLAG_FINAL;}
2002 | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
2003 | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
2004 | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
2006 EXTENDS : {$$=registry_getobjectclass();}
2007 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
2009 EXTENDS_LIST : {$$=list_new();}
2010 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
2012 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2013 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {PASS12 $$=$2;}
2015 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2016 EXTENDS IMPLEMENTS_LIST
2017 '{' {PASS12 startclass($1,$3,$4,$5, 0);}
2019 '}' {PASS12 endclass();$$=0;}
2021 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2023 '{' {PASS12 startclass($1,$3,0,$4,1);}
2024 MAYBE_INTERFACE_BODY
2025 '}' {PASS12 endclass();$$=0;}
2027 /* ------------ classes and interfaces (body) -------------- */
2030 MAYBE_CLASS_BODY : CLASS_BODY
2031 CLASS_BODY : CLASS_BODY_ITEM
2032 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2033 CLASS_BODY_ITEM : ';'
2034 CLASS_BODY_ITEM : SLOT_DECLARATION
2035 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2037 CLASS_BODY_ITEM : CODE_STATEMENT {
2038 code_t*c = state->cls->static_init;
2039 c = code_append(c, $1);
2040 state->cls->static_init = c;
2043 MAYBE_INTERFACE_BODY :
2044 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2045 INTERFACE_BODY : IDECLARATION
2046 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2048 IDECLARATION : "var" T_IDENTIFIER {
2049 syntaxerror("variable declarations not allowed in interfaces");
2051 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2054 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2055 syntaxerror("invalid method modifiers: interface methods always need to be public");
2057 startfunction(0,$1,$3,$4,&$6,$8);
2058 endfunction(0,$1,$3,$4,&$6,$8, 0);
2061 /* ------------ classes and interfaces (body, slots ) ------- */
2063 VARCONST: "var" | "const"
2065 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
2067 memberinfo_t* info = state->cls?
2068 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
2069 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
2072 info->flags = flags;
2075 namespace_t mname_ns = {flags2access(flags), ""};
2076 multiname_t mname = {QNAME, &mname_ns, 0, $3};
2078 trait_list_t**traits;
2082 mname_ns.name = state->package;
2083 traits = &global->init->traits;
2084 code = &global->init->method->body->code;
2085 } else if(flags&FLAG_STATIC) {
2087 traits = &state->cls->abc->static_traits;
2088 code = &state->cls->static_init;
2090 // instance variable
2091 traits = &state->cls->abc->traits;
2092 code = &state->cls->init;
2098 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2100 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2102 info->slot = t->slot_id;
2104 /* initalization code (if needed) */
2106 if($5.c && !is_pushundefined($5.c)) {
2107 c = abc_getlocal_0(c);
2108 c = code_append(c, $5.c);
2109 c = converttype(c, $5.t, $4);
2110 c = abc_setslot(c, t->slot_id);
2113 *code = code_append(*code, c);
2116 t->kind= TRAIT_CONST;
2122 /* ------------ constants -------------------------------------- */
2124 MAYBESTATICCONSTANT: {$$=0;}
2125 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2127 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2128 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2129 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2130 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2131 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
2132 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2133 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2134 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2135 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2137 /* ------------ classes and interfaces (body, functions) ------- */
2139 // non-vararg version
2141 memset(&$$,0,sizeof($$));
2143 MAYBE_PARAM_LIST: PARAM_LIST {
2148 MAYBE_PARAM_LIST: "..." PARAM {
2149 memset(&$$,0,sizeof($$));
2151 list_append($$.list, $2);
2153 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2156 list_append($$.list, $4);
2160 PARAM_LIST: PARAM_LIST ',' PARAM {
2162 list_append($$.list, $3);
2165 memset(&$$,0,sizeof($$));
2166 list_append($$.list, $1);
2169 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2170 $$ = malloc(sizeof(param_t));
2175 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2176 $$ = malloc(sizeof(param_t));
2178 $$->type = TYPE_ANY;
2181 GETSET : "get" {$$=$1;}
2185 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2186 MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}'
2191 if(state->method->late_binding) {
2192 c = abc_getlocal_0(c);
2193 c = abc_pushscope(c);
2195 if(state->method->is_constructor && !state->method->has_super) {
2196 // call default constructor
2197 c = abc_getlocal_0(c);
2198 c = abc_constructsuper(c, 0);
2200 c = wrap_function(c, 0, $11);
2202 endfunction(0,$1,$3,$4,&$6,$8,c);
2206 MAYBE_IDENTIFIER: T_IDENTIFIER
2207 MAYBE_IDENTIFIER: {$$=0;}
2208 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
2210 syntaxerror("nested functions not supported yet");
2214 /* ------------- package + class ids --------------- */
2216 CLASS: T_IDENTIFIER {
2219 /* try current package */
2220 $$ = find_class($1);
2221 if(!$$) syntaxerror("Could not find class %s\n", $1);
2224 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2227 $$ = registry_findclass($1, $3);
2228 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
2232 QNAME: PACKAGEANDCLASS
2235 QNAME_LIST : QNAME {PASS12 $$=list_new();list_append($$, $1);}
2236 QNAME_LIST : QNAME_LIST ',' QNAME {PASS12 $$=$1;list_append($$,$3);}
2238 TYPE : QNAME {$$=$1;}
2239 | '*' {$$=registry_getanytype();}
2240 | "void" {$$=registry_getanytype();}
2242 | "String" {$$=registry_getstringclass();}
2243 | "int" {$$=registry_getintclass();}
2244 | "uint" {$$=registry_getuintclass();}
2245 | "Boolean" {$$=registry_getbooleanclass();}
2246 | "Number" {$$=registry_getnumberclass();}
2249 MAYBETYPE: ':' TYPE {$$=$2;}
2252 /* ----------function calls, delete, constructor calls ------ */
2254 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2255 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2257 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2258 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2259 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2262 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2264 $$.cc = code_append($1.cc, $3.c);
2267 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2272 $$.c = abc_getglobalscope($$.c);
2273 $$.c = abc_getslot($$.c, $2->slot);
2275 $$.c = abc_findpropstrict2($$.c, &m);
2278 $$.c = code_append($$.c, $3.cc);
2281 $$.c = abc_construct($$.c, $3.len);
2283 $$.c = abc_constructprop2($$.c, &m, $3.len);
2287 /* TODO: use abc_call (for calling local variables),
2288 abc_callstatic (for calling own methods)
2291 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2294 if($$.c->opcode == OPCODE_COERCE_A) {
2295 $$.c = code_cutlast($$.c);
2297 code_t*paramcode = $3.cc;
2300 if($$.c->opcode == OPCODE_GETPROPERTY) {
2301 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2302 $$.c = code_cutlast($$.c);
2303 $$.c = code_append($$.c, paramcode);
2304 $$.c = abc_callproperty2($$.c, name, $3.len);
2305 multiname_destroy(name);
2306 } else if($$.c->opcode == OPCODE_GETSLOT) {
2307 int slot = (int)(ptroff_t)$$.c->data[0];
2308 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2309 if(t->kind!=TRAIT_METHOD) {
2310 //ok: flash allows to assign closures to members.
2312 multiname_t*name = t->name;
2313 $$.c = code_cutlast($$.c);
2314 $$.c = code_append($$.c, paramcode);
2315 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2316 $$.c = abc_callproperty2($$.c, name, $3.len);
2317 } else if($$.c->opcode == OPCODE_GETSUPER) {
2318 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2319 $$.c = code_cutlast($$.c);
2320 $$.c = code_append($$.c, paramcode);
2321 $$.c = abc_callsuper2($$.c, name, $3.len);
2322 multiname_destroy(name);
2324 $$.c = abc_getlocal_0($$.c);
2325 $$.c = code_append($$.c, paramcode);
2326 $$.c = abc_call($$.c, $3.len);
2331 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2332 $$.t = $1.t->function->return_type;
2334 $$.c = abc_coerce_a($$.c);
2339 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2340 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2341 if(!state->method) syntaxerror("super() not allowed outside of a function");
2342 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2345 $$.c = abc_getlocal_0($$.c);
2347 $$.c = code_append($$.c, $3.cc);
2349 this is dependent on the control path, check this somewhere else
2350 if(state->method->has_super)
2351 syntaxerror("constructor may call super() only once");
2353 state->method->has_super = 1;
2354 $$.c = abc_constructsuper($$.c, $3.len);
2355 $$.c = abc_pushundefined($$.c);
2359 DELETE: "delete" E {
2361 if($$.c->opcode == OPCODE_COERCE_A) {
2362 $$.c = code_cutlast($$.c);
2364 multiname_t*name = 0;
2365 if($$.c->opcode == OPCODE_GETPROPERTY) {
2366 $$.c->opcode = OPCODE_DELETEPROPERTY;
2367 } else if($$.c->opcode == OPCODE_GETSLOT) {
2368 int slot = (int)(ptroff_t)$$.c->data[0];
2369 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2370 $$.c = code_cutlast($$.c);
2371 $$.c = abc_deleteproperty2($$.c, name);
2373 $$.c = abc_getlocal_0($$.c);
2374 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2375 $$.c = abc_deleteproperty2($$.c, &m);
2377 $$.t = TYPE_BOOLEAN;
2380 RETURN: "return" %prec prec_none {
2381 $$ = abc_returnvoid(0);
2383 RETURN: "return" EXPRESSION {
2385 $$ = abc_returnvalue($$);
2388 // ----------------------- expression types -------------------------------------
2390 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2391 EXPRESSION : E %prec below_minus {$$ = $1;}
2392 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2394 $$.c = cut_last_push($$.c);
2395 $$.c = code_append($$.c,$3.c);
2398 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2399 $$=cut_last_push($1.c);
2402 // ----------------------- expression evaluation -------------------------------------
2404 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2405 //V : CONSTANT {$$ = 0;}
2407 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2408 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2409 //V : NEW {$$ = $1.c;}
2411 //V : DELETE {$$ = $1.c;}
2412 E : DELETE {$$ = $1;}
2416 namespace_t ns = {ACCESS_PACKAGE, ""};
2417 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2419 $$.c = abc_getlex2($$.c, &m);
2420 $$.c = abc_pushstring($$.c, $1.pattern);
2421 $$.c = abc_construct($$.c, 1);
2423 $$.c = abc_getlex2($$.c, &m);
2424 $$.c = abc_pushstring($$.c, $1.pattern);
2425 $$.c = abc_pushstring($$.c, $1.options);
2426 $$.c = abc_construct($$.c, 2);
2431 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2432 //MULTINAME(m, registry_getintclass());
2433 //$$.c = abc_coerce2($$.c, &m); // FIXME
2436 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2439 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2442 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2445 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2448 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2451 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2454 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2455 $$.t = TYPE_BOOLEAN;
2457 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2458 $$.t = TYPE_BOOLEAN;
2460 CONSTANT : "null" {$$.c = abc_pushnull(0);
2465 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2466 $$.t = TYPE_BOOLEAN;
2468 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2469 $$.t = TYPE_BOOLEAN;
2471 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2472 $$.t = TYPE_BOOLEAN;
2474 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2475 $$.t = TYPE_BOOLEAN;
2477 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2478 $$.t = TYPE_BOOLEAN;
2480 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2481 $$.t = TYPE_BOOLEAN;
2483 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2484 $$.t = TYPE_BOOLEAN;
2486 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2487 $$.t = TYPE_BOOLEAN;
2490 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2492 $$.c = converttype($$.c, $1.t, $$.t);
2493 $$.c = abc_dup($$.c);
2494 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2495 $$.c = cut_last_push($$.c);
2496 $$.c = code_append($$.c,$3.c);
2497 $$.c = converttype($$.c, $3.t, $$.t);
2498 code_t*label = $$.c = abc_label($$.c);
2499 jmp->branch = label;
2502 $$.t = join_types($1.t, $3.t, 'A');
2503 /*printf("%08x:\n",$1.t);
2504 code_dump($1.c, 0, 0, "", stdout);
2505 printf("%08x:\n",$3.t);
2506 code_dump($3.c, 0, 0, "", stdout);
2507 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2509 $$.c = converttype($$.c, $1.t, $$.t);
2510 $$.c = abc_dup($$.c);
2511 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2512 $$.c = cut_last_push($$.c);
2513 $$.c = code_append($$.c,$3.c);
2514 $$.c = converttype($$.c, $3.t, $$.t);
2515 code_t*label = $$.c = abc_label($$.c);
2516 jmp->branch = label;
2519 E : '!' E {$$.c=$2.c;
2520 $$.c = abc_not($$.c);
2521 $$.t = TYPE_BOOLEAN;
2524 E : '~' E {$$.c=$2.c;
2525 $$.c = abc_bitnot($$.c);
2529 E : E '&' E {$$.c = code_append($1.c,$3.c);
2530 $$.c = abc_bitand($$.c);
2534 E : E '^' E {$$.c = code_append($1.c,$3.c);
2535 $$.c = abc_bitxor($$.c);
2539 E : E '|' E {$$.c = code_append($1.c,$3.c);
2540 $$.c = abc_bitor($$.c);
2544 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2545 $$.c = abc_rshift($$.c);
2548 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2549 $$.c = abc_urshift($$.c);
2552 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2553 $$.c = abc_lshift($$.c);
2557 E : E '/' E {$$.c = code_append($1.c,$3.c);
2558 $$.c = abc_divide($$.c);
2561 E : E '%' E {$$.c = code_append($1.c,$3.c);
2562 $$.c = abc_modulo($$.c);
2565 E : E '+' E {$$.c = code_append($1.c,$3.c);
2566 if(BOTH_INT($1.t, $3.t)) {
2567 $$.c = abc_add_i($$.c);
2570 $$.c = abc_add($$.c);
2571 $$.t = join_types($1.t,$3.t,'+');
2574 E : E '-' E {$$.c = code_append($1.c,$3.c);
2575 if(BOTH_INT($1.t,$3.t)) {
2576 $$.c = abc_subtract_i($$.c);
2579 $$.c = abc_subtract($$.c);
2583 E : E '*' E {$$.c = code_append($1.c,$3.c);
2584 if(BOTH_INT($1.t,$3.t)) {
2585 $$.c = abc_multiply_i($$.c);
2588 $$.c = abc_multiply($$.c);
2593 E : E "in" E {$$.c = code_append($1.c,$3.c);
2594 $$.c = abc_in($$.c);
2595 $$.t = TYPE_BOOLEAN;
2598 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2599 if(use_astype && TYPE_IS_CLASS($3.t)) {
2600 MULTINAME(m,$3.t->cls);
2601 $$.c = abc_astype2($1.c, &m);
2604 $$.c = code_append($1.c, $3.c);
2605 $$.c = abc_astypelate($$.c);
2610 E : E "instanceof" E
2611 {$$.c = code_append($1.c, $3.c);
2612 $$.c = abc_instanceof($$.c);
2613 $$.t = TYPE_BOOLEAN;
2616 E : E "is" E {$$.c = code_append($1.c, $3.c);
2617 $$.c = abc_istypelate($$.c);
2618 $$.t = TYPE_BOOLEAN;
2621 E : "typeof" '(' E ')' {
2623 $$.c = abc_typeof($$.c);
2628 $$.c = cut_last_push($2.c);
2629 $$.c = abc_pushundefined($$.c);
2633 E : "void" { $$.c = abc_pushundefined(0);
2637 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2642 $$.c=abc_negate_i($$.c);
2645 $$.c=abc_negate($$.c);
2652 $$.c = code_append($$.c, $3.c);
2654 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2655 $$.c = abc_getproperty2($$.c, &m);
2656 $$.t = 0; // array elements have unknown type
2659 E : '[' MAYBE_EXPRESSION_LIST ']' {
2661 $$.c = code_append($$.c, $2.cc);
2662 $$.c = abc_newarray($$.c, $2.len);
2663 $$.t = registry_getarrayclass();
2666 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2667 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
2669 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2671 $$.cc = code_append($$.cc, $1.c);
2672 $$.cc = code_append($$.cc, $3.c);
2675 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2678 $$.cc = code_append($$.cc, $3.c);
2679 $$.cc = code_append($$.cc, $5.c);
2684 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2686 $$.c = code_append($$.c, $2.cc);
2687 $$.c = abc_newobject($$.c, $2.len/2);
2688 $$.t = registry_getobjectclass();
2693 if(BOTH_INT($1.t,$3.t)) {
2694 c=abc_multiply_i(c);
2698 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2699 $$.c = toreadwrite($1.c, c, 0, 0);
2704 code_t*c = abc_modulo($3.c);
2705 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2706 $$.c = toreadwrite($1.c, c, 0, 0);
2710 code_t*c = abc_lshift($3.c);
2711 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2712 $$.c = toreadwrite($1.c, c, 0, 0);
2716 code_t*c = abc_rshift($3.c);
2717 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2718 $$.c = toreadwrite($1.c, c, 0, 0);
2722 code_t*c = abc_urshift($3.c);
2723 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2724 $$.c = toreadwrite($1.c, c, 0, 0);
2728 code_t*c = abc_divide($3.c);
2729 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2730 $$.c = toreadwrite($1.c, c, 0, 0);
2734 code_t*c = abc_bitor($3.c);
2735 c=converttype(c, TYPE_INT, $1.t);
2736 $$.c = toreadwrite($1.c, c, 0, 0);
2742 if(TYPE_IS_INT($1.t)) {
2746 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2749 $$.c = toreadwrite($1.c, c, 0, 0);
2752 E : E "-=" E { code_t*c = $3.c;
2753 if(TYPE_IS_INT($1.t)) {
2754 c=abc_subtract_i(c);
2757 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2760 $$.c = toreadwrite($1.c, c, 0, 0);
2763 E : E '=' E { code_t*c = 0;
2764 c = code_append(c, $3.c);
2765 c = converttype(c, $3.t, $1.t);
2766 $$.c = toreadwrite($1.c, c, 1, 0);
2770 E : E '?' E ':' E %prec below_assignment {
2771 $$.t = join_types($3.t,$5.t,'?');
2773 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2774 $$.c = code_append($$.c, $3.c);
2775 $$.c = converttype($$.c, $3.t, $$.t);
2776 code_t*j2 = $$.c = abc_jump($$.c, 0);
2777 $$.c = j1->branch = abc_label($$.c);
2778 $$.c = code_append($$.c, $5.c);
2779 $$.c = converttype($$.c, $3.t, $$.t);
2780 $$.c = j2->branch = abc_label($$.c);
2783 E : E "++" { code_t*c = 0;
2784 classinfo_t*type = $1.t;
2785 if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
2786 int nr = getlocalnr($1.c);
2787 code_free($1.c);$1.c=0;
2788 if(TYPE_IS_INT($1.t)) {
2789 $$.c = abc_getlocal(0, nr);
2790 $$.c = abc_inclocal_i($$.c, nr);
2791 } else if(TYPE_IS_NUMBER($1.t)) {
2792 $$.c = abc_getlocal(0, nr);
2793 $$.c = abc_inclocal($$.c, nr);
2794 } else syntaxerror("internal error");
2796 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2797 c=abc_increment_i(c);
2803 c=converttype(c, type, $1.t);
2804 $$.c = toreadwrite($1.c, c, 0, 1);
2809 // TODO: use inclocal, like with ++
2810 E : E "--" { code_t*c = 0;
2811 classinfo_t*type = $1.t;
2812 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2813 c=abc_decrement_i(c);
2819 c=converttype(c, type, $1.t);
2820 $$.c = toreadwrite($1.c, c, 0, 1);
2824 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2825 classinfo_t*type = $2.t;
2826 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2827 c=abc_increment_i(c);
2833 c=converttype(c, type, $2.t);
2834 $$.c = toreadwrite($2.c, c, 0, 0);
2838 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2839 classinfo_t*type = $2.t;
2840 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2841 c=abc_decrement_i(c);
2847 c=converttype(c, type, $2.t);
2848 $$.c = toreadwrite($2.c, c, 0, 0);
2852 E : "super" '.' T_IDENTIFIER
2853 { if(!state->cls->info)
2854 syntaxerror("super keyword not allowed outside a class");
2855 classinfo_t*t = state->cls->info->superclass;
2856 if(!t) t = TYPE_OBJECT;
2858 memberinfo_t*f = registry_findmember(t, $3, 1);
2859 namespace_t ns = flags2namespace(f->flags, "");
2860 MEMBER_MULTINAME(m, f, $3);
2862 $$.c = abc_getlocal_0($$.c);
2863 $$.c = abc_getsuper2($$.c, &m);
2864 $$.t = memberinfo_gettype(f);
2867 E : E '.' T_IDENTIFIER
2869 classinfo_t*t = $1.t;
2871 if(TYPE_IS_CLASS(t) && t->cls) {
2876 memberinfo_t*f = registry_findmember(t, $3, 1);
2878 if(f && !is_static != !(f->flags&FLAG_STATIC))
2880 if(f && f->slot && !noslot) {
2881 $$.c = abc_getslot($$.c, f->slot);
2883 MEMBER_MULTINAME(m, f, $3);
2884 $$.c = abc_getproperty2($$.c, &m);
2886 /* determine type */
2887 $$.t = memberinfo_gettype(f);
2889 $$.c = abc_coerce_a($$.c);
2891 /* when resolving a property on an unknown type, we do know the
2892 name of the property (and don't seem to need the package), but
2893 we need to make avm2 try out all access modes */
2894 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2895 $$.c = abc_getproperty2($$.c, &m);
2896 $$.c = abc_coerce_a($$.c);
2897 $$.t = registry_getanytype();
2901 VAR_READ : T_IDENTIFIER {
2908 /* look at variables */
2909 if((v = find_variable($1))) {
2910 // $1 is a local variable
2911 $$.c = abc_getlocal($$.c, v->index);
2916 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
2918 /* look at current class' members */
2919 if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
2920 (f->flags&FLAG_STATIC) >= i_am_static) {
2921 // $1 is a function in this class
2922 int var_is_static = (f->flags&FLAG_STATIC);
2924 if(f->kind == MEMBER_METHOD) {
2925 $$.t = TYPE_FUNCTION(f);
2929 if(var_is_static && !i_am_static) {
2930 /* access to a static member from a non-static location.
2931 do this via findpropstrict:
2932 there doesn't seem to be any non-lookup way to access
2933 static properties of a class */
2934 state->method->late_binding = 1;
2936 namespace_t ns = {flags2access(f->flags), ""};
2937 multiname_t m = {QNAME, &ns, 0, $1};
2938 $$.c = abc_findpropstrict2($$.c, &m);
2939 $$.c = abc_getproperty2($$.c, &m);
2941 } else if(f->slot>0) {
2942 $$.c = abc_getlocal_0($$.c);
2943 $$.c = abc_getslot($$.c, f->slot);
2946 namespace_t ns = {flags2access(f->flags), ""};
2947 multiname_t m = {QNAME, &ns, 0, $1};
2948 $$.c = abc_getlocal_0($$.c);
2949 $$.c = abc_getproperty2($$.c, &m);
2954 /* look at actual classes, in the current package and imported */
2955 if((a = find_class($1))) {
2956 if(a->flags & FLAG_METHOD) {
2958 $$.c = abc_findpropstrict2($$.c, &m);
2959 $$.c = abc_getproperty2($$.c, &m);
2960 if(a->function->kind == MEMBER_METHOD) {
2961 $$.t = TYPE_FUNCTION(a->function);
2963 $$.t = a->function->type;
2967 $$.c = abc_getglobalscope($$.c);
2968 $$.c = abc_getslot($$.c, a->slot);
2971 $$.c = abc_getlex2($$.c, &m);
2973 $$.t = TYPE_CLASS(a);
2978 /* unknown object, let the avm2 resolve it */
2980 if(strcmp($1,"trace"))
2981 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
2982 state->method->late_binding = 1;
2984 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2987 $$.c = abc_findpropstrict2($$.c, &m);
2988 $$.c = abc_getproperty2($$.c, &m);
2993 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2994 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2995 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2997 // ----------------- namespaces -------------------------------------------------
2999 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
3000 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
3001 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
3003 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}