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 {
305 abc_exception_list_t*exceptions;
308 typedef struct _state {
313 import_list_t*wildcard_imports;
315 char has_own_imports;
318 methodstate_t*method;
325 typedef struct _global {
332 static global_t*global = 0;
333 static state_t* state = 0;
337 #define MULTINAME(m,x) \
340 registry_fill_multiname(&m, &m##_ns, x);
342 #define MEMBER_MULTINAME(m,f,n) \
346 m##_ns = flags2namespace(f->flags, ""); \
349 m.namespace_set = 0; \
352 m.type = MULTINAME; \
354 m.namespace_set = &nopackage_namespace_set; \
358 /* warning: list length of namespace set is undefined */
359 #define MULTINAME_LATE(m, access, package) \
360 namespace_t m##_ns = {access, package}; \
361 namespace_set_t m##_nsset; \
362 namespace_list_t m##_l;m##_l.next = 0; \
363 m##_nsset.namespaces = &m##_l; \
364 m##_nsset = m##_nsset; \
365 m##_l.namespace = &m##_ns; \
366 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
368 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
369 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
370 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
371 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
372 static namespace_list_t nl4 = {&ns4,0};
373 static namespace_list_t nl3 = {&ns3,&nl4};
374 static namespace_list_t nl2 = {&ns2,&nl3};
375 static namespace_list_t nl1 = {&ns1,&nl2};
376 static namespace_set_t nopackage_namespace_set = {&nl1};
378 static void new_state()
381 state_t*oldstate = state;
383 memcpy(s, state, sizeof(state_t)); //shallow copy
385 s->imports = dict_new();
389 state->has_own_imports = 0;
390 state->vars = dict_new();
391 state->old = oldstate;
393 static void state_has_imports()
395 state->wildcard_imports = list_clone(state->wildcard_imports);
396 state->imports = dict_clone(state->imports);
397 state->has_own_imports = 1;
400 static void state_destroy(state_t*state)
402 if(state->has_own_imports) {
403 list_free(state->wildcard_imports);
404 dict_destroy(state->imports);state->imports=0;
406 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
407 dict_destroy(state->imports);state->imports=0;
411 for(t=0;t<state->vars->hashsize;t++) {
412 dictentry_t*e =state->vars->slots[t];
414 free(e->data);e->data=0;
418 dict_destroy(state->vars);state->vars=0;
424 static void old_state()
426 if(!state || !state->old)
427 syntaxerror("invalid nesting");
428 state_t*leaving = state;
432 if(leaving->method && leaving->method != state->method) {
433 free(leaving->method);
436 if(leaving->cls && leaving->cls != state->cls) {
441 state_destroy(leaving);
444 void initialize_parser()
446 global = rfx_calloc(sizeof(global_t));
447 global->file = abc_file_new();
448 global->file->flags &= ~ABCFILE_LAZY;
449 global->variable_count = 1;
450 global->init = abc_initscript(global->file);
451 code_t*c = global->init->method->body->code;
452 c = abc_getlocal_0(c);
453 c = abc_pushscope(c);
454 /*c = abc_findpropstrict(c, "[package]::trace");
455 c = abc_pushstring(c, "[entering global init function]");
456 c = abc_callpropvoid(c, "[package]::trace", 1);*/
457 global->init->method->body->code = c;
460 void initialize_file(char*filename)
463 state->package = filename;
464 // needed for state->method->late_binding:
465 state->method = rfx_calloc(sizeof(methodstate_t));
469 if(!state || state->level!=1) {
470 syntaxerror("unexpected end of file");
472 state_destroy(state);state=0;
475 void* finish_parser()
477 code_t*c = global->init->method->body->code;
478 /*c = abc_findpropstrict(c, "[package]::trace");
479 c = abc_pushstring(c, "[leaving global init function]");
480 c = abc_callpropvoid(c, "[package]::trace", 1);*/
481 c = abc_returnvoid(c);
482 global->init->method->body->code = c;
487 static void xx_scopetest()
489 /* findpropstrict doesn't just return a scope object- it
490 also makes it "active" somehow. Push local_0 on the
491 scope stack and read it back with findpropstrict, it'll
492 contain properties like "trace". Trying to find the same
493 property on a "vanilla" local_0 yields only a "undefined" */
494 //c = abc_findpropstrict(c, "[package]::trace");
496 /*c = abc_getlocal_0(c);
497 c = abc_findpropstrict(c, "[package]::trace");
499 c = abc_setlocal_1(c);
501 c = abc_pushbyte(c, 0);
502 c = abc_setlocal_2(c);
504 code_t*xx = c = abc_label(c);
505 c = abc_findpropstrict(c, "[package]::trace");
506 c = abc_pushstring(c, "prop:");
507 c = abc_hasnext2(c, 1, 2);
509 c = abc_setlocal_3(c);
510 c = abc_callpropvoid(c, "[package]::trace", 2);
511 c = abc_getlocal_3(c);
513 c = abc_iftrue(c,xx);*/
517 typedef struct _variable {
523 static variable_t* find_variable(char*name)
529 v = dict_lookup(s->vars, name);
537 static variable_t* find_variable_safe(char*name)
539 variable_t* v = find_variable(name);
541 syntaxerror("undefined variable: %s", name);
544 static char variable_exists(char*name)
546 return dict_lookup(state->vars, name)!=0;
548 code_t*defaultvalue(code_t*c, classinfo_t*type);
549 static int new_variable(char*name, classinfo_t*type, char init)
552 v->index = global->variable_count;
556 dict_put(state->vars, name, v);
558 return global->variable_count++;
560 #define TEMPVARNAME "__as3_temp__"
561 static int gettempvar()
563 variable_t*v = find_variable(TEMPVARNAME);
566 return new_variable(TEMPVARNAME, 0, 0);
569 code_t* var_block(code_t*body)
575 for(t=0;t<state->vars->hashsize;t++) {
576 dictentry_t*e = state->vars->slots[t];
578 variable_t*v = (variable_t*)e->data;
579 if(v->type && v->init) {
580 c = defaultvalue(c, v->type);
581 c = abc_setlocal(c, v->index);
582 k = abc_kill(k, v->index);
592 if(x->opcode== OPCODE___BREAK__ ||
593 x->opcode== OPCODE___CONTINUE__) {
594 /* link kill code before break/continue */
595 code_t*e = code_dup(k);
596 code_t*s = code_start(e);
608 c = code_append(c, body);
609 c = code_append(c, k);
613 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
615 c = code_append(c, header);
616 c = code_append(c, var_block(body));
617 /* append return if necessary */
618 if(!c || (c->opcode != OPCODE_RETURNVOID &&
619 c->opcode != OPCODE_RETURNVALUE)) {
620 c = abc_returnvoid(c);
626 static void startpackage(char*name)
629 /*printf("entering package \"%s\"\n", name);*/
630 state->package = strdup(name);
631 global->variable_count = 1;
633 static void endpackage()
635 /*printf("leaving package \"%s\"\n", state->package);*/
637 //used e.g. in classinfo_register:
638 //free(state->package);state->package=0;
643 void parserassert(int b)
645 if(!b) syntaxerror("internal error: assertion failed");
649 char*as3_globalclass=0;
650 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
653 syntaxerror("inner classes now allowed");
656 global->variable_count = 1;
657 state->cls = rfx_calloc(sizeof(classstate_t));
658 state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
661 classinfo_list_t*mlist=0;
663 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
664 syntaxerror("invalid modifier(s)");
666 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
667 syntaxerror("public and internal not supported at the same time.");
669 /* create the class name, together with the proper attributes */
673 if(!(flags&FLAG_PUBLIC) && !state->package) {
674 access = ACCESS_PRIVATE; package = current_filename;
675 } else if(!(flags&FLAG_PUBLIC) && state->package) {
676 access = ACCESS_PACKAGEINTERNAL; package = state->package;
677 } else if(state->package) {
678 access = ACCESS_PACKAGE; package = state->package;
680 syntaxerror("public classes only allowed inside a package");
684 if(registry_findclass(package, classname)) {
685 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
687 /* build info struct */
688 int num_interfaces = (list_length(implements));
689 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
693 state->cls->info = registry_findclass(package, classname);
694 parserassert((int)state->cls->info);
696 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
697 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
699 classinfo_list_t*l = implements;
700 for(l=implements;l;l=l->next) {
701 state->cls->info->interfaces[pos++] = l->classinfo;
704 /* generate the abc code for this class */
705 MULTINAME(classname2,state->cls->info);
706 multiname_t*extends2 = sig2mname(extends);
708 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
709 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
710 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
712 state->cls->info->flags |= CLASS_INTERFACE;
713 abc_class_interface(state->cls->abc);
716 abc_class_protectedNS(state->cls->abc, classname);
718 for(mlist=implements;mlist;mlist=mlist->next) {
719 MULTINAME(m, mlist->classinfo);
720 abc_class_add_interface(state->cls->abc, &m);
723 /* write the construction code for this class to the global init
725 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
727 abc_method_body_t*m = global->init->method->body;
728 __ getglobalscope(m);
729 classinfo_t*s = extends;
734 //TODO: take a look at the current scope stack, maybe
735 // we can re-use something
740 multiname_t*s2 = sig2mname(s);
742 multiname_destroy(s2);
744 __ pushscope(m); count++;
745 m->code = m->code->prev->prev; // invert
747 /* continue appending after last op end */
748 while(m->code && m->code->next) m->code = m->code->next;
750 /* TODO: if this is one of *our* classes, we can also
751 do a getglobalscope/getslot <nr> (which references
752 the init function's slots) */
754 __ getlex2(m, extends2);
756 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
757 stack is not the superclass */
758 __ pushscope(m);count++;
761 /* notice: we get a verify error #1107 if the top element on the scope
762 stack is not the global object */
764 __ pushscope(m);count++;
766 __ newclass(m,state->cls->abc);
770 __ setslot(m, slotindex);
771 multiname_destroy(extends2);
773 /* flash.display.MovieClip handling */
775 if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
776 if(state->package && state->package[0]) {
777 as3_globalclass = concat3(state->package, ".", classname);
779 as3_globalclass = strdup(classname);
785 static void endclass()
788 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
790 c = abc_getlocal_0(c);
791 c = abc_constructsuper(c, 0);
792 state->cls->init = code_append(state->cls->init, c);
794 if(!state->method->late_binding) {
795 // class initialization code uses late binding
797 c = abc_getlocal_0(c);
798 c = abc_pushscope(c);
799 state->cls->static_init = code_append(c, state->cls->static_init);
802 if(state->cls->init) {
803 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
804 m->body->code = wrap_function(0, state->cls->init, m->body->code);
806 if(state->cls->static_init) {
807 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
808 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
815 void check_code_for_break(code_t*c)
818 if(c->opcode == OPCODE___BREAK__) {
819 char*name = string_cstr(c->data[0]);
820 syntaxerror("Unresolved \"break %s\"", name);
822 if(c->opcode == OPCODE___CONTINUE__) {
823 char*name = string_cstr(c->data[0]);
824 syntaxerror("Unresolved \"continue %s\"", name);
831 static void check_constant_against_type(classinfo_t*t, constant_t*c)
833 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
834 if(TYPE_IS_NUMBER(t)) {
835 xassert(c->type == CONSTANT_FLOAT
836 || c->type == CONSTANT_INT
837 || c->type == CONSTANT_UINT);
838 } else if(TYPE_IS_UINT(t)) {
839 xassert(c->type == CONSTANT_UINT ||
840 (c->type == CONSTANT_INT && c->i>0));
841 } else if(TYPE_IS_INT(t)) {
842 xassert(c->type == CONSTANT_INT);
843 } else if(TYPE_IS_BOOLEAN(t)) {
844 xassert(c->type == CONSTANT_TRUE
845 || c->type == CONSTANT_FALSE);
850 static int flags2access(int flags)
853 if(flags&FLAG_PUBLIC) {
854 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
855 syntaxerror("invalid combination of access levels");
856 access = ACCESS_PACKAGE;
857 } else if(flags&FLAG_PRIVATE) {
858 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
859 syntaxerror("invalid combination of access levels");
860 access = ACCESS_PRIVATE;
861 } else if(flags&FLAG_PROTECTED) {
862 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
863 syntaxerror("invalid combination of access levels");
864 access = ACCESS_PROTECTED;
866 access = ACCESS_PACKAGEINTERNAL;
872 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
874 memberinfo_t*minfo = 0;
877 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
878 minfo->return_type = return_type;
879 } else if(getset != KW_GET && getset != KW_SET) {
881 if((minfo = registry_findmember(state->cls->info, name, 0))) {
882 if(minfo->parent == state->cls->info) {
883 syntaxerror("class already contains a member/method called '%s'", name);
884 } else if(!minfo->parent) {
885 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
887 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
888 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
891 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
892 minfo->return_type = return_type;
893 // getslot on a member slot only returns "undefined", so no need
894 // to actually store these
895 //state->minfo->slot = state->method->abc->method->trait->slot_id;
897 //class getter/setter
898 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
902 else if(params->list)
903 type = params->list->param->type;
904 // not sure wether to look into superclasses here, too
905 if((minfo=registry_findmember(state->cls->info, name, 0))) {
906 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
907 syntaxerror("class already contains a member or method called '%s'", name);
909 syntaxerror("getter/setter for '%s' already defined", name);
910 /* make a setter or getter into a getset */
915 if(type && minfo->type != type)
916 syntaxerror("different type in getter and setter");
918 minfo = memberinfo_register(state->cls->info, name, gs);
921 /* can't assign a slot as getter and setter might have different slots */
922 //minfo->slot = slot;
924 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
925 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
926 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
927 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
928 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
929 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
933 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
935 parserassert(state->method && state->method->info);
936 memberinfo_t*parent_method = state->method->info;
945 state->method = rfx_calloc(sizeof(methodstate_t));
946 state->method->inner = 1;
948 NEW(memberinfo_t,minfo);
949 minfo->return_type = return_type;
952 if(!parent_method->subfunctions)
953 parent_method->subfunctions = dict_new();
955 dict_put(parent_method->subfunctions, name, minfo);
956 state->method->info = minfo;
959 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
960 params_t*params, classinfo_t*return_type)
962 if(state->method && state->method->info) {
963 syntaxerror("not able to start another method scope");
966 state->method = rfx_calloc(sizeof(methodstate_t));
967 state->method->has_super = 0;
970 state->method->is_constructor = !strcmp(state->cls->info->name,name);
971 state->cls->has_constructor |= state->method->is_constructor;
973 state->method->is_global = 1;
974 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
976 if(state->method->is_constructor)
977 name = "__as3_constructor__";
981 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
985 /* retrieve the member info that we stored in the first pass.
986 TODO: better getter/setter support? */
987 if(!state->cls) state->method->info = registry_findclass(state->package, name)->function;
988 else state->method->info = registry_findmember(state->cls->info, name, 0);
989 state->method->info->return_type = return_type;
991 global->variable_count = 0;
992 /* state->vars is initialized by state_new */
993 if(!state->method->is_global)
994 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
996 new_variable("globalscope", 0, 0);
998 for(p=params->list;p;p=p->next) {
999 new_variable(p->param->name, p->param->type, 0);
1004 static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
1005 params_t*params, classinfo_t*return_type, code_t*body)
1014 multiname_t*type2 = sig2mname(return_type);
1016 if(state->method->inner) {
1017 f = abc_method_new(global->file, type2, 1);
1018 } else if(state->method->is_constructor) {
1019 f = abc_class_getconstructor(state->cls->abc, type2);
1020 } else if(!state->method->is_global) {
1021 namespace_t mname_ns = flags2namespace(flags, "");
1022 multiname_t mname = {QNAME, &mname_ns, 0, name};
1024 if(flags&FLAG_STATIC)
1025 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1027 f = abc_class_method(state->cls->abc, type2, &mname);
1028 slot = f->trait->slot_id;
1030 namespace_t mname_ns = flags2namespace(flags, state->package);
1031 multiname_t mname = {QNAME, &mname_ns, 0, name};
1033 f = abc_method_new(global->file, type2, 1);
1034 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1035 //abc_code_t*c = global->init->method->body->code;
1037 //flash doesn't seem to allow us to access function slots
1038 //state->method->info->slot = slot;
1040 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1041 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1042 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1043 if(params->varargs) f->flags |= METHOD_NEED_REST;
1047 for(p=params->list;p;p=p->next) {
1048 if(params->varargs && !p->next) {
1049 break; //varargs: omit last parameter in function signature
1051 multiname_t*m = sig2mname(p->param->type);
1052 list_append(f->parameters, m);
1053 if(p->param->value) {
1054 check_constant_against_type(p->param->type, p->param->value);
1055 opt=1;list_append(f->optional_parameters, p->param->value);
1057 syntaxerror("non-optional parameter not allowed after optional parameters");
1060 check_code_for_break(body);
1063 f->body->code = body;
1064 f->body->exceptions = state->method->exceptions;
1065 } else { //interface
1067 syntaxerror("interface methods can't have a method body");
1074 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1079 void breakjumpsto(code_t*c, char*name, code_t*jump)
1082 if(c->opcode == OPCODE___BREAK__) {
1083 string_t*name2 = c->data[0];
1084 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1085 c->opcode = OPCODE_JUMP;
1092 void continuejumpsto(code_t*c, char*name, code_t*jump)
1095 if(c->opcode == OPCODE___CONTINUE__) {
1096 string_t*name2 = c->data[0];
1097 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1098 c->opcode = OPCODE_JUMP;
1106 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1107 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1108 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1110 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1112 if(!type1 || !type2)
1113 return registry_getanytype();
1114 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1115 return registry_getanytype();
1118 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1127 return registry_getanytype();
1129 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1134 return abc_coerce_a(c);
1138 // cast an "any" type to a specific type. subject to
1139 // runtime exceptions
1140 return abc_coerce2(c, &m);
1143 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1144 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1145 // allow conversion between number types
1146 return abc_coerce2(c, &m);
1148 //printf("%s.%s\n", from.package, from.name);
1149 //printf("%s.%s\n", to.package, to.name);
1151 classinfo_t*supertype = from;
1153 if(supertype == to) {
1154 // target type is one of from's superclasses
1155 return abc_coerce2(c, &m);
1158 while(supertype->interfaces[t]) {
1159 if(supertype->interfaces[t]==to) {
1160 // target type is one of from's interfaces
1161 return abc_coerce2(c, &m);
1165 supertype = supertype->superclass;
1167 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1169 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1171 syntaxerror("can't convert type %s to %s", from->name, to->name);
1172 return 0; // make gcc happy
1175 code_t*defaultvalue(code_t*c, classinfo_t*type)
1177 if(TYPE_IS_INT(type)) {
1178 c = abc_pushbyte(c, 0);
1179 } else if(TYPE_IS_UINT(type)) {
1180 c = abc_pushuint(c, 0);
1181 } else if(TYPE_IS_FLOAT(type)) {
1183 } else if(TYPE_IS_BOOLEAN(type)) {
1184 c = abc_pushfalse(c);
1186 //c = abc_pushundefined(c);
1188 c = abc_pushnull(c);
1190 c = abc_coerce2(c, &m);
1195 char is_pushundefined(code_t*c)
1197 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1200 static classinfo_t* find_class(char*name)
1204 c = registry_findclass(state->package, name);
1207 /* try explicit imports */
1208 dictentry_t* e = dict_get_slot(state->imports, name);
1211 if(!strcmp(e->key, name)) {
1212 c = (classinfo_t*)e->data;
1218 /* try package.* imports */
1219 import_list_t*l = state->wildcard_imports;
1221 //printf("does package %s contain a class %s?\n", l->import->package, name);
1222 c = registry_findclass(l->import->package, name);
1227 /* try global package */
1228 c = registry_findclass("", name);
1231 /* try local "filename" package */
1232 c = registry_findclass(current_filename_short, name);
1238 static char is_getlocal(code_t*c)
1240 if(!c || c->prev || c->next)
1242 return(c->opcode == OPCODE_GETLOCAL
1243 || c->opcode == OPCODE_GETLOCAL_0
1244 || c->opcode == OPCODE_GETLOCAL_1
1245 || c->opcode == OPCODE_GETLOCAL_2
1246 || c->opcode == OPCODE_GETLOCAL_3);
1248 static int getlocalnr(code_t*c)
1250 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1251 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1252 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1253 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1254 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1255 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1259 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1263 [prefix code] [read instruction]
1267 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1270 if(in && in->opcode == OPCODE_COERCE_A) {
1271 in = code_cutlast(in);
1274 syntaxerror("internal error");
1276 /* chop off read instruction */
1280 prefix = r->prev;r->prev = 0;
1286 char use_temp_var = readbefore;
1288 /* generate the write instruction, and maybe append a dup to the prefix code */
1289 code_t* write = abc_nop(0);
1290 if(r->opcode == OPCODE_GETPROPERTY) {
1291 write->opcode = OPCODE_SETPROPERTY;
1292 multiname_t*m = (multiname_t*)r->data[0];
1293 write->data[0] = multiname_clone(m);
1294 if(m->type == QNAME || m->type == MULTINAME) {
1296 prefix = abc_dup(prefix); // we need the object, too
1299 } else if(m->type == MULTINAMEL) {
1301 /* dupping two values on the stack requires 5 operations and one register-
1302 couldn't adobe just have given us a dup2? */
1303 int temp = gettempvar();
1304 prefix = abc_setlocal(prefix, temp);
1305 prefix = abc_dup(prefix);
1306 prefix = abc_getlocal(prefix, temp);
1307 prefix = abc_swap(prefix);
1308 prefix = abc_getlocal(prefix, temp);
1310 prefix = abc_kill(prefix, temp);
1314 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1316 } else if(r->opcode == OPCODE_GETSLOT) {
1317 write->opcode = OPCODE_SETSLOT;
1318 write->data[0] = r->data[0];
1320 prefix = abc_dup(prefix); // we need the object, too
1323 } else if(r->opcode == OPCODE_GETLOCAL) {
1324 write->opcode = OPCODE_SETLOCAL;
1325 write->data[0] = r->data[0];
1326 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1327 write->opcode = OPCODE_SETLOCAL_0;
1328 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1329 write->opcode = OPCODE_SETLOCAL_1;
1330 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1331 write->opcode = OPCODE_SETLOCAL_2;
1332 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1333 write->opcode = OPCODE_SETLOCAL_3;
1336 syntaxerror("illegal lvalue: can't assign a value to this expression");
1343 /* with getproperty/getslot, we have to be extra careful not
1344 to execute the read code twice, as it might have side-effects
1345 (e.g. if the property is in fact a setter/getter combination)
1347 So read the value, modify it, and write it again,
1348 using prefix only once and making sure (by using a temporary
1349 register) that the return value is what we just wrote */
1350 temp = gettempvar();
1351 c = code_append(c, prefix);
1352 c = code_append(c, r);
1355 c = abc_setlocal(c, temp);
1357 c = code_append(c, middlepart);
1360 c = abc_setlocal(c, temp);
1362 c = code_append(c, write);
1363 c = abc_getlocal(c, temp);
1364 c = abc_kill(c, temp);
1366 /* if we're allowed to execute the read code twice *and*
1367 the middlepart doesn't modify the code, things are easier.
1369 code_t* r2 = code_dup(r);
1370 //c = code_append(c, prefix);
1371 parserassert(!prefix);
1372 c = code_append(c, r);
1373 c = code_append(c, middlepart);
1374 c = code_append(c, write);
1375 c = code_append(c, r2);
1378 /* even smaller version: overwrite the value without reading
1382 c = code_append(c, prefix);
1385 c = code_append(c, middlepart);
1386 c = code_append(c, write);
1387 c = code_append(c, r);
1389 temp = gettempvar();
1391 c = code_append(c, prefix);
1393 c = code_append(c, middlepart);
1395 c = abc_setlocal(c, temp);
1396 c = code_append(c, write);
1397 c = abc_getlocal(c, temp);
1398 c = abc_kill(c, temp);
1404 char is_break_or_jump(code_t*c)
1408 if(c->opcode == OPCODE_JUMP ||
1409 c->opcode == OPCODE___BREAK__ ||
1410 c->opcode == OPCODE___CONTINUE__ ||
1411 c->opcode == OPCODE_THROW ||
1412 c->opcode == OPCODE_RETURNVOID ||
1413 c->opcode == OPCODE_RETURNVALUE) {
1420 #define IS_FINALLY_TARGET(op) \
1421 ((op) == OPCODE___CONTINUE__ || \
1422 (op) == OPCODE___BREAK__ || \
1423 (op) == OPCODE_RETURNVOID || \
1424 (op) == OPCODE_RETURNVALUE || \
1425 (op) == OPCODE___RETHROW__)
1427 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1429 #define NEED_EXTRA_STACK_ARG
1430 code_t*finally_label = abc_nop(0);
1431 NEW(lookupswitch_t, l);
1437 code_t*prev = i->prev;
1438 if(IS_FINALLY_TARGET(i->opcode)) {
1441 if(i->opcode == OPCODE___RETHROW__ ||
1442 i->opcode == OPCODE_RETURNVALUE) {
1443 if(i->opcode == OPCODE___RETHROW__)
1444 i->opcode = OPCODE_THROW;
1446 p = abc_coerce_a(p);
1447 p = abc_setlocal(p, tempvar);
1449 p = abc_pushbyte(p, count++);
1450 p = abc_jump(p, finally_label);
1451 code_t*target = p = abc_label(p);
1452 #ifdef NEED_EXTRA_STACK_ARG
1456 p = abc_getlocal(p, tempvar);
1459 p->next = i;i->prev = p;
1460 list_append(l->targets, target);
1466 c = abc_pushbyte(c, -1);
1467 c = code_append(c, finally_label);
1468 c = code_append(c, finally);
1470 #ifdef NEED_EXTRA_STACK_ARG
1473 c = abc_lookupswitch(c, l);
1474 c = l->def = abc_label(c);
1475 #ifdef NEED_EXTRA_STACK_ARG
1482 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1486 code_t*prev = i->prev;
1487 if(IS_FINALLY_TARGET(i->opcode)) {
1488 if(i->opcode == OPCODE___RETHROW__)
1489 i->opcode = OPCODE_THROW;
1490 code_t*end = code_dup(finally);
1491 code_t*start = code_start(end);
1492 if(prev) prev->next = start;
1499 return code_append(c, finally);
1502 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1508 int num_insertion_points=0;
1510 if(IS_FINALLY_TARGET(i->opcode))
1511 num_insertion_points++;
1518 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1523 int simple_version_cost = (1+num_insertion_points)*code_size;
1524 int lookup_version_cost = 4*num_insertion_points + 5;
1526 if(cantdup || simple_version_cost > lookup_version_cost) {
1527 printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
1528 return insert_finally_lookup(c, finally, tempvar);
1530 printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
1531 return insert_finally_simple(c, finally, tempvar);
1535 #define PASS1 }} if(as3_pass == 1) {{
1536 #define PASS1END }} if(as3_pass == 2) {{
1537 #define PASS2 }} if(as3_pass == 2) {{
1538 #define PASS12 }} {{
1539 #define PASS12END }} if(as3_pass == 2) {{
1545 /* ------------ code blocks / statements ---------------- */
1547 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1549 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1550 PROGRAM_CODE_LIST: PROGRAM_CODE
1551 | PROGRAM_CODE_LIST PROGRAM_CODE
1553 PROGRAM_CODE: PACKAGE_DECLARATION
1554 | INTERFACE_DECLARATION
1556 | FUNCTION_DECLARATION
1561 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1562 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1563 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1565 INPACKAGE_CODE: INTERFACE_DECLARATION
1567 | FUNCTION_DECLARATION
1572 MAYBECODE: CODE {$$=$1;}
1573 MAYBECODE: {$$=code_new();}
1575 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1576 CODE: CODEPIECE {$$=$1;}
1578 // code which also may appear outside a method
1579 CODE_STATEMENT: IMPORT
1581 CODE_STATEMENT: FOR_IN
1582 CODE_STATEMENT: WHILE
1583 CODE_STATEMENT: DO_WHILE
1584 CODE_STATEMENT: SWITCH
1586 CODE_STATEMENT: WITH
1588 CODE_STATEMENT: VOIDEXPRESSION
1590 // code which may appear anywhere
1591 CODEPIECE: ';' {$$=0;}
1592 CODEPIECE: CODE_STATEMENT
1593 CODEPIECE: VARIABLE_DECLARATION
1599 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1600 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1602 CODEBLOCK : '{' CODE '}' {$$=$2;}
1603 CODEBLOCK : '{' '}' {$$=0;}
1604 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1605 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1607 /* ------------ package init code ------------------- */
1609 PACKAGE_INITCODE: CODE_STATEMENT {
1610 code_t**cc = &global->init->method->body->code;
1611 *cc = code_append(*cc, $1);
1614 /* ------------ variables --------------------------- */
1616 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1617 | {$$.c=abc_pushundefined(0);
1621 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1622 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1624 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1625 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1627 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1629 if(variable_exists($1))
1630 syntaxerror("Variable %s already defined", $1);
1632 if(!is_subtype_of($3.t, $2)) {
1633 syntaxerror("Can't convert %s to %s", $3.t->name,
1637 int index = new_variable($1, $2, 1);
1640 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1642 $$ = converttype($$, $3.t, $2);
1643 $$ = abc_setlocal($$, index);
1645 $$ = defaultvalue(0, $2);
1646 $$ = abc_setlocal($$, index);
1649 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1651 $$ = abc_coerce_a($$);
1652 $$ = abc_setlocal($$, index);
1658 /* that's the default for a local register, anyway
1660 state->method->initcode = abc_pushundefined(state->method->initcode);
1661 state->method->initcode = abc_setlocal(state->method->initcode, index);
1663 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1666 /* ------------ control flow ------------------------- */
1668 MAYBEELSE: %prec below_else {$$ = code_new();}
1669 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1670 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1672 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1675 $$ = code_append($$, $4.c);
1676 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1678 $$ = code_append($$, $6);
1680 myjmp = $$ = abc_jump($$, 0);
1682 myif->branch = $$ = abc_nop($$);
1684 $$ = code_append($$, $7);
1685 myjmp->branch = $$ = abc_nop($$);
1691 FOR_INIT : {$$=code_new();}
1692 FOR_INIT : VARIABLE_DECLARATION
1693 FOR_INIT : VOIDEXPRESSION
1695 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1696 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1697 $$=$2;new_variable($2,$3,1);
1699 FOR_IN_INIT : T_IDENTIFIER {
1703 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1704 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1706 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1707 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1709 $$ = code_append($$, $2);
1710 code_t*loopstart = $$ = abc_label($$);
1711 $$ = code_append($$, $4.c);
1712 code_t*myif = $$ = abc_iffalse($$, 0);
1713 $$ = code_append($$, $8);
1714 code_t*cont = $$ = abc_nop($$);
1715 $$ = code_append($$, $6);
1716 $$ = abc_jump($$, loopstart);
1717 code_t*out = $$ = abc_nop($$);
1718 breakjumpsto($$, $1.name, out);
1719 continuejumpsto($$, $1.name, cont);
1726 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1727 variable_t*var = find_variable($2);
1728 char*tmp1name = concat2($2, "__tmp1__");
1729 int it = new_variable(tmp1name, TYPE_INT, 0);
1730 char*tmp2name = concat2($2, "__array__");
1731 int array = new_variable(tmp1name, 0, 0);
1734 $$ = code_append($$, $4.c);
1735 $$ = abc_coerce_a($$);
1736 $$ = abc_setlocal($$, array);
1737 $$ = abc_pushbyte($$, 0);
1738 $$ = abc_setlocal($$, it);
1740 code_t*loopstart = $$ = abc_label($$);
1742 $$ = abc_hasnext2($$, array, it);
1743 code_t*myif = $$ = abc_iffalse($$, 0);
1744 $$ = abc_getlocal($$, array);
1745 $$ = abc_getlocal($$, it);
1747 $$ = abc_nextname($$);
1749 $$ = abc_nextvalue($$);
1750 $$ = converttype($$, 0, var->type);
1751 $$ = abc_setlocal($$, var->index);
1753 $$ = code_append($$, $6);
1754 $$ = abc_jump($$, loopstart);
1756 code_t*out = $$ = abc_nop($$);
1757 breakjumpsto($$, $1.name, out);
1758 continuejumpsto($$, $1.name, loopstart);
1769 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1773 code_t*myjmp = $$ = abc_jump($$, 0);
1774 code_t*loopstart = $$ = abc_label($$);
1775 $$ = code_append($$, $6);
1776 code_t*cont = $$ = abc_nop($$);
1777 myjmp->branch = cont;
1778 $$ = code_append($$, $4.c);
1779 $$ = abc_iftrue($$, loopstart);
1780 code_t*out = $$ = abc_nop($$);
1781 breakjumpsto($$, $1, out);
1782 continuejumpsto($$, $1, cont);
1788 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1790 code_t*loopstart = $$ = abc_label($$);
1791 $$ = code_append($$, $3);
1792 code_t*cont = $$ = abc_nop($$);
1793 $$ = code_append($$, $6.c);
1794 $$ = abc_iftrue($$, loopstart);
1795 code_t*out = $$ = abc_nop($$);
1796 breakjumpsto($$, $1, out);
1797 continuejumpsto($$, $1, cont);
1803 BREAK : "break" %prec prec_none {
1804 $$ = abc___break__(0, "");
1806 BREAK : "break" T_IDENTIFIER {
1807 $$ = abc___break__(0, $2);
1809 CONTINUE : "continue" %prec prec_none {
1810 $$ = abc___continue__(0, "");
1812 CONTINUE : "continue" T_IDENTIFIER {
1813 $$ = abc___continue__(0, $2);
1816 MAYBE_CASE_LIST : {$$=0;}
1817 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1818 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1819 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1820 CASE_LIST: CASE {$$=$1;}
1821 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1823 CASE: "case" E ':' MAYBECODE {
1825 $$ = code_append($$, $2.c);
1826 code_t*j = $$ = abc_ifne($$, 0);
1827 $$ = code_append($$, $4);
1828 if($$->opcode != OPCODE___BREAK__) {
1829 $$ = abc___fallthrough__($$, "");
1831 code_t*e = $$ = abc_nop($$);
1834 DEFAULT: "default" ':' MAYBECODE {
1837 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1839 $$ = code_append($$, $7);
1840 code_t*out = $$ = abc_pop($$);
1841 breakjumpsto($$, $1, out);
1843 code_t*c = $$,*lastblock=0;
1845 if(c->opcode == OPCODE_IFNE) {
1846 if(!c->next) syntaxerror("internal error in fallthrough handling");
1848 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1850 c->opcode = OPCODE_JUMP;
1851 c->branch = lastblock;
1853 /* fall through end of switch */
1854 c->opcode = OPCODE_NOP;
1864 /* ------------ try / catch /finally ---------------- */
1866 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1868 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1869 multiname_t name = {QNAME, &name_ns, 0, $3};
1871 NEW(abc_exception_t, e)
1872 e->exc_type = sig2mname($4);
1873 e->var_name = multiname_clone(&name);
1877 int i = find_variable_safe($3)->index;
1878 e->target = c = abc_nop(0);
1879 c = abc_setlocal(c, i);
1880 c = code_append(c, $8);
1886 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
1892 NEW(abc_exception_t, e)
1893 e->exc_type = 0; //all exceptions
1894 e->var_name = 0; //no name
1897 e->to = code_append(e->to, $4);
1903 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
1904 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
1905 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
1906 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
1910 list_append($$.l,$2);
1911 $$.finally = $2->to;$2->to=0;
1914 CATCH_FINALLY_LIST: FINALLY {
1918 list_append($$.l,$1);
1919 $$.finally = $1->to;$1->to=0;
1923 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
1924 code_t*out = abc_nop(0);
1926 code_t*start = abc_nop(0);
1927 $$ = code_append(start, $4);
1928 if(!is_break_or_jump($4)) {
1929 $$ = abc_jump($$, out);
1931 code_t*end = $$ = abc_nop($$);
1935 tmp = new_variable("__finally__", 0, 0);
1937 abc_exception_list_t*l = $6.l;
1940 abc_exception_t*e = l->abc_exception;
1942 $$ = code_append($$, e->target);
1943 $$ = abc_jump($$, out);
1945 parserassert((ptroff_t)$6.finally);
1947 e->target = $$ = abc_nop($$);
1948 $$ = abc___rethrow__($$);
1956 $$ = code_append($$, out);
1958 $$ = insert_finally($$, $6.finally, tmp);
1960 list_concat(state->method->exceptions, $6.l);
1966 /* ------------ throw ------------------------------- */
1968 THROW : "throw" EXPRESSION {
1972 THROW : "throw" %prec prec_none {
1973 if(!state->exception_name)
1974 syntaxerror("re-throw only possible within a catch block");
1975 variable_t*v = find_variable(state->exception_name);
1977 $$=abc_getlocal($$, v->index);
1981 /* ------------ with -------------------------------- */
1983 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1985 $$ = abc_pushscope($$);
1986 $$ = code_append($$, $5);
1987 $$ = abc_popscope($$);
1990 /* ------------ packages and imports ---------------- */
1992 X_IDENTIFIER: T_IDENTIFIER
1993 | "package" {PASS12 $$="package";}
1995 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
1996 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
1998 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
1999 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2000 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2001 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2003 IMPORT : "import" QNAME {
2006 syntaxerror("Couldn't import class\n");
2007 state_has_imports();
2008 dict_put(state->imports, c->name, c);
2011 IMPORT : "import" PACKAGE '.' '*' {
2014 state_has_imports();
2015 list_append(state->wildcard_imports, i);
2019 /* ------------ classes and interfaces (header) -------------- */
2021 MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
2022 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2023 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2024 MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
2026 MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
2027 | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
2028 | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
2029 | KW_STATIC {PASS12 $$=FLAG_STATIC;}
2030 | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
2031 | KW_FINAL {PASS12 $$=FLAG_FINAL;}
2032 | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
2033 | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
2034 | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
2036 EXTENDS : {$$=registry_getobjectclass();}
2037 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
2039 EXTENDS_LIST : {PASS12 $$=list_new();}
2040 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {PASS12 $$=$2;}
2042 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2043 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {PASS12 $$=$2;}
2045 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2046 EXTENDS IMPLEMENTS_LIST
2047 '{' {PASS12 startclass($1,$3,$4,$5, 0);}
2049 '}' {PASS12 endclass();$$=0;}
2051 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2053 '{' {PASS12 startclass($1,$3,0,$4,1);}
2054 MAYBE_INTERFACE_BODY
2055 '}' {PASS12 endclass();$$=0;}
2057 /* ------------ classes and interfaces (body) -------------- */
2060 MAYBE_CLASS_BODY : CLASS_BODY
2061 CLASS_BODY : CLASS_BODY_ITEM
2062 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2063 CLASS_BODY_ITEM : ';'
2064 CLASS_BODY_ITEM : SLOT_DECLARATION
2065 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2067 CLASS_BODY_ITEM : CODE_STATEMENT {
2068 code_t*c = state->cls->static_init;
2069 c = code_append(c, $1);
2070 state->cls->static_init = c;
2073 MAYBE_INTERFACE_BODY :
2074 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2075 INTERFACE_BODY : IDECLARATION
2076 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2078 IDECLARATION : "var" T_IDENTIFIER {
2079 syntaxerror("variable declarations not allowed in interfaces");
2081 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2084 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2085 syntaxerror("invalid method modifiers: interface methods always need to be public");
2087 startfunction(0,$1,$3,$4,&$6,$8);
2088 endfunction(0,$1,$3,$4,&$6,$8, 0);
2091 /* ------------ classes and interfaces (body, slots ) ------- */
2093 VARCONST: "var" | "const"
2095 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
2097 memberinfo_t* info = state->cls?
2098 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
2099 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
2102 info->flags = flags;
2105 namespace_t mname_ns = {flags2access(flags), ""};
2106 multiname_t mname = {QNAME, &mname_ns, 0, $3};
2108 trait_list_t**traits;
2112 mname_ns.name = state->package;
2113 traits = &global->init->traits;
2114 code = &global->init->method->body->code;
2115 } else if(flags&FLAG_STATIC) {
2117 traits = &state->cls->abc->static_traits;
2118 code = &state->cls->static_init;
2120 // instance variable
2121 traits = &state->cls->abc->traits;
2122 code = &state->cls->init;
2128 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2130 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2132 info->slot = t->slot_id;
2134 /* initalization code (if needed) */
2136 if($5.c && !is_pushundefined($5.c)) {
2137 c = abc_getlocal_0(c);
2138 c = code_append(c, $5.c);
2139 c = converttype(c, $5.t, $4);
2140 c = abc_setslot(c, t->slot_id);
2143 *code = code_append(*code, c);
2146 t->kind= TRAIT_CONST;
2152 /* ------------ constants -------------------------------------- */
2154 MAYBESTATICCONSTANT: {$$=0;}
2155 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2157 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2158 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2159 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2160 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2161 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
2162 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2163 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2164 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2165 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2167 /* ------------ classes and interfaces (body, functions) ------- */
2169 // non-vararg version
2171 memset(&$$,0,sizeof($$));
2173 MAYBE_PARAM_LIST: PARAM_LIST {
2178 MAYBE_PARAM_LIST: "..." PARAM {
2179 memset(&$$,0,sizeof($$));
2181 list_append($$.list, $2);
2183 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2186 list_append($$.list, $4);
2190 PARAM_LIST: PARAM_LIST ',' PARAM {
2192 list_append($$.list, $3);
2195 memset(&$$,0,sizeof($$));
2196 list_append($$.list, $1);
2199 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2200 $$ = malloc(sizeof(param_t));
2205 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2206 $$ = malloc(sizeof(param_t));
2208 $$->type = TYPE_ANY;
2211 GETSET : "get" {$$=$1;}
2215 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2216 MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}'
2220 if(!state->method->info) syntaxerror("internal error");
2222 if(state->method->late_binding) {
2223 c = abc_getlocal_0(c);
2224 c = abc_pushscope(c);
2226 if(state->method->is_constructor && !state->method->has_super) {
2227 // call default constructor
2228 c = abc_getlocal_0(c);
2229 c = abc_constructsuper(c, 0);
2231 c = wrap_function(c, 0, $11);
2233 endfunction(0,$1,$3,$4,&$6,$8,c);
2237 MAYBE_IDENTIFIER: T_IDENTIFIER
2238 MAYBE_IDENTIFIER: {$$=0;}
2239 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2240 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2244 memberinfo_t*f = state->method->info;
2245 if(!f) syntaxerror("internal error");
2248 c = wrap_function(c, 0, $9);
2250 abc_method_t*abc = endfunction(0,0,0,$2,&$4,$6,c);
2252 $$.c = abc_newfunction(0, abc);
2253 $$.t = TYPE_FUNCTION(f);
2257 /* ------------- package + class ids --------------- */
2259 CLASS: T_IDENTIFIER {
2262 /* try current package */
2263 $$ = find_class($1);
2264 if(!$$) syntaxerror("Could not find class %s\n", $1);
2267 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2270 $$ = registry_findclass($1, $3);
2271 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
2275 QNAME: PACKAGEANDCLASS
2278 QNAME_LIST : QNAME {PASS12 $$=list_new();list_append($$, $1);}
2279 QNAME_LIST : QNAME_LIST ',' QNAME {PASS12 $$=$1;list_append($$,$3);}
2281 TYPE : QNAME {$$=$1;}
2282 | '*' {$$=registry_getanytype();}
2283 | "void" {$$=registry_getanytype();}
2285 | "String" {$$=registry_getstringclass();}
2286 | "int" {$$=registry_getintclass();}
2287 | "uint" {$$=registry_getuintclass();}
2288 | "Boolean" {$$=registry_getbooleanclass();}
2289 | "Number" {$$=registry_getnumberclass();}
2292 MAYBETYPE: ':' TYPE {$$=$2;}
2295 /* ----------function calls, delete, constructor calls ------ */
2297 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2298 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2300 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2301 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2302 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2305 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2307 $$.cc = code_append($1.cc, $3.c);
2310 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2315 $$.c = abc_getglobalscope($$.c);
2316 $$.c = abc_getslot($$.c, $2->slot);
2318 $$.c = abc_findpropstrict2($$.c, &m);
2321 $$.c = code_append($$.c, $3.cc);
2324 $$.c = abc_construct($$.c, $3.len);
2326 $$.c = abc_constructprop2($$.c, &m, $3.len);
2330 /* TODO: use abc_call (for calling local variables),
2331 abc_callstatic (for calling own methods)
2334 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2337 if($$.c->opcode == OPCODE_COERCE_A) {
2338 $$.c = code_cutlast($$.c);
2340 code_t*paramcode = $3.cc;
2343 if($$.c->opcode == OPCODE_GETPROPERTY) {
2344 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2345 $$.c = code_cutlast($$.c);
2346 $$.c = code_append($$.c, paramcode);
2347 $$.c = abc_callproperty2($$.c, name, $3.len);
2348 multiname_destroy(name);
2349 } else if($$.c->opcode == OPCODE_GETSLOT) {
2350 int slot = (int)(ptroff_t)$$.c->data[0];
2351 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2352 if(t->kind!=TRAIT_METHOD) {
2353 //ok: flash allows to assign closures to members.
2355 multiname_t*name = t->name;
2356 $$.c = code_cutlast($$.c);
2357 $$.c = code_append($$.c, paramcode);
2358 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2359 $$.c = abc_callproperty2($$.c, name, $3.len);
2360 } else if($$.c->opcode == OPCODE_GETSUPER) {
2361 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2362 $$.c = code_cutlast($$.c);
2363 $$.c = code_append($$.c, paramcode);
2364 $$.c = abc_callsuper2($$.c, name, $3.len);
2365 multiname_destroy(name);
2367 $$.c = abc_getlocal_0($$.c);
2368 $$.c = code_append($$.c, paramcode);
2369 $$.c = abc_call($$.c, $3.len);
2374 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2375 $$.t = $1.t->function->return_type;
2377 $$.c = abc_coerce_a($$.c);
2382 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2383 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2384 if(!state->method) syntaxerror("super() not allowed outside of a function");
2385 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2388 $$.c = abc_getlocal_0($$.c);
2390 $$.c = code_append($$.c, $3.cc);
2392 this is dependent on the control path, check this somewhere else
2393 if(state->method->has_super)
2394 syntaxerror("constructor may call super() only once");
2396 state->method->has_super = 1;
2397 $$.c = abc_constructsuper($$.c, $3.len);
2398 $$.c = abc_pushundefined($$.c);
2402 DELETE: "delete" E {
2404 if($$.c->opcode == OPCODE_COERCE_A) {
2405 $$.c = code_cutlast($$.c);
2407 multiname_t*name = 0;
2408 if($$.c->opcode == OPCODE_GETPROPERTY) {
2409 $$.c->opcode = OPCODE_DELETEPROPERTY;
2410 } else if($$.c->opcode == OPCODE_GETSLOT) {
2411 int slot = (int)(ptroff_t)$$.c->data[0];
2412 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2413 $$.c = code_cutlast($$.c);
2414 $$.c = abc_deleteproperty2($$.c, name);
2416 $$.c = abc_getlocal_0($$.c);
2417 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2418 $$.c = abc_deleteproperty2($$.c, &m);
2420 $$.t = TYPE_BOOLEAN;
2423 RETURN: "return" %prec prec_none {
2424 $$ = abc_returnvoid(0);
2426 RETURN: "return" EXPRESSION {
2428 $$ = abc_returnvalue($$);
2431 // ----------------------- expression types -------------------------------------
2433 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2434 EXPRESSION : E %prec below_minus {$$ = $1;}
2435 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2437 $$.c = cut_last_push($$.c);
2438 $$.c = code_append($$.c,$3.c);
2441 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2442 $$=cut_last_push($1.c);
2445 // ----------------------- expression evaluation -------------------------------------
2447 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2448 //V : CONSTANT {$$ = 0;}
2450 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2451 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2452 //V : NEW {$$ = $1.c;}
2454 //V : DELETE {$$ = $1.c;}
2455 E : DELETE {$$ = $1;}
2459 namespace_t ns = {ACCESS_PACKAGE, ""};
2460 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2462 $$.c = abc_getlex2($$.c, &m);
2463 $$.c = abc_pushstring($$.c, $1.pattern);
2464 $$.c = abc_construct($$.c, 1);
2466 $$.c = abc_getlex2($$.c, &m);
2467 $$.c = abc_pushstring($$.c, $1.pattern);
2468 $$.c = abc_pushstring($$.c, $1.options);
2469 $$.c = abc_construct($$.c, 2);
2474 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2475 //MULTINAME(m, registry_getintclass());
2476 //$$.c = abc_coerce2($$.c, &m); // FIXME
2479 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2482 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2485 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2488 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2491 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2494 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2497 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2498 $$.t = TYPE_BOOLEAN;
2500 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2501 $$.t = TYPE_BOOLEAN;
2503 CONSTANT : "null" {$$.c = abc_pushnull(0);
2508 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2509 $$.t = TYPE_BOOLEAN;
2511 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2512 $$.t = TYPE_BOOLEAN;
2514 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2515 $$.t = TYPE_BOOLEAN;
2517 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2518 $$.t = TYPE_BOOLEAN;
2520 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2521 $$.t = TYPE_BOOLEAN;
2523 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2524 $$.t = TYPE_BOOLEAN;
2526 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2527 $$.t = TYPE_BOOLEAN;
2529 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2530 $$.t = TYPE_BOOLEAN;
2533 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2535 $$.c = converttype($$.c, $1.t, $$.t);
2536 $$.c = abc_dup($$.c);
2537 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2538 $$.c = cut_last_push($$.c);
2539 $$.c = code_append($$.c,$3.c);
2540 $$.c = converttype($$.c, $3.t, $$.t);
2541 code_t*label = $$.c = abc_label($$.c);
2542 jmp->branch = label;
2545 $$.t = join_types($1.t, $3.t, 'A');
2546 /*printf("%08x:\n",$1.t);
2547 code_dump($1.c, 0, 0, "", stdout);
2548 printf("%08x:\n",$3.t);
2549 code_dump($3.c, 0, 0, "", stdout);
2550 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2552 $$.c = converttype($$.c, $1.t, $$.t);
2553 $$.c = abc_dup($$.c);
2554 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2555 $$.c = cut_last_push($$.c);
2556 $$.c = code_append($$.c,$3.c);
2557 $$.c = converttype($$.c, $3.t, $$.t);
2558 code_t*label = $$.c = abc_label($$.c);
2559 jmp->branch = label;
2562 E : '!' E {$$.c=$2.c;
2563 $$.c = abc_not($$.c);
2564 $$.t = TYPE_BOOLEAN;
2567 E : '~' E {$$.c=$2.c;
2568 $$.c = abc_bitnot($$.c);
2572 E : E '&' E {$$.c = code_append($1.c,$3.c);
2573 $$.c = abc_bitand($$.c);
2577 E : E '^' E {$$.c = code_append($1.c,$3.c);
2578 $$.c = abc_bitxor($$.c);
2582 E : E '|' E {$$.c = code_append($1.c,$3.c);
2583 $$.c = abc_bitor($$.c);
2587 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2588 $$.c = abc_rshift($$.c);
2591 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2592 $$.c = abc_urshift($$.c);
2595 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2596 $$.c = abc_lshift($$.c);
2600 E : E '/' E {$$.c = code_append($1.c,$3.c);
2601 $$.c = abc_divide($$.c);
2604 E : E '%' E {$$.c = code_append($1.c,$3.c);
2605 $$.c = abc_modulo($$.c);
2608 E : E '+' E {$$.c = code_append($1.c,$3.c);
2609 if(BOTH_INT($1.t, $3.t)) {
2610 $$.c = abc_add_i($$.c);
2613 $$.c = abc_add($$.c);
2614 $$.t = join_types($1.t,$3.t,'+');
2617 E : E '-' E {$$.c = code_append($1.c,$3.c);
2618 if(BOTH_INT($1.t,$3.t)) {
2619 $$.c = abc_subtract_i($$.c);
2622 $$.c = abc_subtract($$.c);
2626 E : E '*' E {$$.c = code_append($1.c,$3.c);
2627 if(BOTH_INT($1.t,$3.t)) {
2628 $$.c = abc_multiply_i($$.c);
2631 $$.c = abc_multiply($$.c);
2636 E : E "in" E {$$.c = code_append($1.c,$3.c);
2637 $$.c = abc_in($$.c);
2638 $$.t = TYPE_BOOLEAN;
2641 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2642 if(use_astype && TYPE_IS_CLASS($3.t)) {
2643 MULTINAME(m,$3.t->cls);
2644 $$.c = abc_astype2($1.c, &m);
2647 $$.c = code_append($1.c, $3.c);
2648 $$.c = abc_astypelate($$.c);
2653 E : E "instanceof" E
2654 {$$.c = code_append($1.c, $3.c);
2655 $$.c = abc_instanceof($$.c);
2656 $$.t = TYPE_BOOLEAN;
2659 E : E "is" E {$$.c = code_append($1.c, $3.c);
2660 $$.c = abc_istypelate($$.c);
2661 $$.t = TYPE_BOOLEAN;
2664 E : "typeof" '(' E ')' {
2666 $$.c = abc_typeof($$.c);
2671 $$.c = cut_last_push($2.c);
2672 $$.c = abc_pushundefined($$.c);
2676 E : "void" { $$.c = abc_pushundefined(0);
2680 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2685 $$.c=abc_negate_i($$.c);
2688 $$.c=abc_negate($$.c);
2695 $$.c = code_append($$.c, $3.c);
2697 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2698 $$.c = abc_getproperty2($$.c, &m);
2699 $$.t = 0; // array elements have unknown type
2702 E : '[' MAYBE_EXPRESSION_LIST ']' {
2704 $$.c = code_append($$.c, $2.cc);
2705 $$.c = abc_newarray($$.c, $2.len);
2706 $$.t = registry_getarrayclass();
2709 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2710 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
2712 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2714 $$.cc = code_append($$.cc, $1.c);
2715 $$.cc = code_append($$.cc, $3.c);
2718 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2721 $$.cc = code_append($$.cc, $3.c);
2722 $$.cc = code_append($$.cc, $5.c);
2727 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2729 $$.c = code_append($$.c, $2.cc);
2730 $$.c = abc_newobject($$.c, $2.len/2);
2731 $$.t = registry_getobjectclass();
2736 if(BOTH_INT($1.t,$3.t)) {
2737 c=abc_multiply_i(c);
2741 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2742 $$.c = toreadwrite($1.c, c, 0, 0);
2747 code_t*c = abc_modulo($3.c);
2748 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2749 $$.c = toreadwrite($1.c, c, 0, 0);
2753 code_t*c = abc_lshift($3.c);
2754 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2755 $$.c = toreadwrite($1.c, c, 0, 0);
2759 code_t*c = abc_rshift($3.c);
2760 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2761 $$.c = toreadwrite($1.c, c, 0, 0);
2765 code_t*c = abc_urshift($3.c);
2766 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2767 $$.c = toreadwrite($1.c, c, 0, 0);
2771 code_t*c = abc_divide($3.c);
2772 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2773 $$.c = toreadwrite($1.c, c, 0, 0);
2777 code_t*c = abc_bitor($3.c);
2778 c=converttype(c, TYPE_INT, $1.t);
2779 $$.c = toreadwrite($1.c, c, 0, 0);
2785 if(TYPE_IS_INT($1.t)) {
2789 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2792 $$.c = toreadwrite($1.c, c, 0, 0);
2795 E : E "-=" E { code_t*c = $3.c;
2796 if(TYPE_IS_INT($1.t)) {
2797 c=abc_subtract_i(c);
2800 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2803 $$.c = toreadwrite($1.c, c, 0, 0);
2806 E : E '=' E { code_t*c = 0;
2807 c = code_append(c, $3.c);
2808 c = converttype(c, $3.t, $1.t);
2809 $$.c = toreadwrite($1.c, c, 1, 0);
2813 E : E '?' E ':' E %prec below_assignment {
2814 $$.t = join_types($3.t,$5.t,'?');
2816 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2817 $$.c = code_append($$.c, $3.c);
2818 $$.c = converttype($$.c, $3.t, $$.t);
2819 code_t*j2 = $$.c = abc_jump($$.c, 0);
2820 $$.c = j1->branch = abc_label($$.c);
2821 $$.c = code_append($$.c, $5.c);
2822 $$.c = converttype($$.c, $3.t, $$.t);
2823 $$.c = j2->branch = abc_label($$.c);
2826 E : E "++" { code_t*c = 0;
2827 classinfo_t*type = $1.t;
2828 if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
2829 int nr = getlocalnr($1.c);
2830 code_free($1.c);$1.c=0;
2831 if(TYPE_IS_INT($1.t)) {
2832 $$.c = abc_getlocal(0, nr);
2833 $$.c = abc_inclocal_i($$.c, nr);
2834 } else if(TYPE_IS_NUMBER($1.t)) {
2835 $$.c = abc_getlocal(0, nr);
2836 $$.c = abc_inclocal($$.c, nr);
2837 } else syntaxerror("internal error");
2839 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2840 c=abc_increment_i(c);
2846 c=converttype(c, type, $1.t);
2847 $$.c = toreadwrite($1.c, c, 0, 1);
2852 // TODO: use inclocal, like with ++
2853 E : E "--" { code_t*c = 0;
2854 classinfo_t*type = $1.t;
2855 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2856 c=abc_decrement_i(c);
2862 c=converttype(c, type, $1.t);
2863 $$.c = toreadwrite($1.c, c, 0, 1);
2867 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2868 classinfo_t*type = $2.t;
2869 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2870 c=abc_increment_i(c);
2876 c=converttype(c, type, $2.t);
2877 $$.c = toreadwrite($2.c, c, 0, 0);
2881 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2882 classinfo_t*type = $2.t;
2883 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2884 c=abc_decrement_i(c);
2890 c=converttype(c, type, $2.t);
2891 $$.c = toreadwrite($2.c, c, 0, 0);
2895 E : "super" '.' T_IDENTIFIER
2896 { if(!state->cls->info)
2897 syntaxerror("super keyword not allowed outside a class");
2898 classinfo_t*t = state->cls->info->superclass;
2899 if(!t) t = TYPE_OBJECT;
2901 memberinfo_t*f = registry_findmember(t, $3, 1);
2902 namespace_t ns = flags2namespace(f->flags, "");
2903 MEMBER_MULTINAME(m, f, $3);
2905 $$.c = abc_getlocal_0($$.c);
2906 $$.c = abc_getsuper2($$.c, &m);
2907 $$.t = memberinfo_gettype(f);
2910 E : E '.' T_IDENTIFIER
2912 classinfo_t*t = $1.t;
2914 if(TYPE_IS_CLASS(t) && t->cls) {
2919 memberinfo_t*f = registry_findmember(t, $3, 1);
2921 if(f && !is_static != !(f->flags&FLAG_STATIC))
2923 if(f && f->slot && !noslot) {
2924 $$.c = abc_getslot($$.c, f->slot);
2926 MEMBER_MULTINAME(m, f, $3);
2927 $$.c = abc_getproperty2($$.c, &m);
2929 /* determine type */
2930 $$.t = memberinfo_gettype(f);
2932 $$.c = abc_coerce_a($$.c);
2934 /* when resolving a property on an unknown type, we do know the
2935 name of the property (and don't seem to need the package), but
2936 we need to make avm2 try out all access modes */
2937 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2938 $$.c = abc_getproperty2($$.c, &m);
2939 $$.c = abc_coerce_a($$.c);
2940 $$.t = registry_getanytype();
2944 VAR_READ : T_IDENTIFIER {
2951 /* look at variables */
2952 if((v = find_variable($1))) {
2953 // $1 is a local variable
2954 $$.c = abc_getlocal($$.c, v->index);
2959 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
2961 /* look at current class' members */
2962 if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
2963 (f->flags&FLAG_STATIC) >= i_am_static) {
2964 // $1 is a function in this class
2965 int var_is_static = (f->flags&FLAG_STATIC);
2967 if(f->kind == MEMBER_METHOD) {
2968 $$.t = TYPE_FUNCTION(f);
2972 if(var_is_static && !i_am_static) {
2973 /* access to a static member from a non-static location.
2974 do this via findpropstrict:
2975 there doesn't seem to be any non-lookup way to access
2976 static properties of a class */
2977 state->method->late_binding = 1;
2979 namespace_t ns = {flags2access(f->flags), ""};
2980 multiname_t m = {QNAME, &ns, 0, $1};
2981 $$.c = abc_findpropstrict2($$.c, &m);
2982 $$.c = abc_getproperty2($$.c, &m);
2984 } else if(f->slot>0) {
2985 $$.c = abc_getlocal_0($$.c);
2986 $$.c = abc_getslot($$.c, f->slot);
2989 namespace_t ns = {flags2access(f->flags), ""};
2990 multiname_t m = {QNAME, &ns, 0, $1};
2991 $$.c = abc_getlocal_0($$.c);
2992 $$.c = abc_getproperty2($$.c, &m);
2997 /* look at actual classes, in the current package and imported */
2998 if((a = find_class($1))) {
2999 if(a->flags & FLAG_METHOD) {
3001 $$.c = abc_findpropstrict2($$.c, &m);
3002 $$.c = abc_getproperty2($$.c, &m);
3003 if(a->function->kind == MEMBER_METHOD) {
3004 $$.t = TYPE_FUNCTION(a->function);
3006 $$.t = a->function->type;
3010 $$.c = abc_getglobalscope($$.c);
3011 $$.c = abc_getslot($$.c, a->slot);
3014 $$.c = abc_getlex2($$.c, &m);
3016 $$.t = TYPE_CLASS(a);
3021 /* unknown object, let the avm2 resolve it */
3023 if(strcmp($1,"trace"))
3024 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3025 state->method->late_binding = 1;
3027 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3030 $$.c = abc_findpropstrict2($$.c, &m);
3031 $$.c = abc_getproperty2($$.c, &m);
3036 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
3037 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
3038 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
3040 // ----------------- namespaces -------------------------------------------------
3042 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
3043 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
3044 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
3046 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}