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;
430 state_destroy(leaving);
433 void initialize_parser()
435 global = rfx_calloc(sizeof(global_t));
436 global->file = abc_file_new();
437 global->file->flags &= ~ABCFILE_LAZY;
438 global->variable_count = 1;
439 global->init = abc_initscript(global->file);
440 code_t*c = global->init->method->body->code;
441 c = abc_getlocal_0(c);
442 c = abc_pushscope(c);
443 /*c = abc_findpropstrict(c, "[package]::trace");
444 c = abc_pushstring(c, "[entering global init function]");
445 c = abc_callpropvoid(c, "[package]::trace", 1);*/
446 global->init->method->body->code = c;
449 void initialize_file(char*filename)
452 state->package = filename;
453 // needed for state->method->late_binding:
454 state->method = rfx_calloc(sizeof(methodstate_t));
458 if(!state || state->level!=1) {
459 syntaxerror("unexpected end of file");
461 state_destroy(state);state=0;
464 void* finish_parser()
466 code_t*c = global->init->method->body->code;
467 /*c = abc_findpropstrict(c, "[package]::trace");
468 c = abc_pushstring(c, "[leaving global init function]");
469 c = abc_callpropvoid(c, "[package]::trace", 1);*/
470 c = abc_returnvoid(c);
471 global->init->method->body->code = c;
476 static void xx_scopetest()
478 /* findpropstrict doesn't just return a scope object- it
479 also makes it "active" somehow. Push local_0 on the
480 scope stack and read it back with findpropstrict, it'll
481 contain properties like "trace". Trying to find the same
482 property on a "vanilla" local_0 yields only a "undefined" */
483 //c = abc_findpropstrict(c, "[package]::trace");
485 /*c = abc_getlocal_0(c);
486 c = abc_findpropstrict(c, "[package]::trace");
488 c = abc_setlocal_1(c);
490 c = abc_pushbyte(c, 0);
491 c = abc_setlocal_2(c);
493 code_t*xx = c = abc_label(c);
494 c = abc_findpropstrict(c, "[package]::trace");
495 c = abc_pushstring(c, "prop:");
496 c = abc_hasnext2(c, 1, 2);
498 c = abc_setlocal_3(c);
499 c = abc_callpropvoid(c, "[package]::trace", 2);
500 c = abc_getlocal_3(c);
502 c = abc_iftrue(c,xx);*/
506 typedef struct _variable {
512 static variable_t* find_variable(char*name)
518 v = dict_lookup(s->vars, name);
526 static variable_t* find_variable_safe(char*name)
528 variable_t* v = find_variable(name);
530 syntaxerror("undefined variable: %s", name);
533 static char variable_exists(char*name)
535 return dict_lookup(state->vars, name)!=0;
537 code_t*defaultvalue(code_t*c, classinfo_t*type);
538 static int new_variable(char*name, classinfo_t*type, char init)
541 v->index = global->variable_count;
545 dict_put(state->vars, name, v);
547 return global->variable_count++;
549 #define TEMPVARNAME "__as3_temp__"
550 static int gettempvar()
552 variable_t*v = find_variable(TEMPVARNAME);
555 return new_variable(TEMPVARNAME, 0, 0);
558 code_t* var_block(code_t*body)
564 for(t=0;t<state->vars->hashsize;t++) {
565 dictentry_t*e = state->vars->slots[t];
567 variable_t*v = (variable_t*)e->data;
568 if(v->type && v->init) {
569 c = defaultvalue(c, v->type);
570 c = abc_setlocal(c, v->index);
571 k = abc_kill(k, v->index);
581 if(x->opcode== OPCODE___BREAK__ ||
582 x->opcode== OPCODE___CONTINUE__) {
583 /* link kill code before break/continue */
584 code_t*e = code_dup(k);
585 code_t*s = code_start(e);
597 c = code_append(c, body);
598 c = code_append(c, k);
602 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
604 c = code_append(c, header);
605 c = code_append(c, var_block(body));
606 /* append return if necessary */
607 if(!c || (c->opcode != OPCODE_RETURNVOID &&
608 c->opcode != OPCODE_RETURNVALUE)) {
609 c = abc_returnvoid(c);
615 static void startpackage(char*name)
618 /*printf("entering package \"%s\"\n", name);*/
619 state->package = strdup(name);
620 global->variable_count = 1;
622 static void endpackage()
624 /*printf("leaving package \"%s\"\n", state->package);*/
626 //used e.g. in classinfo_register:
627 //free(state->package);state->package=0;
632 char*as3_globalclass=0;
633 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
636 syntaxerror("inner classes now allowed");
639 global->variable_count = 1;
640 state->cls = rfx_calloc(sizeof(classstate_t));
641 state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
644 classinfo_list_t*mlist=0;
646 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
647 syntaxerror("invalid modifier(s)");
649 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
650 syntaxerror("public and internal not supported at the same time.");
652 /* create the class name, together with the proper attributes */
656 if(!(flags&FLAG_PUBLIC) && !state->package) {
657 access = ACCESS_PRIVATE; package = current_filename;
658 } else if(!(flags&FLAG_PUBLIC) && state->package) {
659 access = ACCESS_PACKAGEINTERNAL; package = state->package;
660 } else if(state->package) {
661 access = ACCESS_PACKAGE; package = state->package;
663 syntaxerror("public classes only allowed inside a package");
666 if(registry_findclass(package, classname)) {
667 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
671 /* build info struct */
672 int num_interfaces = (list_length(implements));
673 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
674 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
676 classinfo_list_t*l = implements;
677 for(l=implements;l;l=l->next) {
678 state->cls->info->interfaces[pos++] = l->classinfo;
681 multiname_t*extends2 = sig2mname(extends);
683 MULTINAME(classname2,state->cls->info);
686 state->cls_init = abc_getlocal_0(state->cls_init);
687 state->cls_init = abc_constructsuper(state->cls_init, 0);
690 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
691 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
692 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
694 state->cls->info->flags |= CLASS_INTERFACE;
695 abc_class_interface(state->cls->abc);
698 abc_class_protectedNS(state->cls->abc, classname);
700 for(mlist=implements;mlist;mlist=mlist->next) {
701 MULTINAME(m, mlist->classinfo);
702 abc_class_add_interface(state->cls->abc, &m);
705 /* now write the construction code for this class */
706 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
708 abc_method_body_t*m = global->init->method->body;
709 __ getglobalscope(m);
710 classinfo_t*s = extends;
715 //TODO: take a look at the current scope stack, maybe
716 // we can re-use something
721 multiname_t*s2 = sig2mname(s);
723 multiname_destroy(s2);
725 __ pushscope(m); count++;
726 m->code = m->code->prev->prev; // invert
728 /* continue appending after last op end */
729 while(m->code && m->code->next) m->code = m->code->next;
731 /* TODO: if this is one of *our* classes, we can also
732 do a getglobalscope/getslot <nr> (which references
733 the init function's slots) */
735 __ getlex2(m, extends2);
737 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
738 stack is not the superclass */
739 __ pushscope(m);count++;
742 /* notice: we get a verify error #1107 if the top element on the scope
743 stack is not the global object */
745 __ pushscope(m);count++;
747 __ newclass(m,state->cls->abc);
751 __ setslot(m, slotindex);
753 /* flash.display.MovieClip handling */
754 if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
755 if(state->package && state->package[0]) {
756 as3_globalclass = concat3(state->package, ".", classname);
758 as3_globalclass = strdup(classname);
761 multiname_destroy(extends2);
764 static void endclass()
766 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
768 c = abc_getlocal_0(c);
769 c = abc_constructsuper(c, 0);
770 state->cls->init = code_append(state->cls->init, c);
772 if(!state->method->late_binding) {
773 // class initialization code uses late binding
775 c = abc_getlocal_0(c);
776 c = abc_pushscope(c);
777 state->cls->static_init = code_append(c, state->cls->static_init);
780 if(state->cls->init) {
781 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
782 m->body->code = wrap_function(0, state->cls->init, m->body->code);
784 if(state->cls->static_init) {
785 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
786 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
789 free(state->cls);state->cls=0;
790 free(state->method);state->method=0;
794 void check_code_for_break(code_t*c)
797 if(c->opcode == OPCODE___BREAK__) {
798 char*name = string_cstr(c->data[0]);
799 syntaxerror("Unresolved \"break %s\"", name);
801 if(c->opcode == OPCODE___CONTINUE__) {
802 char*name = string_cstr(c->data[0]);
803 syntaxerror("Unresolved \"continue %s\"", name);
810 static void check_constant_against_type(classinfo_t*t, constant_t*c)
812 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
813 if(TYPE_IS_NUMBER(t)) {
814 xassert(c->type == CONSTANT_FLOAT
815 || c->type == CONSTANT_INT
816 || c->type == CONSTANT_UINT);
817 } else if(TYPE_IS_UINT(t)) {
818 xassert(c->type == CONSTANT_UINT ||
819 (c->type == CONSTANT_INT && c->i>0));
820 } else if(TYPE_IS_INT(t)) {
821 xassert(c->type == CONSTANT_INT);
822 } else if(TYPE_IS_BOOLEAN(t)) {
823 xassert(c->type == CONSTANT_TRUE
824 || c->type == CONSTANT_FALSE);
829 static int flags2access(int flags)
832 if(flags&FLAG_PUBLIC) {
833 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
834 syntaxerror("invalid combination of access levels");
835 access = ACCESS_PACKAGE;
836 } else if(flags&FLAG_PRIVATE) {
837 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
838 syntaxerror("invalid combination of access levels");
839 access = ACCESS_PRIVATE;
840 } else if(flags&FLAG_PROTECTED) {
841 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
842 syntaxerror("invalid combination of access levels");
843 access = ACCESS_PROTECTED;
845 access = ACCESS_PACKAGEINTERNAL;
851 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
853 memberinfo_t*minfo = 0;
856 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
857 minfo->return_type = return_type;
858 } else if(getset != KW_GET && getset != KW_SET) {
860 if((minfo = registry_findmember(state->cls->info, name, 0))) {
861 if(minfo->parent == state->cls->info) {
862 syntaxerror("class already contains a member/method called '%s'", name);
863 } else if(!minfo->parent) {
864 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
866 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
867 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
870 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
871 minfo->return_type = return_type;
872 // getslot on a member slot only returns "undefined", so no need
873 // to actually store these
874 //state->minfo->slot = state->method->abc->method->trait->slot_id;
876 //class getter/setter
877 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
881 else if(params->list)
882 type = params->list->param->type;
883 // not sure wether to look into superclasses here, too
884 if((minfo=registry_findmember(state->cls->info, name, 0))) {
885 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
886 syntaxerror("class already contains a member or method called '%s'", name);
888 syntaxerror("getter/setter for '%s' already defined", name);
889 /* make a setter or getter into a getset */
894 if(type && minfo->type != type)
895 syntaxerror("different type in getter and setter");
897 minfo = memberinfo_register(state->cls->info, name, gs);
900 /* can't assign a slot as getter and setter might have different slots */
901 //minfo->slot = slot;
903 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
904 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
905 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
906 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
907 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
908 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
912 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
913 params_t*params, classinfo_t*return_type)
915 if(state->method && state->method->info) {
916 syntaxerror("not able to start another method scope");
919 global->variable_count = 0;
920 state->method = rfx_calloc(sizeof(methodstate_t));
921 state->method->has_super = 0;
924 state->method->is_constructor = !strcmp(state->cls->info->name,name);
925 state->cls->has_constructor |= state->method->is_constructor;
927 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
929 state->method->is_global = 1;
930 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
932 new_variable("globalscope", 0, 0);
935 /* state->vars is initialized by state_new */
938 for(p=params->list;p;p=p->next) {
939 new_variable(p->param->name, p->param->type, 0);
941 if(state->method->is_constructor)
942 name = "__as3_constructor__";
943 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
946 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
947 params_t*params, classinfo_t*return_type, code_t*body)
951 multiname_t*type2 = sig2mname(return_type);
953 if(state->method->is_constructor) {
954 f = abc_class_getconstructor(state->cls->abc, type2);
955 } else if(!state->method->is_global) {
956 namespace_t mname_ns = flags2namespace(flags, "");
957 multiname_t mname = {QNAME, &mname_ns, 0, name};
959 if(flags&FLAG_STATIC)
960 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
962 f = abc_class_method(state->cls->abc, type2, &mname);
963 slot = f->trait->slot_id;
965 namespace_t mname_ns = flags2namespace(flags, state->package);
966 multiname_t mname = {QNAME, &mname_ns, 0, name};
968 f = abc_method_new(global->file, type2, 1);
969 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
970 //abc_code_t*c = global->init->method->body->code;
972 //flash doesn't seem to allow us to access function slots
973 //state->method->info->slot = slot;
975 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
976 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
977 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
978 if(params->varargs) f->flags |= METHOD_NEED_REST;
982 for(p=params->list;p;p=p->next) {
983 if(params->varargs && !p->next) {
984 break; //varargs: omit last parameter in function signature
986 multiname_t*m = sig2mname(p->param->type);
987 list_append(f->parameters, m);
988 if(p->param->value) {
989 check_constant_against_type(p->param->type, p->param->value);
990 opt=1;list_append(f->optional_parameters, p->param->value);
992 syntaxerror("non-optional parameter not allowed after optional parameters");
995 check_code_for_break(body);
998 f->body->code = body;
999 f->body->exceptions = state->method->exceptions;
1000 } else { //interface
1002 syntaxerror("interface methods can't have a method body");
1005 free(state->method);state->method=0;
1011 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1016 void breakjumpsto(code_t*c, char*name, code_t*jump)
1019 if(c->opcode == OPCODE___BREAK__) {
1020 string_t*name2 = c->data[0];
1021 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1022 c->opcode = OPCODE_JUMP;
1029 void continuejumpsto(code_t*c, char*name, code_t*jump)
1032 if(c->opcode == OPCODE___CONTINUE__) {
1033 string_t*name2 = c->data[0];
1034 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1035 c->opcode = OPCODE_JUMP;
1043 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1044 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1045 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1047 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1049 if(!type1 || !type2)
1050 return registry_getanytype();
1051 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1052 return registry_getanytype();
1055 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1064 return registry_getanytype();
1066 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1071 return abc_coerce_a(c);
1075 // cast an "any" type to a specific type. subject to
1076 // runtime exceptions
1077 return abc_coerce2(c, &m);
1080 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1081 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1082 // allow conversion between number types
1083 return abc_coerce2(c, &m);
1085 //printf("%s.%s\n", from.package, from.name);
1086 //printf("%s.%s\n", to.package, to.name);
1088 classinfo_t*supertype = from;
1090 if(supertype == to) {
1091 // target type is one of from's superclasses
1092 return abc_coerce2(c, &m);
1095 while(supertype->interfaces[t]) {
1096 if(supertype->interfaces[t]==to) {
1097 // target type is one of from's interfaces
1098 return abc_coerce2(c, &m);
1102 supertype = supertype->superclass;
1104 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1106 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1108 syntaxerror("can't convert type %s to %s", from->name, to->name);
1109 return 0; // make gcc happy
1112 code_t*defaultvalue(code_t*c, classinfo_t*type)
1114 if(TYPE_IS_INT(type)) {
1115 c = abc_pushbyte(c, 0);
1116 } else if(TYPE_IS_UINT(type)) {
1117 c = abc_pushuint(c, 0);
1118 } else if(TYPE_IS_FLOAT(type)) {
1120 } else if(TYPE_IS_BOOLEAN(type)) {
1121 c = abc_pushfalse(c);
1123 //c = abc_pushundefined(c);
1125 c = abc_pushnull(c);
1127 c = abc_coerce2(c, &m);
1132 char is_pushundefined(code_t*c)
1134 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1137 void parserassert(int b)
1139 if(!b) syntaxerror("internal error: assertion failed");
1142 static classinfo_t* find_class(char*name)
1146 c = registry_findclass(state->package, name);
1149 /* try explicit imports */
1150 dictentry_t* e = dict_get_slot(state->imports, name);
1153 if(!strcmp(e->key, name)) {
1154 c = (classinfo_t*)e->data;
1160 /* try package.* imports */
1161 import_list_t*l = state->wildcard_imports;
1163 //printf("does package %s contain a class %s?\n", l->import->package, name);
1164 c = registry_findclass(l->import->package, name);
1169 /* try global package */
1170 c = registry_findclass("", name);
1173 /* try local "filename" package */
1174 c = registry_findclass(current_filename, name);
1180 static char is_getlocal(code_t*c)
1182 if(!c || c->prev || c->next)
1184 return(c->opcode == OPCODE_GETLOCAL
1185 || c->opcode == OPCODE_GETLOCAL_0
1186 || c->opcode == OPCODE_GETLOCAL_1
1187 || c->opcode == OPCODE_GETLOCAL_2
1188 || c->opcode == OPCODE_GETLOCAL_3);
1190 static int getlocalnr(code_t*c)
1192 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1193 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1194 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1195 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1196 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1197 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1201 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1205 [prefix code] [read instruction]
1209 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1212 if(in && in->opcode == OPCODE_COERCE_A) {
1213 in = code_cutlast(in);
1216 syntaxerror("internal error");
1218 /* chop off read instruction */
1222 prefix = r->prev;r->prev = 0;
1228 char use_temp_var = readbefore;
1230 /* generate the write instruction, and maybe append a dup to the prefix code */
1231 code_t* write = abc_nop(0);
1232 if(r->opcode == OPCODE_GETPROPERTY) {
1233 write->opcode = OPCODE_SETPROPERTY;
1234 multiname_t*m = (multiname_t*)r->data[0];
1235 write->data[0] = multiname_clone(m);
1236 if(m->type == QNAME || m->type == MULTINAME) {
1238 prefix = abc_dup(prefix); // we need the object, too
1241 } else if(m->type == MULTINAMEL) {
1243 /* dupping two values on the stack requires 5 operations and one register-
1244 couldn't adobe just have given us a dup2? */
1245 int temp = gettempvar();
1246 prefix = abc_setlocal(prefix, temp);
1247 prefix = abc_dup(prefix);
1248 prefix = abc_getlocal(prefix, temp);
1249 prefix = abc_swap(prefix);
1250 prefix = abc_getlocal(prefix, temp);
1252 prefix = abc_kill(prefix, temp);
1256 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1258 } else if(r->opcode == OPCODE_GETSLOT) {
1259 write->opcode = OPCODE_SETSLOT;
1260 write->data[0] = r->data[0];
1262 prefix = abc_dup(prefix); // we need the object, too
1265 } else if(r->opcode == OPCODE_GETLOCAL) {
1266 write->opcode = OPCODE_SETLOCAL;
1267 write->data[0] = r->data[0];
1268 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1269 write->opcode = OPCODE_SETLOCAL_0;
1270 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1271 write->opcode = OPCODE_SETLOCAL_1;
1272 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1273 write->opcode = OPCODE_SETLOCAL_2;
1274 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1275 write->opcode = OPCODE_SETLOCAL_3;
1278 syntaxerror("illegal lvalue: can't assign a value to this expression");
1285 /* with getproperty/getslot, we have to be extra careful not
1286 to execute the read code twice, as it might have side-effects
1287 (e.g. if the property is in fact a setter/getter combination)
1289 So read the value, modify it, and write it again,
1290 using prefix only once and making sure (by using a temporary
1291 register) that the return value is what we just wrote */
1292 temp = gettempvar();
1293 c = code_append(c, prefix);
1294 c = code_append(c, r);
1297 c = abc_setlocal(c, temp);
1299 c = code_append(c, middlepart);
1302 c = abc_setlocal(c, temp);
1304 c = code_append(c, write);
1305 c = abc_getlocal(c, temp);
1306 c = abc_kill(c, temp);
1308 /* if we're allowed to execute the read code twice *and*
1309 the middlepart doesn't modify the code, things are easier.
1311 code_t* r2 = code_dup(r);
1312 //c = code_append(c, prefix);
1313 parserassert(!prefix);
1314 c = code_append(c, r);
1315 c = code_append(c, middlepart);
1316 c = code_append(c, write);
1317 c = code_append(c, r2);
1320 /* even smaller version: overwrite the value without reading
1324 c = code_append(c, prefix);
1327 c = code_append(c, middlepart);
1328 c = code_append(c, write);
1329 c = code_append(c, r);
1331 temp = gettempvar();
1333 c = code_append(c, prefix);
1335 c = code_append(c, middlepart);
1337 c = abc_setlocal(c, temp);
1338 c = code_append(c, write);
1339 c = abc_getlocal(c, temp);
1340 c = abc_kill(c, temp);
1346 char is_break_or_jump(code_t*c)
1350 if(c->opcode == OPCODE_JUMP ||
1351 c->opcode == OPCODE___BREAK__ ||
1352 c->opcode == OPCODE___CONTINUE__ ||
1353 c->opcode == OPCODE_THROW ||
1354 c->opcode == OPCODE_RETURNVOID ||
1355 c->opcode == OPCODE_RETURNVALUE) {
1362 #define IS_FINALLY_TARGET(op) \
1363 ((op) == OPCODE___CONTINUE__ || \
1364 (op) == OPCODE___BREAK__ || \
1365 (op) == OPCODE_RETURNVOID || \
1366 (op) == OPCODE_RETURNVALUE || \
1367 (op) == OPCODE___RETHROW__)
1369 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1371 #define NEED_EXTRA_STACK_ARG
1372 code_t*finally_label = abc_nop(0);
1373 NEW(lookupswitch_t, l);
1379 code_t*prev = i->prev;
1380 if(IS_FINALLY_TARGET(i->opcode)) {
1383 if(i->opcode == OPCODE___RETHROW__ ||
1384 i->opcode == OPCODE_RETURNVALUE) {
1385 if(i->opcode == OPCODE___RETHROW__)
1386 i->opcode = OPCODE_THROW;
1388 p = abc_coerce_a(p);
1389 p = abc_setlocal(p, tempvar);
1391 p = abc_pushbyte(p, count++);
1392 p = abc_jump(p, finally_label);
1393 code_t*target = p = abc_label(p);
1394 #ifdef NEED_EXTRA_STACK_ARG
1398 p = abc_getlocal(p, tempvar);
1401 p->next = i;i->prev = p;
1402 list_append(l->targets, target);
1408 c = abc_pushbyte(c, -1);
1409 c = code_append(c, finally_label);
1410 c = code_append(c, finally);
1412 #ifdef NEED_EXTRA_STACK_ARG
1415 c = abc_lookupswitch(c, l);
1416 c = l->def = abc_label(c);
1417 #ifdef NEED_EXTRA_STACK_ARG
1424 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1428 code_t*prev = i->prev;
1429 if(IS_FINALLY_TARGET(i->opcode)) {
1430 if(i->opcode == OPCODE___RETHROW__)
1431 i->opcode = OPCODE_THROW;
1432 code_t*end = code_dup(finally);
1433 code_t*start = code_start(end);
1434 if(prev) prev->next = start;
1441 return code_append(c, finally);
1444 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1450 int num_insertion_points=0;
1452 if(IS_FINALLY_TARGET(i->opcode))
1453 num_insertion_points++;
1460 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1465 int simple_version_cost = (1+num_insertion_points)*code_size;
1466 int lookup_version_cost = 4*num_insertion_points + 5;
1468 if(cantdup || simple_version_cost > lookup_version_cost) {
1469 printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
1470 return insert_finally_lookup(c, finally, tempvar);
1472 printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
1473 return insert_finally_simple(c, finally, tempvar);
1482 /* ------------ code blocks / statements ---------------- */
1484 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1486 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1487 PROGRAM_CODE_LIST: PROGRAM_CODE
1488 | PROGRAM_CODE_LIST PROGRAM_CODE
1490 PROGRAM_CODE: PACKAGE_DECLARATION
1491 | INTERFACE_DECLARATION
1493 | FUNCTION_DECLARATION
1498 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1499 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1500 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1502 INPACKAGE_CODE: INTERFACE_DECLARATION
1504 | FUNCTION_DECLARATION
1509 MAYBECODE: CODE {$$=$1;}
1510 MAYBECODE: {$$=code_new();}
1512 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1513 CODE: CODEPIECE {$$=$1;}
1515 // code which also may appear outside a method
1516 CODE_STATEMENT: IMPORT
1518 CODE_STATEMENT: FOR_IN
1519 CODE_STATEMENT: WHILE
1520 CODE_STATEMENT: DO_WHILE
1521 CODE_STATEMENT: SWITCH
1523 CODE_STATEMENT: WITH
1525 CODE_STATEMENT: VOIDEXPRESSION
1527 // code which may appear anywhere
1528 CODEPIECE: ';' {$$=0;}
1529 CODEPIECE: CODE_STATEMENT
1530 CODEPIECE: VARIABLE_DECLARATION
1536 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1537 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1539 CODEBLOCK : '{' CODE '}' {$$=$2;}
1540 CODEBLOCK : '{' '}' {$$=0;}
1541 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1542 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1544 /* ------------ package init code ------------------- */
1546 PACKAGE_INITCODE: CODE_STATEMENT {
1547 if($1) as3_warning("code ignored");
1550 /* ------------ variables --------------------------- */
1552 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1553 | {$$.c=abc_pushundefined(0);
1557 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1558 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1560 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1561 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1563 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1565 if(variable_exists($1))
1566 syntaxerror("Variable %s already defined", $1);
1568 if(!is_subtype_of($3.t, $2)) {
1569 syntaxerror("Can't convert %s to %s", $3.t->name,
1573 int index = new_variable($1, $2, 1);
1576 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1578 $$ = converttype($$, $3.t, $2);
1579 $$ = abc_setlocal($$, index);
1581 $$ = defaultvalue(0, $2);
1582 $$ = abc_setlocal($$, index);
1585 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1587 $$ = abc_coerce_a($$);
1588 $$ = abc_setlocal($$, index);
1594 /* that's the default for a local register, anyway
1596 state->method->initcode = abc_pushundefined(state->method->initcode);
1597 state->method->initcode = abc_setlocal(state->method->initcode, index);
1599 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1602 /* ------------ control flow ------------------------- */
1604 MAYBEELSE: %prec below_else {$$ = code_new();}
1605 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1606 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1608 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1611 $$ = code_append($$, $4.c);
1612 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1614 $$ = code_append($$, $6);
1616 myjmp = $$ = abc_jump($$, 0);
1618 myif->branch = $$ = abc_nop($$);
1620 $$ = code_append($$, $7);
1621 myjmp->branch = $$ = abc_nop($$);
1627 FOR_INIT : {$$=code_new();}
1628 FOR_INIT : VARIABLE_DECLARATION
1629 FOR_INIT : VOIDEXPRESSION
1631 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1632 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1633 $$=$2;new_variable($2,$3,1);
1635 FOR_IN_INIT : T_IDENTIFIER {
1639 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1640 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1642 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1643 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1645 $$ = code_append($$, $2);
1646 code_t*loopstart = $$ = abc_label($$);
1647 $$ = code_append($$, $4.c);
1648 code_t*myif = $$ = abc_iffalse($$, 0);
1649 $$ = code_append($$, $8);
1650 code_t*cont = $$ = abc_nop($$);
1651 $$ = code_append($$, $6);
1652 $$ = abc_jump($$, loopstart);
1653 code_t*out = $$ = abc_nop($$);
1654 breakjumpsto($$, $1.name, out);
1655 continuejumpsto($$, $1.name, cont);
1662 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1663 variable_t*var = find_variable($2);
1664 char*tmp1name = concat2($2, "__tmp1__");
1665 int it = new_variable(tmp1name, TYPE_INT, 0);
1666 char*tmp2name = concat2($2, "__array__");
1667 int array = new_variable(tmp1name, 0, 0);
1670 $$ = code_append($$, $4.c);
1671 $$ = abc_coerce_a($$);
1672 $$ = abc_setlocal($$, array);
1673 $$ = abc_pushbyte($$, 0);
1674 $$ = abc_setlocal($$, it);
1676 code_t*loopstart = $$ = abc_label($$);
1678 $$ = abc_hasnext2($$, array, it);
1679 code_t*myif = $$ = abc_iffalse($$, 0);
1680 $$ = abc_getlocal($$, array);
1681 $$ = abc_getlocal($$, it);
1683 $$ = abc_nextname($$);
1685 $$ = abc_nextvalue($$);
1686 $$ = converttype($$, 0, var->type);
1687 $$ = abc_setlocal($$, var->index);
1689 $$ = code_append($$, $6);
1690 $$ = abc_jump($$, loopstart);
1692 code_t*out = $$ = abc_nop($$);
1693 breakjumpsto($$, $1.name, out);
1694 continuejumpsto($$, $1.name, loopstart);
1705 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1709 code_t*myjmp = $$ = abc_jump($$, 0);
1710 code_t*loopstart = $$ = abc_label($$);
1711 $$ = code_append($$, $6);
1712 code_t*cont = $$ = abc_nop($$);
1713 myjmp->branch = cont;
1714 $$ = code_append($$, $4.c);
1715 $$ = abc_iftrue($$, loopstart);
1716 code_t*out = $$ = abc_nop($$);
1717 breakjumpsto($$, $1, out);
1718 continuejumpsto($$, $1, cont);
1724 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1726 code_t*loopstart = $$ = abc_label($$);
1727 $$ = code_append($$, $3);
1728 code_t*cont = $$ = abc_nop($$);
1729 $$ = code_append($$, $6.c);
1730 $$ = abc_iftrue($$, loopstart);
1731 code_t*out = $$ = abc_nop($$);
1732 breakjumpsto($$, $1, out);
1733 continuejumpsto($$, $1, cont);
1739 BREAK : "break" %prec prec_none {
1740 $$ = abc___break__(0, "");
1742 BREAK : "break" T_IDENTIFIER {
1743 $$ = abc___break__(0, $2);
1745 CONTINUE : "continue" %prec prec_none {
1746 $$ = abc___continue__(0, "");
1748 CONTINUE : "continue" T_IDENTIFIER {
1749 $$ = abc___continue__(0, $2);
1752 MAYBE_CASE_LIST : {$$=0;}
1753 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1754 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1755 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1756 CASE_LIST: CASE {$$=$1}
1757 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1759 CASE: "case" E ':' MAYBECODE {
1761 $$ = code_append($$, $2.c);
1762 code_t*j = $$ = abc_ifne($$, 0);
1763 $$ = code_append($$, $4);
1764 if($$->opcode != OPCODE___BREAK__) {
1765 $$ = abc___fallthrough__($$, "");
1767 code_t*e = $$ = abc_nop($$);
1770 DEFAULT: "default" ':' MAYBECODE {
1773 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1775 $$ = code_append($$, $7);
1776 code_t*out = $$ = abc_pop($$);
1777 breakjumpsto($$, $1, out);
1779 code_t*c = $$,*lastblock=0;
1781 if(c->opcode == OPCODE_IFNE) {
1782 if(!c->next) syntaxerror("internal error in fallthrough handling");
1784 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1786 c->opcode = OPCODE_JUMP;
1787 c->branch = lastblock;
1789 /* fall through end of switch */
1790 c->opcode = OPCODE_NOP;
1800 /* ------------ try / catch /finally ---------------- */
1802 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1804 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1805 multiname_t name = {QNAME, &name_ns, 0, $3};
1807 NEW(abc_exception_t, e)
1808 e->exc_type = sig2mname($4);
1809 e->var_name = multiname_clone(&name);
1813 int i = find_variable_safe($3)->index;
1814 e->target = c = abc_nop(0);
1815 c = abc_setlocal(c, i);
1816 c = code_append(c, $8);
1822 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
1828 NEW(abc_exception_t, e)
1829 e->exc_type = 0; //all exceptions
1830 e->var_name = 0; //no name
1833 e->to = code_append(e->to, $4);
1839 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
1840 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
1841 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1};
1842 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
1846 list_append($$.l,$2);
1847 $$.finally = $2->to;$2->to=0;
1850 CATCH_FINALLY_LIST: FINALLY {
1854 list_append($$.l,$1);
1855 $$.finally = $1->to;$1->to=0;
1859 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
1860 code_t*out = abc_nop(0);
1862 code_t*start = abc_nop(0);
1863 $$ = code_append(start, $4);
1864 if(!is_break_or_jump($4)) {
1865 $$ = abc_jump($$, out);
1867 code_t*end = $$ = abc_nop($$);
1871 tmp = new_variable("__finally__", 0, 0);
1873 abc_exception_list_t*l = $6.l;
1876 abc_exception_t*e = l->abc_exception;
1878 $$ = code_append($$, e->target);
1879 $$ = abc_jump($$, out);
1881 parserassert((ptroff_t)$6.finally);
1883 e->target = $$ = abc_nop($$);
1884 $$ = abc___rethrow__($$);
1892 $$ = code_append($$, out);
1894 $$ = insert_finally($$, $6.finally, tmp);
1896 list_concat(state->method->exceptions, $6.l);
1902 /* ------------ throw ------------------------------- */
1904 THROW : "throw" EXPRESSION {
1908 THROW : "throw" %prec prec_none {
1909 if(!state->exception_name)
1910 syntaxerror("re-throw only possible within a catch block");
1911 variable_t*v = find_variable(state->exception_name);
1913 $$=abc_getlocal($$, v->index);
1917 /* ------------ with -------------------------------- */
1919 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1921 $$ = abc_pushscope($$);
1922 $$ = code_append($$, $5);
1923 $$ = abc_popscope($$);
1926 /* ------------ packages and imports ---------------- */
1928 X_IDENTIFIER: T_IDENTIFIER
1929 | "package" {$$="package";}
1931 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1932 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1934 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1935 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1937 IMPORT : "import" QNAME {
1940 syntaxerror("Couldn't import class\n");
1941 state_has_imports();
1942 dict_put(state->imports, c->name, c);
1945 IMPORT : "import" PACKAGE '.' '*' {
1948 state_has_imports();
1949 list_append(state->wildcard_imports, i);
1953 /* ------------ classes and interfaces (header) -------------- */
1955 MAYBE_MODIFIERS : %prec above_function {$$=0;}
1956 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1957 MODIFIER_LIST : MODIFIER {$$=$1;}
1958 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1960 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1961 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1962 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1963 | KW_STATIC {$$=FLAG_STATIC;}
1964 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1965 | KW_FINAL {$$=FLAG_FINAL;}
1966 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1967 | KW_NATIVE {$$=FLAG_NATIVE;}
1968 | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1970 EXTENDS : {$$=registry_getobjectclass();}
1971 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1973 EXTENDS_LIST : {$$=list_new();}
1974 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1976 IMPLEMENTS_LIST : {$$=list_new();}
1977 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1979 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1980 EXTENDS IMPLEMENTS_LIST
1981 '{' {startclass($1,$3,$4,$5, 0);}
1983 '}' {endclass();$$=0;}
1985 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1987 '{' {startclass($1,$3,0,$4,1);}
1988 MAYBE_INTERFACE_BODY
1989 '}' {endclass();$$=0;}
1991 /* ------------ classes and interfaces (body) -------------- */
1994 MAYBE_CLASS_BODY : CLASS_BODY
1995 CLASS_BODY : CLASS_BODY_ITEM
1996 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1997 CLASS_BODY_ITEM : ';'
1998 CLASS_BODY_ITEM : SLOT_DECLARATION
1999 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2001 CLASS_BODY_ITEM : CODE_STATEMENT {
2002 code_t*c = state->cls->static_init;
2003 c = code_append(c, $1);
2004 state->cls->static_init = c;
2007 MAYBE_INTERFACE_BODY :
2008 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2009 INTERFACE_BODY : IDECLARATION
2010 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2012 IDECLARATION : "var" T_IDENTIFIER {
2013 syntaxerror("variable declarations not allowed in interfaces");
2015 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2017 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2018 syntaxerror("invalid method modifiers: interface methods always need to be public");
2020 startfunction(0,$1,$3,$4,&$6,$8);
2021 endfunction(0,$1,$3,$4,&$6,$8, 0);
2024 /* ------------ classes and interfaces (body, slots ) ------- */
2026 VARCONST: "var" | "const"
2028 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
2030 memberinfo_t* info = state->cls?
2031 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
2032 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
2035 info->flags = flags;
2038 namespace_t mname_ns = {flags2access(flags), ""};
2039 multiname_t mname = {QNAME, &mname_ns, 0, $3};
2041 trait_list_t**traits;
2045 traits = &global->init->traits;
2046 code = &global->init->method->body->code;
2047 } else if(flags&FLAG_STATIC) {
2049 traits = &state->cls->abc->static_traits;
2050 code = &state->cls->static_init;
2052 // instance variable
2053 traits = &state->cls->abc->traits;
2054 code = &state->cls->init;
2060 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2062 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2064 info->slot = t->slot_id;
2066 /* initalization code (if needed) */
2068 if($5.c && !is_pushundefined($5.c)) {
2069 c = abc_getlocal_0(c);
2070 c = code_append(c, $5.c);
2071 c = converttype(c, $5.t, $4);
2072 c = abc_setslot(c, t->slot_id);
2075 *code = code_append(*code, c);
2078 t->kind= TRAIT_CONST;
2084 /* ------------ constants -------------------------------------- */
2086 MAYBESTATICCONSTANT: {$$=0;}
2087 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2089 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2090 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2091 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2092 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2093 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
2094 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2095 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2096 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2097 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2099 /* ------------ classes and interfaces (body, functions) ------- */
2101 // non-vararg version
2103 memset(&$$,0,sizeof($$));
2105 MAYBE_PARAM_LIST: PARAM_LIST {
2110 MAYBE_PARAM_LIST: "..." PARAM {
2111 memset(&$$,0,sizeof($$));
2113 list_append($$.list, $2);
2115 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2118 list_append($$.list, $4);
2122 PARAM_LIST: PARAM_LIST ',' PARAM {
2124 list_append($$.list, $3);
2127 memset(&$$,0,sizeof($$));
2128 list_append($$.list, $1);
2131 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2132 $$ = malloc(sizeof(param_t));
2137 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2138 $$ = malloc(sizeof(param_t));
2140 $$->type = TYPE_ANY;
2143 GETSET : "get" {$$=$1;}
2147 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2148 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
2151 if(state->method->late_binding) {
2152 c = abc_getlocal_0(c);
2153 c = abc_pushscope(c);
2155 if(state->method->is_constructor && !state->method->has_super) {
2156 // call default constructor
2157 c = abc_getlocal_0(c);
2158 c = abc_constructsuper(c, 0);
2160 c = wrap_function(c, 0, $11);
2161 endfunction(0,$1,$3,$4,&$6,$8,c);
2165 MAYBE_IDENTIFIER: T_IDENTIFIER
2166 MAYBE_IDENTIFIER: {$$=0;}
2167 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
2169 syntaxerror("nested functions not supported yet");
2173 /* ------------- package + class ids --------------- */
2175 CLASS: T_IDENTIFIER {
2177 /* try current package */
2178 $$ = find_class($1);
2179 if(!$$) syntaxerror("Could not find class %s\n", $1);
2182 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2183 $$ = registry_findclass($1, $3);
2184 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
2188 QNAME: PACKAGEANDCLASS
2191 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
2192 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
2194 TYPE : QNAME {$$=$1;}
2195 | '*' {$$=registry_getanytype();}
2196 | "void" {$$=registry_getanytype();}
2198 | "String" {$$=registry_getstringclass();}
2199 | "int" {$$=registry_getintclass();}
2200 | "uint" {$$=registry_getuintclass();}
2201 | "Boolean" {$$=registry_getbooleanclass();}
2202 | "Number" {$$=registry_getnumberclass();}
2205 MAYBETYPE: ':' TYPE {$$=$2;}
2208 /* ----------function calls, delete, constructor calls ------ */
2210 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2211 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
2213 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2214 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2215 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2218 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2220 $$.cc = code_append($1.cc, $3.c);
2223 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2228 $$.c = abc_getglobalscope($$.c);
2229 $$.c = abc_getslot($$.c, $2->slot);
2231 $$.c = abc_findpropstrict2($$.c, &m);
2234 $$.c = code_append($$.c, $3.cc);
2237 $$.c = abc_construct($$.c, $3.len);
2239 $$.c = abc_constructprop2($$.c, &m, $3.len);
2243 /* TODO: use abc_call (for calling local variables),
2244 abc_callstatic (for calling own methods)
2247 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2250 if($$.c->opcode == OPCODE_COERCE_A) {
2251 $$.c = code_cutlast($$.c);
2253 code_t*paramcode = $3.cc;
2256 if($$.c->opcode == OPCODE_GETPROPERTY) {
2257 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2258 $$.c = code_cutlast($$.c);
2259 $$.c = code_append($$.c, paramcode);
2260 $$.c = abc_callproperty2($$.c, name, $3.len);
2261 multiname_destroy(name);
2262 } else if($$.c->opcode == OPCODE_GETSLOT) {
2263 int slot = (int)(ptroff_t)$$.c->data[0];
2264 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2265 if(t->kind!=TRAIT_METHOD) {
2266 //ok: flash allows to assign closures to members.
2268 multiname_t*name = t->name;
2269 $$.c = code_cutlast($$.c);
2270 $$.c = code_append($$.c, paramcode);
2271 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2272 $$.c = abc_callproperty2($$.c, name, $3.len);
2273 } else if($$.c->opcode == OPCODE_GETSUPER) {
2274 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2275 $$.c = code_cutlast($$.c);
2276 $$.c = code_append($$.c, paramcode);
2277 $$.c = abc_callsuper2($$.c, name, $3.len);
2278 multiname_destroy(name);
2280 $$.c = abc_getlocal_0($$.c);
2281 $$.c = code_append($$.c, paramcode);
2282 $$.c = abc_call($$.c, $3.len);
2287 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2288 $$.t = $1.t->function->return_type;
2290 $$.c = abc_coerce_a($$.c);
2295 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2296 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2297 if(!state->method) syntaxerror("super() not allowed outside of a function");
2298 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2301 $$.c = abc_getlocal_0($$.c);
2303 $$.c = code_append($$.c, $3.cc);
2305 this is dependent on the control path, check this somewhere else
2306 if(state->method->has_super)
2307 syntaxerror("constructor may call super() only once");
2309 state->method->has_super = 1;
2310 $$.c = abc_constructsuper($$.c, $3.len);
2311 $$.c = abc_pushundefined($$.c);
2315 DELETE: "delete" E {
2317 if($$.c->opcode == OPCODE_COERCE_A) {
2318 $$.c = code_cutlast($$.c);
2320 multiname_t*name = 0;
2321 if($$.c->opcode == OPCODE_GETPROPERTY) {
2322 $$.c->opcode = OPCODE_DELETEPROPERTY;
2323 } else if($$.c->opcode == OPCODE_GETSLOT) {
2324 int slot = (int)(ptroff_t)$$.c->data[0];
2325 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2326 $$.c = code_cutlast($$.c);
2327 $$.c = abc_deleteproperty2($$.c, name);
2329 $$.c = abc_getlocal_0($$.c);
2330 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2331 $$.c = abc_deleteproperty2($$.c, &m);
2333 $$.t = TYPE_BOOLEAN;
2336 RETURN: "return" %prec prec_none {
2337 $$ = abc_returnvoid(0);
2339 RETURN: "return" EXPRESSION {
2341 $$ = abc_returnvalue($$);
2344 // ----------------------- expression types -------------------------------------
2346 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2347 EXPRESSION : E %prec below_minus {$$ = $1;}
2348 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2350 $$.c = cut_last_push($$.c);
2351 $$.c = code_append($$.c,$3.c);
2354 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2355 $$=cut_last_push($1.c);
2358 // ----------------------- expression evaluation -------------------------------------
2360 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2361 //V : CONSTANT {$$ = 0;}
2363 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2364 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2365 //V : NEW {$$ = $1.c;}
2367 //V : DELETE {$$ = $1.c;}
2368 E : DELETE {$$ = $1;}
2372 namespace_t ns = {ACCESS_PACKAGE, ""};
2373 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2375 $$.c = abc_getlex2($$.c, &m);
2376 $$.c = abc_pushstring($$.c, $1.pattern);
2377 $$.c = abc_construct($$.c, 1);
2379 $$.c = abc_getlex2($$.c, &m);
2380 $$.c = abc_pushstring($$.c, $1.pattern);
2381 $$.c = abc_pushstring($$.c, $1.options);
2382 $$.c = abc_construct($$.c, 2);
2387 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2388 //MULTINAME(m, registry_getintclass());
2389 //$$.c = abc_coerce2($$.c, &m); // FIXME
2392 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2395 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2398 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2401 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2404 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2407 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2410 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2411 $$.t = TYPE_BOOLEAN;
2413 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2414 $$.t = TYPE_BOOLEAN;
2416 CONSTANT : "null" {$$.c = abc_pushnull(0);
2421 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2422 $$.t = TYPE_BOOLEAN;
2424 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2425 $$.t = TYPE_BOOLEAN;
2427 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2428 $$.t = TYPE_BOOLEAN;
2430 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2431 $$.t = TYPE_BOOLEAN;
2433 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2434 $$.t = TYPE_BOOLEAN;
2436 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2437 $$.t = TYPE_BOOLEAN;
2439 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2440 $$.t = TYPE_BOOLEAN;
2442 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2443 $$.t = TYPE_BOOLEAN;
2446 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2448 $$.c = converttype($$.c, $1.t, $$.t);
2449 $$.c = abc_dup($$.c);
2450 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2451 $$.c = cut_last_push($$.c);
2452 $$.c = code_append($$.c,$3.c);
2453 $$.c = converttype($$.c, $3.t, $$.t);
2454 code_t*label = $$.c = abc_label($$.c);
2455 jmp->branch = label;
2458 $$.t = join_types($1.t, $3.t, 'A');
2459 /*printf("%08x:\n",$1.t);
2460 code_dump($1.c, 0, 0, "", stdout);
2461 printf("%08x:\n",$3.t);
2462 code_dump($3.c, 0, 0, "", stdout);
2463 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2465 $$.c = converttype($$.c, $1.t, $$.t);
2466 $$.c = abc_dup($$.c);
2467 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2468 $$.c = cut_last_push($$.c);
2469 $$.c = code_append($$.c,$3.c);
2470 $$.c = converttype($$.c, $3.t, $$.t);
2471 code_t*label = $$.c = abc_label($$.c);
2472 jmp->branch = label;
2475 E : '!' E {$$.c=$2.c;
2476 $$.c = abc_not($$.c);
2477 $$.t = TYPE_BOOLEAN;
2480 E : '~' E {$$.c=$2.c;
2481 $$.c = abc_bitnot($$.c);
2485 E : E '&' E {$$.c = code_append($1.c,$3.c);
2486 $$.c = abc_bitand($$.c);
2490 E : E '^' E {$$.c = code_append($1.c,$3.c);
2491 $$.c = abc_bitxor($$.c);
2495 E : E '|' E {$$.c = code_append($1.c,$3.c);
2496 $$.c = abc_bitor($$.c);
2500 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2501 $$.c = abc_rshift($$.c);
2504 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2505 $$.c = abc_urshift($$.c);
2508 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2509 $$.c = abc_lshift($$.c);
2513 E : E '/' E {$$.c = code_append($1.c,$3.c);
2514 $$.c = abc_divide($$.c);
2517 E : E '%' E {$$.c = code_append($1.c,$3.c);
2518 $$.c = abc_modulo($$.c);
2521 E : E '+' E {$$.c = code_append($1.c,$3.c);
2522 if(BOTH_INT($1.t, $3.t)) {
2523 $$.c = abc_add_i($$.c);
2526 $$.c = abc_add($$.c);
2527 $$.t = join_types($1.t,$3.t,'+');
2530 E : E '-' E {$$.c = code_append($1.c,$3.c);
2531 if(BOTH_INT($1.t,$3.t)) {
2532 $$.c = abc_subtract_i($$.c);
2535 $$.c = abc_subtract($$.c);
2539 E : E '*' E {$$.c = code_append($1.c,$3.c);
2540 if(BOTH_INT($1.t,$3.t)) {
2541 $$.c = abc_multiply_i($$.c);
2544 $$.c = abc_multiply($$.c);
2549 E : E "in" E {$$.c = code_append($1.c,$3.c);
2550 $$.c = abc_in($$.c);
2551 $$.t = TYPE_BOOLEAN;
2554 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2555 if(use_astype && TYPE_IS_CLASS($3.t)) {
2556 MULTINAME(m,$3.t->cls);
2557 $$.c = abc_astype2($1.c, &m);
2560 $$.c = code_append($1.c, $3.c);
2561 $$.c = abc_astypelate($$.c);
2566 E : E "instanceof" E
2567 {$$.c = code_append($1.c, $3.c);
2568 $$.c = abc_instanceof($$.c);
2569 $$.t = TYPE_BOOLEAN;
2572 E : E "is" E {$$.c = code_append($1.c, $3.c);
2573 $$.c = abc_istypelate($$.c);
2574 $$.t = TYPE_BOOLEAN;
2577 E : "typeof" '(' E ')' {
2579 $$.c = abc_typeof($$.c);
2584 $$.c = cut_last_push($2.c);
2585 $$.c = abc_pushundefined($$.c);
2589 E : "void" { $$.c = abc_pushundefined(0);
2593 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2598 $$.c=abc_negate_i($$.c);
2601 $$.c=abc_negate($$.c);
2608 $$.c = code_append($$.c, $3.c);
2610 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2611 $$.c = abc_getproperty2($$.c, &m);
2612 $$.t = 0; // array elements have unknown type
2615 E : '[' MAYBE_EXPRESSION_LIST ']' {
2617 $$.c = code_append($$.c, $2.cc);
2618 $$.c = abc_newarray($$.c, $2.len);
2619 $$.t = registry_getarrayclass();
2622 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2623 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2625 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2627 $$.cc = code_append($$.cc, $1.c);
2628 $$.cc = code_append($$.cc, $3.c);
2631 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2634 $$.cc = code_append($$.cc, $3.c);
2635 $$.cc = code_append($$.cc, $5.c);
2640 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2642 $$.c = code_append($$.c, $2.cc);
2643 $$.c = abc_newobject($$.c, $2.len/2);
2644 $$.t = registry_getobjectclass();
2649 if(BOTH_INT($1.t,$3.t)) {
2650 c=abc_multiply_i(c);
2654 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2655 $$.c = toreadwrite($1.c, c, 0, 0);
2660 code_t*c = abc_modulo($3.c);
2661 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2662 $$.c = toreadwrite($1.c, c, 0, 0);
2666 code_t*c = abc_lshift($3.c);
2667 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2668 $$.c = toreadwrite($1.c, c, 0, 0);
2672 code_t*c = abc_rshift($3.c);
2673 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2674 $$.c = toreadwrite($1.c, c, 0, 0);
2678 code_t*c = abc_urshift($3.c);
2679 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2680 $$.c = toreadwrite($1.c, c, 0, 0);
2684 code_t*c = abc_divide($3.c);
2685 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2686 $$.c = toreadwrite($1.c, c, 0, 0);
2690 code_t*c = abc_bitor($3.c);
2691 c=converttype(c, TYPE_INT, $1.t);
2692 $$.c = toreadwrite($1.c, c, 0, 0);
2698 if(TYPE_IS_INT($1.t)) {
2702 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2705 $$.c = toreadwrite($1.c, c, 0, 0);
2708 E : E "-=" E { code_t*c = $3.c;
2709 if(TYPE_IS_INT($1.t)) {
2710 c=abc_subtract_i(c);
2713 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2716 $$.c = toreadwrite($1.c, c, 0, 0);
2719 E : E '=' E { code_t*c = 0;
2720 c = code_append(c, $3.c);
2721 c = converttype(c, $3.t, $1.t);
2722 $$.c = toreadwrite($1.c, c, 1, 0);
2726 E : E '?' E ':' E %prec below_assignment {
2727 $$.t = join_types($3.t,$5.t,'?');
2729 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2730 $$.c = code_append($$.c, $3.c);
2731 $$.c = converttype($$.c, $3.t, $$.t);
2732 code_t*j2 = $$.c = abc_jump($$.c, 0);
2733 $$.c = j1->branch = abc_label($$.c);
2734 $$.c = code_append($$.c, $5.c);
2735 $$.c = converttype($$.c, $3.t, $$.t);
2736 $$.c = j2->branch = abc_label($$.c);
2739 E : E "++" { code_t*c = 0;
2740 classinfo_t*type = $1.t;
2741 if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
2742 int nr = getlocalnr($1.c);
2743 code_free($1.c);$1.c=0;
2744 if(TYPE_IS_INT($1.t)) {
2745 $$.c = abc_getlocal(0, nr);
2746 $$.c = abc_inclocal_i($$.c, nr);
2747 } else if(TYPE_IS_NUMBER($1.t)) {
2748 $$.c = abc_getlocal(0, nr);
2749 $$.c = abc_inclocal($$.c, nr);
2750 } else syntaxerror("internal error");
2752 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2753 c=abc_increment_i(c);
2759 c=converttype(c, type, $1.t);
2760 $$.c = toreadwrite($1.c, c, 0, 1);
2765 // TODO: use inclocal, like with ++
2766 E : E "--" { code_t*c = 0;
2767 classinfo_t*type = $1.t;
2768 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2769 c=abc_decrement_i(c);
2775 c=converttype(c, type, $1.t);
2776 $$.c = toreadwrite($1.c, c, 0, 1);
2780 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2781 classinfo_t*type = $2.t;
2782 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2783 c=abc_increment_i(c);
2789 c=converttype(c, type, $2.t);
2790 $$.c = toreadwrite($2.c, c, 0, 0);
2794 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2795 classinfo_t*type = $2.t;
2796 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2797 c=abc_decrement_i(c);
2803 c=converttype(c, type, $2.t);
2804 $$.c = toreadwrite($2.c, c, 0, 0);
2808 E : "super" '.' T_IDENTIFIER
2809 { if(!state->cls->info)
2810 syntaxerror("super keyword not allowed outside a class");
2811 classinfo_t*t = state->cls->info->superclass;
2812 if(!t) t = TYPE_OBJECT;
2814 memberinfo_t*f = registry_findmember(t, $3, 1);
2815 namespace_t ns = flags2namespace(f->flags, "");
2816 MEMBER_MULTINAME(m, f, $3);
2818 $$.c = abc_getlocal_0($$.c);
2819 $$.c = abc_getsuper2($$.c, &m);
2820 $$.t = memberinfo_gettype(f);
2823 E : E '.' T_IDENTIFIER
2825 classinfo_t*t = $1.t;
2827 if(TYPE_IS_CLASS(t) && t->cls) {
2832 memberinfo_t*f = registry_findmember(t, $3, 1);
2834 if(f && !is_static != !(f->flags&FLAG_STATIC))
2836 if(f && f->slot && !noslot) {
2837 $$.c = abc_getslot($$.c, f->slot);
2839 MEMBER_MULTINAME(m, f, $3);
2840 $$.c = abc_getproperty2($$.c, &m);
2842 /* determine type */
2843 $$.t = memberinfo_gettype(f);
2845 $$.c = abc_coerce_a($$.c);
2847 /* when resolving a property on an unknown type, we do know the
2848 name of the property (and don't seem to need the package), but
2849 we need to make avm2 try out all access modes */
2850 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2851 $$.c = abc_getproperty2($$.c, &m);
2852 $$.c = abc_coerce_a($$.c);
2853 $$.t = registry_getanytype();
2857 VAR_READ : T_IDENTIFIER {
2864 /* look at variables */
2865 if((v = find_variable($1))) {
2866 // $1 is a local variable
2867 $$.c = abc_getlocal($$.c, v->index);
2870 /* look at current class' members */
2871 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2872 // $1 is a function in this class
2873 int var_is_static = (f->flags&FLAG_STATIC);
2874 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2875 if(var_is_static != i_am_static) {
2876 /* there doesn't seem to be any "static" way to access
2877 static properties of a class */
2878 state->method->late_binding = 1;
2880 namespace_t ns = {flags2access(f->flags), ""};
2881 multiname_t m = {QNAME, &ns, 0, $1};
2882 $$.c = abc_findpropstrict2($$.c, &m);
2883 $$.c = abc_getproperty2($$.c, &m);
2886 $$.c = abc_getlocal_0($$.c);
2887 $$.c = abc_getslot($$.c, f->slot);
2889 namespace_t ns = {flags2access(f->flags), ""};
2890 multiname_t m = {QNAME, &ns, 0, $1};
2891 $$.c = abc_getlocal_0($$.c);
2892 $$.c = abc_getproperty2($$.c, &m);
2895 if(f->kind == MEMBER_METHOD) {
2896 $$.t = TYPE_FUNCTION(f);
2901 /* look at actual classes, in the current package and imported */
2902 } else if((a = find_class($1))) {
2903 if(a->flags & FLAG_METHOD) {
2905 $$.c = abc_findpropstrict2($$.c, &m);
2906 $$.c = abc_getproperty2($$.c, &m);
2907 if(a->function->kind == MEMBER_METHOD) {
2908 $$.t = TYPE_FUNCTION(a->function);
2910 $$.t = a->function->type;
2914 $$.c = abc_getglobalscope($$.c);
2915 $$.c = abc_getslot($$.c, a->slot);
2918 $$.c = abc_getlex2($$.c, &m);
2920 $$.t = TYPE_CLASS(a);
2923 /* unknown object, let the avm2 resolve it */
2925 if(strcmp($1,"trace"))
2926 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
2927 state->method->late_binding = 1;
2929 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2932 $$.c = abc_findpropstrict2($$.c, &m);
2933 $$.c = abc_getproperty2($$.c, &m);
2938 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2939 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2940 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2942 // ----------------- namespaces -------------------------------------------------
2944 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2945 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2946 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2948 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}