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 code_t**cc = &global->init->method->body->code;
1548 *cc = code_append(*cc, $1);
1551 /* ------------ variables --------------------------- */
1553 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1554 | {$$.c=abc_pushundefined(0);
1558 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1559 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1561 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1562 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1564 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1566 if(variable_exists($1))
1567 syntaxerror("Variable %s already defined", $1);
1569 if(!is_subtype_of($3.t, $2)) {
1570 syntaxerror("Can't convert %s to %s", $3.t->name,
1574 int index = new_variable($1, $2, 1);
1577 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1579 $$ = converttype($$, $3.t, $2);
1580 $$ = abc_setlocal($$, index);
1582 $$ = defaultvalue(0, $2);
1583 $$ = abc_setlocal($$, index);
1586 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1588 $$ = abc_coerce_a($$);
1589 $$ = abc_setlocal($$, index);
1595 /* that's the default for a local register, anyway
1597 state->method->initcode = abc_pushundefined(state->method->initcode);
1598 state->method->initcode = abc_setlocal(state->method->initcode, index);
1600 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1603 /* ------------ control flow ------------------------- */
1605 MAYBEELSE: %prec below_else {$$ = code_new();}
1606 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1607 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1609 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1612 $$ = code_append($$, $4.c);
1613 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1615 $$ = code_append($$, $6);
1617 myjmp = $$ = abc_jump($$, 0);
1619 myif->branch = $$ = abc_nop($$);
1621 $$ = code_append($$, $7);
1622 myjmp->branch = $$ = abc_nop($$);
1628 FOR_INIT : {$$=code_new();}
1629 FOR_INIT : VARIABLE_DECLARATION
1630 FOR_INIT : VOIDEXPRESSION
1632 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1633 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1634 $$=$2;new_variable($2,$3,1);
1636 FOR_IN_INIT : T_IDENTIFIER {
1640 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1641 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1643 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1644 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1646 $$ = code_append($$, $2);
1647 code_t*loopstart = $$ = abc_label($$);
1648 $$ = code_append($$, $4.c);
1649 code_t*myif = $$ = abc_iffalse($$, 0);
1650 $$ = code_append($$, $8);
1651 code_t*cont = $$ = abc_nop($$);
1652 $$ = code_append($$, $6);
1653 $$ = abc_jump($$, loopstart);
1654 code_t*out = $$ = abc_nop($$);
1655 breakjumpsto($$, $1.name, out);
1656 continuejumpsto($$, $1.name, cont);
1663 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1664 variable_t*var = find_variable($2);
1665 char*tmp1name = concat2($2, "__tmp1__");
1666 int it = new_variable(tmp1name, TYPE_INT, 0);
1667 char*tmp2name = concat2($2, "__array__");
1668 int array = new_variable(tmp1name, 0, 0);
1671 $$ = code_append($$, $4.c);
1672 $$ = abc_coerce_a($$);
1673 $$ = abc_setlocal($$, array);
1674 $$ = abc_pushbyte($$, 0);
1675 $$ = abc_setlocal($$, it);
1677 code_t*loopstart = $$ = abc_label($$);
1679 $$ = abc_hasnext2($$, array, it);
1680 code_t*myif = $$ = abc_iffalse($$, 0);
1681 $$ = abc_getlocal($$, array);
1682 $$ = abc_getlocal($$, it);
1684 $$ = abc_nextname($$);
1686 $$ = abc_nextvalue($$);
1687 $$ = converttype($$, 0, var->type);
1688 $$ = abc_setlocal($$, var->index);
1690 $$ = code_append($$, $6);
1691 $$ = abc_jump($$, loopstart);
1693 code_t*out = $$ = abc_nop($$);
1694 breakjumpsto($$, $1.name, out);
1695 continuejumpsto($$, $1.name, loopstart);
1706 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1710 code_t*myjmp = $$ = abc_jump($$, 0);
1711 code_t*loopstart = $$ = abc_label($$);
1712 $$ = code_append($$, $6);
1713 code_t*cont = $$ = abc_nop($$);
1714 myjmp->branch = cont;
1715 $$ = code_append($$, $4.c);
1716 $$ = abc_iftrue($$, loopstart);
1717 code_t*out = $$ = abc_nop($$);
1718 breakjumpsto($$, $1, out);
1719 continuejumpsto($$, $1, cont);
1725 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1727 code_t*loopstart = $$ = abc_label($$);
1728 $$ = code_append($$, $3);
1729 code_t*cont = $$ = abc_nop($$);
1730 $$ = code_append($$, $6.c);
1731 $$ = abc_iftrue($$, loopstart);
1732 code_t*out = $$ = abc_nop($$);
1733 breakjumpsto($$, $1, out);
1734 continuejumpsto($$, $1, cont);
1740 BREAK : "break" %prec prec_none {
1741 $$ = abc___break__(0, "");
1743 BREAK : "break" T_IDENTIFIER {
1744 $$ = abc___break__(0, $2);
1746 CONTINUE : "continue" %prec prec_none {
1747 $$ = abc___continue__(0, "");
1749 CONTINUE : "continue" T_IDENTIFIER {
1750 $$ = abc___continue__(0, $2);
1753 MAYBE_CASE_LIST : {$$=0;}
1754 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1755 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1756 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1757 CASE_LIST: CASE {$$=$1}
1758 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1760 CASE: "case" E ':' MAYBECODE {
1762 $$ = code_append($$, $2.c);
1763 code_t*j = $$ = abc_ifne($$, 0);
1764 $$ = code_append($$, $4);
1765 if($$->opcode != OPCODE___BREAK__) {
1766 $$ = abc___fallthrough__($$, "");
1768 code_t*e = $$ = abc_nop($$);
1771 DEFAULT: "default" ':' MAYBECODE {
1774 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1776 $$ = code_append($$, $7);
1777 code_t*out = $$ = abc_pop($$);
1778 breakjumpsto($$, $1, out);
1780 code_t*c = $$,*lastblock=0;
1782 if(c->opcode == OPCODE_IFNE) {
1783 if(!c->next) syntaxerror("internal error in fallthrough handling");
1785 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1787 c->opcode = OPCODE_JUMP;
1788 c->branch = lastblock;
1790 /* fall through end of switch */
1791 c->opcode = OPCODE_NOP;
1801 /* ------------ try / catch /finally ---------------- */
1803 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1805 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1806 multiname_t name = {QNAME, &name_ns, 0, $3};
1808 NEW(abc_exception_t, e)
1809 e->exc_type = sig2mname($4);
1810 e->var_name = multiname_clone(&name);
1814 int i = find_variable_safe($3)->index;
1815 e->target = c = abc_nop(0);
1816 c = abc_setlocal(c, i);
1817 c = code_append(c, $8);
1823 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
1829 NEW(abc_exception_t, e)
1830 e->exc_type = 0; //all exceptions
1831 e->var_name = 0; //no name
1834 e->to = code_append(e->to, $4);
1840 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
1841 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
1842 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1};
1843 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
1847 list_append($$.l,$2);
1848 $$.finally = $2->to;$2->to=0;
1851 CATCH_FINALLY_LIST: FINALLY {
1855 list_append($$.l,$1);
1856 $$.finally = $1->to;$1->to=0;
1860 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
1861 code_t*out = abc_nop(0);
1863 code_t*start = abc_nop(0);
1864 $$ = code_append(start, $4);
1865 if(!is_break_or_jump($4)) {
1866 $$ = abc_jump($$, out);
1868 code_t*end = $$ = abc_nop($$);
1872 tmp = new_variable("__finally__", 0, 0);
1874 abc_exception_list_t*l = $6.l;
1877 abc_exception_t*e = l->abc_exception;
1879 $$ = code_append($$, e->target);
1880 $$ = abc_jump($$, out);
1882 parserassert((ptroff_t)$6.finally);
1884 e->target = $$ = abc_nop($$);
1885 $$ = abc___rethrow__($$);
1893 $$ = code_append($$, out);
1895 $$ = insert_finally($$, $6.finally, tmp);
1897 list_concat(state->method->exceptions, $6.l);
1903 /* ------------ throw ------------------------------- */
1905 THROW : "throw" EXPRESSION {
1909 THROW : "throw" %prec prec_none {
1910 if(!state->exception_name)
1911 syntaxerror("re-throw only possible within a catch block");
1912 variable_t*v = find_variable(state->exception_name);
1914 $$=abc_getlocal($$, v->index);
1918 /* ------------ with -------------------------------- */
1920 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1922 $$ = abc_pushscope($$);
1923 $$ = code_append($$, $5);
1924 $$ = abc_popscope($$);
1927 /* ------------ packages and imports ---------------- */
1929 X_IDENTIFIER: T_IDENTIFIER
1930 | "package" {$$="package";}
1932 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1933 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1935 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1936 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1938 IMPORT : "import" QNAME {
1941 syntaxerror("Couldn't import class\n");
1942 state_has_imports();
1943 dict_put(state->imports, c->name, c);
1946 IMPORT : "import" PACKAGE '.' '*' {
1949 state_has_imports();
1950 list_append(state->wildcard_imports, i);
1954 /* ------------ classes and interfaces (header) -------------- */
1956 MAYBE_MODIFIERS : %prec above_function {$$=0;}
1957 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1958 MODIFIER_LIST : MODIFIER {$$=$1;}
1959 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1961 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1962 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1963 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1964 | KW_STATIC {$$=FLAG_STATIC;}
1965 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1966 | KW_FINAL {$$=FLAG_FINAL;}
1967 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1968 | KW_NATIVE {$$=FLAG_NATIVE;}
1969 | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1971 EXTENDS : {$$=registry_getobjectclass();}
1972 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1974 EXTENDS_LIST : {$$=list_new();}
1975 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1977 IMPLEMENTS_LIST : {$$=list_new();}
1978 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1980 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1981 EXTENDS IMPLEMENTS_LIST
1982 '{' {startclass($1,$3,$4,$5, 0);}
1984 '}' {endclass();$$=0;}
1986 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1988 '{' {startclass($1,$3,0,$4,1);}
1989 MAYBE_INTERFACE_BODY
1990 '}' {endclass();$$=0;}
1992 /* ------------ classes and interfaces (body) -------------- */
1995 MAYBE_CLASS_BODY : CLASS_BODY
1996 CLASS_BODY : CLASS_BODY_ITEM
1997 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1998 CLASS_BODY_ITEM : ';'
1999 CLASS_BODY_ITEM : SLOT_DECLARATION
2000 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2002 CLASS_BODY_ITEM : CODE_STATEMENT {
2003 code_t*c = state->cls->static_init;
2004 c = code_append(c, $1);
2005 state->cls->static_init = c;
2008 MAYBE_INTERFACE_BODY :
2009 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2010 INTERFACE_BODY : IDECLARATION
2011 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2013 IDECLARATION : "var" T_IDENTIFIER {
2014 syntaxerror("variable declarations not allowed in interfaces");
2016 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2018 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2019 syntaxerror("invalid method modifiers: interface methods always need to be public");
2021 startfunction(0,$1,$3,$4,&$6,$8);
2022 endfunction(0,$1,$3,$4,&$6,$8, 0);
2025 /* ------------ classes and interfaces (body, slots ) ------- */
2027 VARCONST: "var" | "const"
2029 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
2031 memberinfo_t* info = state->cls?
2032 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
2033 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
2036 info->flags = flags;
2039 namespace_t mname_ns = {flags2access(flags), ""};
2040 multiname_t mname = {QNAME, &mname_ns, 0, $3};
2042 trait_list_t**traits;
2046 traits = &global->init->traits;
2047 code = &global->init->method->body->code;
2048 } else if(flags&FLAG_STATIC) {
2050 traits = &state->cls->abc->static_traits;
2051 code = &state->cls->static_init;
2053 // instance variable
2054 traits = &state->cls->abc->traits;
2055 code = &state->cls->init;
2061 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2063 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2065 info->slot = t->slot_id;
2067 /* initalization code (if needed) */
2069 if($5.c && !is_pushundefined($5.c)) {
2070 c = abc_getlocal_0(c);
2071 c = code_append(c, $5.c);
2072 c = converttype(c, $5.t, $4);
2073 c = abc_setslot(c, t->slot_id);
2076 *code = code_append(*code, c);
2079 t->kind= TRAIT_CONST;
2085 /* ------------ constants -------------------------------------- */
2087 MAYBESTATICCONSTANT: {$$=0;}
2088 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2090 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2091 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2092 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2093 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2094 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
2095 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2096 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2097 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2098 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2100 /* ------------ classes and interfaces (body, functions) ------- */
2102 // non-vararg version
2104 memset(&$$,0,sizeof($$));
2106 MAYBE_PARAM_LIST: PARAM_LIST {
2111 MAYBE_PARAM_LIST: "..." PARAM {
2112 memset(&$$,0,sizeof($$));
2114 list_append($$.list, $2);
2116 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2119 list_append($$.list, $4);
2123 PARAM_LIST: PARAM_LIST ',' PARAM {
2125 list_append($$.list, $3);
2128 memset(&$$,0,sizeof($$));
2129 list_append($$.list, $1);
2132 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2133 $$ = malloc(sizeof(param_t));
2138 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2139 $$ = malloc(sizeof(param_t));
2141 $$->type = TYPE_ANY;
2144 GETSET : "get" {$$=$1;}
2148 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2149 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
2152 if(state->method->late_binding) {
2153 c = abc_getlocal_0(c);
2154 c = abc_pushscope(c);
2156 if(state->method->is_constructor && !state->method->has_super) {
2157 // call default constructor
2158 c = abc_getlocal_0(c);
2159 c = abc_constructsuper(c, 0);
2161 c = wrap_function(c, 0, $11);
2162 endfunction(0,$1,$3,$4,&$6,$8,c);
2166 MAYBE_IDENTIFIER: T_IDENTIFIER
2167 MAYBE_IDENTIFIER: {$$=0;}
2168 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
2170 syntaxerror("nested functions not supported yet");
2174 /* ------------- package + class ids --------------- */
2176 CLASS: T_IDENTIFIER {
2178 /* try current package */
2179 $$ = find_class($1);
2180 if(!$$) syntaxerror("Could not find class %s\n", $1);
2183 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2184 $$ = registry_findclass($1, $3);
2185 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
2189 QNAME: PACKAGEANDCLASS
2192 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
2193 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
2195 TYPE : QNAME {$$=$1;}
2196 | '*' {$$=registry_getanytype();}
2197 | "void" {$$=registry_getanytype();}
2199 | "String" {$$=registry_getstringclass();}
2200 | "int" {$$=registry_getintclass();}
2201 | "uint" {$$=registry_getuintclass();}
2202 | "Boolean" {$$=registry_getbooleanclass();}
2203 | "Number" {$$=registry_getnumberclass();}
2206 MAYBETYPE: ':' TYPE {$$=$2;}
2209 /* ----------function calls, delete, constructor calls ------ */
2211 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2212 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
2214 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2215 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2216 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2219 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2221 $$.cc = code_append($1.cc, $3.c);
2224 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2229 $$.c = abc_getglobalscope($$.c);
2230 $$.c = abc_getslot($$.c, $2->slot);
2232 $$.c = abc_findpropstrict2($$.c, &m);
2235 $$.c = code_append($$.c, $3.cc);
2238 $$.c = abc_construct($$.c, $3.len);
2240 $$.c = abc_constructprop2($$.c, &m, $3.len);
2244 /* TODO: use abc_call (for calling local variables),
2245 abc_callstatic (for calling own methods)
2248 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2251 if($$.c->opcode == OPCODE_COERCE_A) {
2252 $$.c = code_cutlast($$.c);
2254 code_t*paramcode = $3.cc;
2257 if($$.c->opcode == OPCODE_GETPROPERTY) {
2258 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2259 $$.c = code_cutlast($$.c);
2260 $$.c = code_append($$.c, paramcode);
2261 $$.c = abc_callproperty2($$.c, name, $3.len);
2262 multiname_destroy(name);
2263 } else if($$.c->opcode == OPCODE_GETSLOT) {
2264 int slot = (int)(ptroff_t)$$.c->data[0];
2265 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2266 if(t->kind!=TRAIT_METHOD) {
2267 //ok: flash allows to assign closures to members.
2269 multiname_t*name = t->name;
2270 $$.c = code_cutlast($$.c);
2271 $$.c = code_append($$.c, paramcode);
2272 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2273 $$.c = abc_callproperty2($$.c, name, $3.len);
2274 } else if($$.c->opcode == OPCODE_GETSUPER) {
2275 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2276 $$.c = code_cutlast($$.c);
2277 $$.c = code_append($$.c, paramcode);
2278 $$.c = abc_callsuper2($$.c, name, $3.len);
2279 multiname_destroy(name);
2281 $$.c = abc_getlocal_0($$.c);
2282 $$.c = code_append($$.c, paramcode);
2283 $$.c = abc_call($$.c, $3.len);
2288 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2289 $$.t = $1.t->function->return_type;
2291 $$.c = abc_coerce_a($$.c);
2296 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2297 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2298 if(!state->method) syntaxerror("super() not allowed outside of a function");
2299 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2302 $$.c = abc_getlocal_0($$.c);
2304 $$.c = code_append($$.c, $3.cc);
2306 this is dependent on the control path, check this somewhere else
2307 if(state->method->has_super)
2308 syntaxerror("constructor may call super() only once");
2310 state->method->has_super = 1;
2311 $$.c = abc_constructsuper($$.c, $3.len);
2312 $$.c = abc_pushundefined($$.c);
2316 DELETE: "delete" E {
2318 if($$.c->opcode == OPCODE_COERCE_A) {
2319 $$.c = code_cutlast($$.c);
2321 multiname_t*name = 0;
2322 if($$.c->opcode == OPCODE_GETPROPERTY) {
2323 $$.c->opcode = OPCODE_DELETEPROPERTY;
2324 } else if($$.c->opcode == OPCODE_GETSLOT) {
2325 int slot = (int)(ptroff_t)$$.c->data[0];
2326 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2327 $$.c = code_cutlast($$.c);
2328 $$.c = abc_deleteproperty2($$.c, name);
2330 $$.c = abc_getlocal_0($$.c);
2331 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2332 $$.c = abc_deleteproperty2($$.c, &m);
2334 $$.t = TYPE_BOOLEAN;
2337 RETURN: "return" %prec prec_none {
2338 $$ = abc_returnvoid(0);
2340 RETURN: "return" EXPRESSION {
2342 $$ = abc_returnvalue($$);
2345 // ----------------------- expression types -------------------------------------
2347 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2348 EXPRESSION : E %prec below_minus {$$ = $1;}
2349 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2351 $$.c = cut_last_push($$.c);
2352 $$.c = code_append($$.c,$3.c);
2355 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2356 $$=cut_last_push($1.c);
2359 // ----------------------- expression evaluation -------------------------------------
2361 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2362 //V : CONSTANT {$$ = 0;}
2364 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2365 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2366 //V : NEW {$$ = $1.c;}
2368 //V : DELETE {$$ = $1.c;}
2369 E : DELETE {$$ = $1;}
2373 namespace_t ns = {ACCESS_PACKAGE, ""};
2374 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2376 $$.c = abc_getlex2($$.c, &m);
2377 $$.c = abc_pushstring($$.c, $1.pattern);
2378 $$.c = abc_construct($$.c, 1);
2380 $$.c = abc_getlex2($$.c, &m);
2381 $$.c = abc_pushstring($$.c, $1.pattern);
2382 $$.c = abc_pushstring($$.c, $1.options);
2383 $$.c = abc_construct($$.c, 2);
2388 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2389 //MULTINAME(m, registry_getintclass());
2390 //$$.c = abc_coerce2($$.c, &m); // FIXME
2393 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2396 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2399 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2402 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2405 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2408 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2411 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2412 $$.t = TYPE_BOOLEAN;
2414 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2415 $$.t = TYPE_BOOLEAN;
2417 CONSTANT : "null" {$$.c = abc_pushnull(0);
2422 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2423 $$.t = TYPE_BOOLEAN;
2425 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2426 $$.t = TYPE_BOOLEAN;
2428 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2429 $$.t = TYPE_BOOLEAN;
2431 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2432 $$.t = TYPE_BOOLEAN;
2434 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2435 $$.t = TYPE_BOOLEAN;
2437 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2438 $$.t = TYPE_BOOLEAN;
2440 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2441 $$.t = TYPE_BOOLEAN;
2443 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2444 $$.t = TYPE_BOOLEAN;
2447 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2449 $$.c = converttype($$.c, $1.t, $$.t);
2450 $$.c = abc_dup($$.c);
2451 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2452 $$.c = cut_last_push($$.c);
2453 $$.c = code_append($$.c,$3.c);
2454 $$.c = converttype($$.c, $3.t, $$.t);
2455 code_t*label = $$.c = abc_label($$.c);
2456 jmp->branch = label;
2459 $$.t = join_types($1.t, $3.t, 'A');
2460 /*printf("%08x:\n",$1.t);
2461 code_dump($1.c, 0, 0, "", stdout);
2462 printf("%08x:\n",$3.t);
2463 code_dump($3.c, 0, 0, "", stdout);
2464 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2466 $$.c = converttype($$.c, $1.t, $$.t);
2467 $$.c = abc_dup($$.c);
2468 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2469 $$.c = cut_last_push($$.c);
2470 $$.c = code_append($$.c,$3.c);
2471 $$.c = converttype($$.c, $3.t, $$.t);
2472 code_t*label = $$.c = abc_label($$.c);
2473 jmp->branch = label;
2476 E : '!' E {$$.c=$2.c;
2477 $$.c = abc_not($$.c);
2478 $$.t = TYPE_BOOLEAN;
2481 E : '~' E {$$.c=$2.c;
2482 $$.c = abc_bitnot($$.c);
2486 E : E '&' E {$$.c = code_append($1.c,$3.c);
2487 $$.c = abc_bitand($$.c);
2491 E : E '^' E {$$.c = code_append($1.c,$3.c);
2492 $$.c = abc_bitxor($$.c);
2496 E : E '|' E {$$.c = code_append($1.c,$3.c);
2497 $$.c = abc_bitor($$.c);
2501 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2502 $$.c = abc_rshift($$.c);
2505 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2506 $$.c = abc_urshift($$.c);
2509 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2510 $$.c = abc_lshift($$.c);
2514 E : E '/' E {$$.c = code_append($1.c,$3.c);
2515 $$.c = abc_divide($$.c);
2518 E : E '%' E {$$.c = code_append($1.c,$3.c);
2519 $$.c = abc_modulo($$.c);
2522 E : E '+' E {$$.c = code_append($1.c,$3.c);
2523 if(BOTH_INT($1.t, $3.t)) {
2524 $$.c = abc_add_i($$.c);
2527 $$.c = abc_add($$.c);
2528 $$.t = join_types($1.t,$3.t,'+');
2531 E : E '-' E {$$.c = code_append($1.c,$3.c);
2532 if(BOTH_INT($1.t,$3.t)) {
2533 $$.c = abc_subtract_i($$.c);
2536 $$.c = abc_subtract($$.c);
2540 E : E '*' E {$$.c = code_append($1.c,$3.c);
2541 if(BOTH_INT($1.t,$3.t)) {
2542 $$.c = abc_multiply_i($$.c);
2545 $$.c = abc_multiply($$.c);
2550 E : E "in" E {$$.c = code_append($1.c,$3.c);
2551 $$.c = abc_in($$.c);
2552 $$.t = TYPE_BOOLEAN;
2555 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2556 if(use_astype && TYPE_IS_CLASS($3.t)) {
2557 MULTINAME(m,$3.t->cls);
2558 $$.c = abc_astype2($1.c, &m);
2561 $$.c = code_append($1.c, $3.c);
2562 $$.c = abc_astypelate($$.c);
2567 E : E "instanceof" E
2568 {$$.c = code_append($1.c, $3.c);
2569 $$.c = abc_instanceof($$.c);
2570 $$.t = TYPE_BOOLEAN;
2573 E : E "is" E {$$.c = code_append($1.c, $3.c);
2574 $$.c = abc_istypelate($$.c);
2575 $$.t = TYPE_BOOLEAN;
2578 E : "typeof" '(' E ')' {
2580 $$.c = abc_typeof($$.c);
2585 $$.c = cut_last_push($2.c);
2586 $$.c = abc_pushundefined($$.c);
2590 E : "void" { $$.c = abc_pushundefined(0);
2594 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2599 $$.c=abc_negate_i($$.c);
2602 $$.c=abc_negate($$.c);
2609 $$.c = code_append($$.c, $3.c);
2611 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2612 $$.c = abc_getproperty2($$.c, &m);
2613 $$.t = 0; // array elements have unknown type
2616 E : '[' MAYBE_EXPRESSION_LIST ']' {
2618 $$.c = code_append($$.c, $2.cc);
2619 $$.c = abc_newarray($$.c, $2.len);
2620 $$.t = registry_getarrayclass();
2623 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2624 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2626 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2628 $$.cc = code_append($$.cc, $1.c);
2629 $$.cc = code_append($$.cc, $3.c);
2632 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2635 $$.cc = code_append($$.cc, $3.c);
2636 $$.cc = code_append($$.cc, $5.c);
2641 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2643 $$.c = code_append($$.c, $2.cc);
2644 $$.c = abc_newobject($$.c, $2.len/2);
2645 $$.t = registry_getobjectclass();
2650 if(BOTH_INT($1.t,$3.t)) {
2651 c=abc_multiply_i(c);
2655 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2656 $$.c = toreadwrite($1.c, c, 0, 0);
2661 code_t*c = abc_modulo($3.c);
2662 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2663 $$.c = toreadwrite($1.c, c, 0, 0);
2667 code_t*c = abc_lshift($3.c);
2668 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2669 $$.c = toreadwrite($1.c, c, 0, 0);
2673 code_t*c = abc_rshift($3.c);
2674 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2675 $$.c = toreadwrite($1.c, c, 0, 0);
2679 code_t*c = abc_urshift($3.c);
2680 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2681 $$.c = toreadwrite($1.c, c, 0, 0);
2685 code_t*c = abc_divide($3.c);
2686 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2687 $$.c = toreadwrite($1.c, c, 0, 0);
2691 code_t*c = abc_bitor($3.c);
2692 c=converttype(c, TYPE_INT, $1.t);
2693 $$.c = toreadwrite($1.c, c, 0, 0);
2699 if(TYPE_IS_INT($1.t)) {
2703 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2706 $$.c = toreadwrite($1.c, c, 0, 0);
2709 E : E "-=" E { code_t*c = $3.c;
2710 if(TYPE_IS_INT($1.t)) {
2711 c=abc_subtract_i(c);
2714 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2717 $$.c = toreadwrite($1.c, c, 0, 0);
2720 E : E '=' E { code_t*c = 0;
2721 c = code_append(c, $3.c);
2722 c = converttype(c, $3.t, $1.t);
2723 $$.c = toreadwrite($1.c, c, 1, 0);
2727 E : E '?' E ':' E %prec below_assignment {
2728 $$.t = join_types($3.t,$5.t,'?');
2730 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2731 $$.c = code_append($$.c, $3.c);
2732 $$.c = converttype($$.c, $3.t, $$.t);
2733 code_t*j2 = $$.c = abc_jump($$.c, 0);
2734 $$.c = j1->branch = abc_label($$.c);
2735 $$.c = code_append($$.c, $5.c);
2736 $$.c = converttype($$.c, $3.t, $$.t);
2737 $$.c = j2->branch = abc_label($$.c);
2740 E : E "++" { code_t*c = 0;
2741 classinfo_t*type = $1.t;
2742 if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
2743 int nr = getlocalnr($1.c);
2744 code_free($1.c);$1.c=0;
2745 if(TYPE_IS_INT($1.t)) {
2746 $$.c = abc_getlocal(0, nr);
2747 $$.c = abc_inclocal_i($$.c, nr);
2748 } else if(TYPE_IS_NUMBER($1.t)) {
2749 $$.c = abc_getlocal(0, nr);
2750 $$.c = abc_inclocal($$.c, nr);
2751 } else syntaxerror("internal error");
2753 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2754 c=abc_increment_i(c);
2760 c=converttype(c, type, $1.t);
2761 $$.c = toreadwrite($1.c, c, 0, 1);
2766 // TODO: use inclocal, like with ++
2767 E : E "--" { code_t*c = 0;
2768 classinfo_t*type = $1.t;
2769 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2770 c=abc_decrement_i(c);
2776 c=converttype(c, type, $1.t);
2777 $$.c = toreadwrite($1.c, c, 0, 1);
2781 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2782 classinfo_t*type = $2.t;
2783 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2784 c=abc_increment_i(c);
2790 c=converttype(c, type, $2.t);
2791 $$.c = toreadwrite($2.c, c, 0, 0);
2795 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2796 classinfo_t*type = $2.t;
2797 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2798 c=abc_decrement_i(c);
2804 c=converttype(c, type, $2.t);
2805 $$.c = toreadwrite($2.c, c, 0, 0);
2809 E : "super" '.' T_IDENTIFIER
2810 { if(!state->cls->info)
2811 syntaxerror("super keyword not allowed outside a class");
2812 classinfo_t*t = state->cls->info->superclass;
2813 if(!t) t = TYPE_OBJECT;
2815 memberinfo_t*f = registry_findmember(t, $3, 1);
2816 namespace_t ns = flags2namespace(f->flags, "");
2817 MEMBER_MULTINAME(m, f, $3);
2819 $$.c = abc_getlocal_0($$.c);
2820 $$.c = abc_getsuper2($$.c, &m);
2821 $$.t = memberinfo_gettype(f);
2824 E : E '.' T_IDENTIFIER
2826 classinfo_t*t = $1.t;
2828 if(TYPE_IS_CLASS(t) && t->cls) {
2833 memberinfo_t*f = registry_findmember(t, $3, 1);
2835 if(f && !is_static != !(f->flags&FLAG_STATIC))
2837 if(f && f->slot && !noslot) {
2838 $$.c = abc_getslot($$.c, f->slot);
2840 MEMBER_MULTINAME(m, f, $3);
2841 $$.c = abc_getproperty2($$.c, &m);
2843 /* determine type */
2844 $$.t = memberinfo_gettype(f);
2846 $$.c = abc_coerce_a($$.c);
2848 /* when resolving a property on an unknown type, we do know the
2849 name of the property (and don't seem to need the package), but
2850 we need to make avm2 try out all access modes */
2851 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2852 $$.c = abc_getproperty2($$.c, &m);
2853 $$.c = abc_coerce_a($$.c);
2854 $$.t = registry_getanytype();
2858 VAR_READ : T_IDENTIFIER {
2865 /* look at variables */
2866 if((v = find_variable($1))) {
2867 // $1 is a local variable
2868 $$.c = abc_getlocal($$.c, v->index);
2871 /* look at current class' members */
2872 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2873 // $1 is a function in this class
2874 int var_is_static = (f->flags&FLAG_STATIC);
2875 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2876 if(var_is_static != i_am_static) {
2877 /* there doesn't seem to be any "static" way to access
2878 static properties of a class */
2879 state->method->late_binding = 1;
2881 namespace_t ns = {flags2access(f->flags), ""};
2882 multiname_t m = {QNAME, &ns, 0, $1};
2883 $$.c = abc_findpropstrict2($$.c, &m);
2884 $$.c = abc_getproperty2($$.c, &m);
2887 $$.c = abc_getlocal_0($$.c);
2888 $$.c = abc_getslot($$.c, f->slot);
2890 namespace_t ns = {flags2access(f->flags), ""};
2891 multiname_t m = {QNAME, &ns, 0, $1};
2892 $$.c = abc_getlocal_0($$.c);
2893 $$.c = abc_getproperty2($$.c, &m);
2896 if(f->kind == MEMBER_METHOD) {
2897 $$.t = TYPE_FUNCTION(f);
2902 /* look at actual classes, in the current package and imported */
2903 } else if((a = find_class($1))) {
2904 if(a->flags & FLAG_METHOD) {
2906 $$.c = abc_findpropstrict2($$.c, &m);
2907 $$.c = abc_getproperty2($$.c, &m);
2908 if(a->function->kind == MEMBER_METHOD) {
2909 $$.t = TYPE_FUNCTION(a->function);
2911 $$.t = a->function->type;
2915 $$.c = abc_getglobalscope($$.c);
2916 $$.c = abc_getslot($$.c, a->slot);
2919 $$.c = abc_getlex2($$.c, &m);
2921 $$.t = TYPE_CLASS(a);
2924 /* unknown object, let the avm2 resolve it */
2926 if(strcmp($1,"trace"))
2927 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
2928 state->method->late_binding = 1;
2930 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2933 $$.c = abc_findpropstrict2($$.c, &m);
2934 $$.c = abc_getproperty2($$.c, &m);
2939 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2940 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2941 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2943 // ----------------- namespaces -------------------------------------------------
2945 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2946 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2947 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2949 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}