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);
258 static char* concat2(const char* t1, const char* t2)
262 char*text = malloc(l1+l2+1);
263 memcpy(text , t1, l1);
264 memcpy(text+l1, t2, l2);
268 static char* concat3(const char* t1, const char* t2, const char* t3)
273 char*text = malloc(l1+l2+l3+1);
274 memcpy(text , t1, l1);
275 memcpy(text+l1, t2, l2);
276 memcpy(text+l1+l2, t3, l3);
281 typedef struct _import {
285 DECLARE_LIST(import);
287 typedef struct _classstate {
293 char has_constructor;
296 typedef struct _methodstate {
303 abc_exception_list_t*exceptions;
306 typedef struct _state {
311 import_list_t*wildcard_imports;
313 char has_own_imports;
316 methodstate_t*method;
323 typedef struct _global {
330 static global_t*global = 0;
331 static state_t* state = 0;
335 #define MULTINAME(m,x) \
338 registry_fill_multiname(&m, &m##_ns, x);
340 #define MEMBER_MULTINAME(m,f,n) \
344 m##_ns = flags2namespace(f->flags, ""); \
347 m.namespace_set = 0; \
350 m.type = MULTINAME; \
352 m.namespace_set = &nopackage_namespace_set; \
356 /* warning: list length of namespace set is undefined */
357 #define MULTINAME_LATE(m, access, package) \
358 namespace_t m##_ns = {access, package}; \
359 namespace_set_t m##_nsset; \
360 namespace_list_t m##_l;m##_l.next = 0; \
361 m##_nsset.namespaces = &m##_l; \
362 m##_nsset = m##_nsset; \
363 m##_l.namespace = &m##_ns; \
364 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
366 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
367 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
368 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
369 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
370 static namespace_list_t nl4 = {&ns4,0};
371 static namespace_list_t nl3 = {&ns3,&nl4};
372 static namespace_list_t nl2 = {&ns2,&nl3};
373 static namespace_list_t nl1 = {&ns1,&nl2};
374 static namespace_set_t nopackage_namespace_set = {&nl1};
376 static void new_state()
379 state_t*oldstate = state;
381 memcpy(s, state, sizeof(state_t)); //shallow copy
383 s->imports = dict_new();
387 state->has_own_imports = 0;
388 state->vars = dict_new();
389 state->old = oldstate;
391 static void state_has_imports()
393 state->wildcard_imports = list_clone(state->wildcard_imports);
394 state->imports = dict_clone(state->imports);
395 state->has_own_imports = 1;
398 static void state_destroy(state_t*state)
400 if(state->has_own_imports) {
401 list_free(state->wildcard_imports);
402 dict_destroy(state->imports);state->imports=0;
404 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
405 dict_destroy(state->imports);state->imports=0;
409 for(t=0;t<state->vars->hashsize;t++) {
410 dictentry_t*e =state->vars->slots[t];
412 free(e->data);e->data=0;
416 dict_destroy(state->vars);state->vars=0;
422 static void old_state()
424 if(!state || !state->old)
425 syntaxerror("invalid nesting");
426 state_t*leaving = state;
429 state_destroy(leaving);
432 void initialize_parser()
434 global = rfx_calloc(sizeof(global_t));
435 global->file = abc_file_new();
436 global->file->flags &= ~ABCFILE_LAZY;
437 global->variable_count = 1;
438 global->init = abc_initscript(global->file);
439 code_t*c = global->init->method->body->code;
440 c = abc_getlocal_0(c);
441 c = abc_pushscope(c);
442 /*c = abc_findpropstrict(c, "[package]::trace");
443 c = abc_pushstring(c, "[entering global init function]");
444 c = abc_callpropvoid(c, "[package]::trace", 1);*/
445 global->init->method->body->code = c;
448 void initialize_file(char*filename)
451 state->package = filename;
455 if(!state || state->level!=1) {
456 syntaxerror("unexpected end of file");
458 state_destroy(state);state=0;
461 void* finish_parser()
463 code_t*c = global->init->method->body->code;
464 /*c = abc_findpropstrict(c, "[package]::trace");
465 c = abc_pushstring(c, "[leaving global init function]");
466 c = abc_callpropvoid(c, "[package]::trace", 1);*/
467 c = abc_returnvoid(c);
468 global->init->method->body->code = c;
473 static void xx_scopetest()
475 /* findpropstrict doesn't just return a scope object- it
476 also makes it "active" somehow. Push local_0 on the
477 scope stack and read it back with findpropstrict, it'll
478 contain properties like "trace". Trying to find the same
479 property on a "vanilla" local_0 yields only a "undefined" */
480 //c = abc_findpropstrict(c, "[package]::trace");
482 /*c = abc_getlocal_0(c);
483 c = abc_findpropstrict(c, "[package]::trace");
485 c = abc_setlocal_1(c);
487 c = abc_pushbyte(c, 0);
488 c = abc_setlocal_2(c);
490 code_t*xx = c = abc_label(c);
491 c = abc_findpropstrict(c, "[package]::trace");
492 c = abc_pushstring(c, "prop:");
493 c = abc_hasnext2(c, 1, 2);
495 c = abc_setlocal_3(c);
496 c = abc_callpropvoid(c, "[package]::trace", 2);
497 c = abc_getlocal_3(c);
499 c = abc_iftrue(c,xx);*/
503 typedef struct _variable {
509 static variable_t* find_variable(char*name)
515 v = dict_lookup(s->vars, name);
523 static variable_t* find_variable_safe(char*name)
525 variable_t* v = find_variable(name);
527 syntaxerror("undefined variable: %s", name);
530 static char variable_exists(char*name)
532 return dict_lookup(state->vars, name)!=0;
534 code_t*defaultvalue(code_t*c, classinfo_t*type);
535 static int new_variable(char*name, classinfo_t*type, char init)
538 v->index = global->variable_count;
542 dict_put(state->vars, name, v);
544 return global->variable_count++;
546 #define TEMPVARNAME "__as3_temp__"
547 static int gettempvar()
549 variable_t*v = find_variable(TEMPVARNAME);
552 return new_variable(TEMPVARNAME, 0, 0);
555 code_t* var_block(code_t*body)
561 for(t=0;t<state->vars->hashsize;t++) {
562 dictentry_t*e = state->vars->slots[t];
564 variable_t*v = (variable_t*)e->data;
565 if(v->type && v->init) {
566 c = defaultvalue(c, v->type);
567 c = abc_setlocal(c, v->index);
568 k = abc_kill(k, v->index);
578 if(x->opcode== OPCODE___BREAK__ ||
579 x->opcode== OPCODE___CONTINUE__) {
580 /* link kill code before break/continue */
581 code_t*e = code_dup(k);
582 code_t*s = code_start(e);
594 c = code_append(c, body);
595 c = code_append(c, k);
599 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
601 c = code_append(c, header);
602 c = code_append(c, var_block(body));
603 /* append return if necessary */
604 if(!c || c->opcode != OPCODE_RETURNVOID &&
605 c->opcode != OPCODE_RETURNVALUE) {
606 c = abc_returnvoid(c);
612 static void startpackage(char*name)
615 /*printf("entering package \"%s\"\n", name);*/
616 state->package = strdup(name);
617 global->variable_count = 1;
619 static void endpackage()
621 /*printf("leaving package \"%s\"\n", state->package);*/
623 //used e.g. in classinfo_register:
624 //free(state->package);state->package=0;
629 char*as3_globalclass=0;
630 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
633 syntaxerror("inner classes now allowed");
636 global->variable_count = 1;
637 state->cls = rfx_calloc(sizeof(classstate_t));
638 state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
641 classinfo_list_t*mlist=0;
643 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
644 syntaxerror("invalid modifier(s)");
646 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
647 syntaxerror("public and internal not supported at the same time.");
649 /* create the class name, together with the proper attributes */
653 if(!(flags&FLAG_PUBLIC) && !state->package) {
654 access = ACCESS_PRIVATE; package = current_filename;
655 } else if(!(flags&FLAG_PUBLIC) && state->package) {
656 access = ACCESS_PACKAGEINTERNAL; package = state->package;
657 } else if(state->package) {
658 access = ACCESS_PACKAGE; package = state->package;
660 syntaxerror("public classes only allowed inside a package");
663 if(registry_findclass(package, classname)) {
664 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
668 /* build info struct */
669 int num_interfaces = (list_length(implements));
670 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
671 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
673 classinfo_list_t*l = implements;
674 for(l=implements;l;l=l->next) {
675 state->cls->info->interfaces[pos++] = l->classinfo;
678 multiname_t*extends2 = sig2mname(extends);
680 MULTINAME(classname2,state->cls->info);
683 state->cls_init = abc_getlocal_0(state->cls_init);
684 state->cls_init = abc_constructsuper(state->cls_init, 0);
687 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
688 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
689 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
691 state->cls->info->flags |= CLASS_INTERFACE;
692 abc_class_interface(state->cls->abc);
695 abc_class_protectedNS(state->cls->abc, classname);
697 for(mlist=implements;mlist;mlist=mlist->next) {
698 MULTINAME(m, mlist->classinfo);
699 abc_class_add_interface(state->cls->abc, &m);
702 /* now write the construction code for this class */
703 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
705 abc_method_body_t*m = global->init->method->body;
706 __ getglobalscope(m);
707 classinfo_t*s = extends;
712 //TODO: take a look at the current scope stack, maybe
713 // we can re-use something
718 multiname_t*s2 = sig2mname(s);
720 multiname_destroy(s2);
722 __ pushscope(m); count++;
723 m->code = m->code->prev->prev; // invert
725 /* continue appending after last op end */
726 while(m->code && m->code->next) m->code = m->code->next;
728 /* TODO: if this is one of *our* classes, we can also
729 do a getglobalscope/getslot <nr> (which references
730 the init function's slots) */
732 __ getlex2(m, extends2);
734 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
735 stack is not the superclass */
736 __ pushscope(m);count++;
739 /* notice: we get a verify error #1107 if the top element on the scope
740 stack is not the global object */
742 __ pushscope(m);count++;
744 __ newclass(m,state->cls->abc);
748 __ setslot(m, slotindex);
750 /* flash.display.MovieClip handling */
751 if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
752 if(state->package && state->package[0]) {
753 as3_globalclass = concat3(state->package, ".", classname);
755 as3_globalclass = strdup(classname);
758 multiname_destroy(extends2);
761 static void endclass()
763 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
765 c = abc_getlocal_0(c);
766 c = abc_constructsuper(c, 0);
767 state->cls->init = code_append(state->cls->init, c);
769 if(!state->method->late_binding) {
770 // class initialization code uses late binding
772 c = abc_getlocal_0(c);
773 c = abc_pushscope(c);
774 state->cls->static_init = code_append(c, state->cls->static_init);
777 if(state->cls->init) {
778 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
779 m->body->code = wrap_function(0, state->cls->init, m->body->code);
781 if(state->cls->static_init) {
782 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
783 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
786 free(state->cls);state->cls=0;
787 free(state->method);state->method=0;
791 void check_code_for_break(code_t*c)
794 if(c->opcode == OPCODE___BREAK__) {
795 char*name = string_cstr(c->data[0]);
796 syntaxerror("Unresolved \"break %s\"", name);
798 if(c->opcode == OPCODE___CONTINUE__) {
799 char*name = string_cstr(c->data[0]);
800 syntaxerror("Unresolved \"continue %s\"", name);
807 static void check_constant_against_type(classinfo_t*t, constant_t*c)
809 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
810 if(TYPE_IS_NUMBER(t)) {
811 xassert(c->type == CONSTANT_FLOAT
812 || c->type == CONSTANT_INT
813 || c->type == CONSTANT_UINT);
814 } else if(TYPE_IS_UINT(t)) {
815 xassert(c->type == CONSTANT_UINT ||
816 (c->type == CONSTANT_INT && c->i>0));
817 } else if(TYPE_IS_INT(t)) {
818 xassert(c->type == CONSTANT_INT);
819 } else if(TYPE_IS_BOOLEAN(t)) {
820 xassert(c->type == CONSTANT_TRUE
821 || c->type == CONSTANT_FALSE);
826 static int flags2access(int flags)
829 if(flags&FLAG_PUBLIC) {
830 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
831 syntaxerror("invalid combination of access levels");
832 access = ACCESS_PACKAGE;
833 } else if(flags&FLAG_PRIVATE) {
834 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
835 syntaxerror("invalid combination of access levels");
836 access = ACCESS_PRIVATE;
837 } else if(flags&FLAG_PROTECTED) {
838 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
839 syntaxerror("invalid combination of access levels");
840 access = ACCESS_PROTECTED;
842 access = ACCESS_PACKAGEINTERNAL;
848 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
850 memberinfo_t*minfo = 0;
853 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
854 minfo->return_type = return_type;
855 } else if(getset != KW_GET && getset != KW_SET) {
857 if((minfo = registry_findmember(state->cls->info, name, 0))) {
858 if(minfo->parent == state->cls->info) {
859 syntaxerror("class already contains a member/method called '%s'", name);
860 } else if(!minfo->parent) {
861 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
863 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
864 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
867 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
868 minfo->return_type = return_type;
869 // getslot on a member slot only returns "undefined", so no need
870 // to actually store these
871 //state->minfo->slot = state->method->abc->method->trait->slot_id;
873 //class getter/setter
874 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
878 else if(params->list)
879 type = params->list->param->type;
880 // not sure wether to look into superclasses here, too
881 if((minfo=registry_findmember(state->cls->info, name, 0))) {
882 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
883 syntaxerror("class already contains a member or method called '%s'", name);
885 syntaxerror("getter/setter for '%s' already defined", name);
886 /* make a setter or getter into a getset */
891 if(type && minfo->type != type)
892 syntaxerror("different type in getter and setter");
894 minfo = memberinfo_register(state->cls->info, name, gs);
897 /* can't assign a slot as getter and setter might have different slots */
898 //minfo->slot = slot;
900 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
901 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
902 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
903 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
904 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
905 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
909 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
910 params_t*params, classinfo_t*return_type)
912 if(state->method && state->method->info) {
913 syntaxerror("not able to start another method scope");
916 global->variable_count = 0;
917 state->method = rfx_calloc(sizeof(methodstate_t));
918 state->method->has_super = 0;
921 state->method->is_constructor = !strcmp(state->cls->info->name,name);
922 state->cls->has_constructor |= state->method->is_constructor;
924 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
926 state->method->is_global = 1;
927 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
929 new_variable("globalscope", 0, 0);
932 /* state->vars is initialized by state_new */
935 for(p=params->list;p;p=p->next) {
936 new_variable(p->param->name, p->param->type, 0);
938 if(state->method->is_constructor)
939 name = "__as3_constructor__";
940 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
943 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
944 params_t*params, classinfo_t*return_type, code_t*body)
948 multiname_t*type2 = sig2mname(return_type);
950 if(state->method->is_constructor) {
951 f = abc_class_getconstructor(state->cls->abc, type2);
952 } else if(!state->method->is_global) {
953 namespace_t mname_ns = flags2namespace(flags, "");
954 multiname_t mname = {QNAME, &mname_ns, 0, name};
956 if(flags&FLAG_STATIC)
957 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
959 f = abc_class_method(state->cls->abc, type2, &mname);
960 slot = f->trait->slot_id;
962 namespace_t mname_ns = flags2namespace(flags, state->package);
963 multiname_t mname = {QNAME, &mname_ns, 0, name};
965 f = abc_method_new(global->file, type2, 1);
966 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
967 //abc_code_t*c = global->init->method->body->code;
969 //flash doesn't seem to allow us to access function slots
970 //state->method->info->slot = slot;
972 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
973 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
974 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
975 if(params->varargs) f->flags |= METHOD_NEED_REST;
979 for(p=params->list;p;p=p->next) {
980 if(params->varargs && !p->next) {
981 break; //varargs: omit last parameter in function signature
983 multiname_t*m = sig2mname(p->param->type);
984 list_append(f->parameters, m);
985 if(p->param->value) {
986 check_constant_against_type(p->param->type, p->param->value);
987 opt=1;list_append(f->optional_parameters, p->param->value);
989 syntaxerror("non-optional parameter not allowed after optional parameters");
992 check_code_for_break(body);
995 f->body->code = body;
996 f->body->exceptions = state->method->exceptions;
999 syntaxerror("interface methods can't have a method body");
1002 free(state->method);state->method=0;
1008 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1013 void breakjumpsto(code_t*c, char*name, code_t*jump)
1016 if(c->opcode == OPCODE___BREAK__) {
1017 string_t*name2 = c->data[0];
1018 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1019 c->opcode = OPCODE_JUMP;
1026 void continuejumpsto(code_t*c, char*name, code_t*jump)
1029 if(c->opcode == OPCODE___CONTINUE__) {
1030 string_t*name2 = c->data[0];
1031 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1032 c->opcode = OPCODE_JUMP;
1040 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1041 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1042 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1044 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1046 if(!type1 || !type2)
1047 return registry_getanytype();
1048 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1049 return registry_getanytype();
1052 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1061 return registry_getanytype();
1063 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1068 return abc_coerce_a(c);
1072 // cast an "any" type to a specific type. subject to
1073 // runtime exceptions
1074 return abc_coerce2(c, &m);
1077 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1078 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1079 // allow conversion between number types
1080 return abc_coerce2(c, &m);
1082 //printf("%s.%s\n", from.package, from.name);
1083 //printf("%s.%s\n", to.package, to.name);
1085 classinfo_t*supertype = from;
1087 if(supertype == to) {
1088 // target type is one of from's superclasses
1089 return abc_coerce2(c, &m);
1092 while(supertype->interfaces[t]) {
1093 if(supertype->interfaces[t]==to) {
1094 // target type is one of from's interfaces
1095 return abc_coerce2(c, &m);
1099 supertype = supertype->superclass;
1101 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1103 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1105 syntaxerror("can't convert type %s to %s", from->name, to->name);
1108 code_t*defaultvalue(code_t*c, classinfo_t*type)
1110 if(TYPE_IS_INT(type)) {
1111 c = abc_pushbyte(c, 0);
1112 } else if(TYPE_IS_UINT(type)) {
1113 c = abc_pushuint(c, 0);
1114 } else if(TYPE_IS_FLOAT(type)) {
1116 } else if(TYPE_IS_BOOLEAN(type)) {
1117 c = abc_pushfalse(c);
1119 //c = abc_pushundefined(c);
1121 c = abc_pushnull(c);
1123 c = abc_coerce2(c, &m);
1128 char is_pushundefined(code_t*c)
1130 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1133 void parserassert(int b)
1135 if(!b) syntaxerror("internal error: assertion failed");
1138 static classinfo_t* find_class(char*name)
1142 c = registry_findclass(state->package, name);
1145 /* try explicit imports */
1146 dictentry_t* e = dict_get_slot(state->imports, name);
1149 if(!strcmp(e->key, name)) {
1150 c = (classinfo_t*)e->data;
1156 /* try package.* imports */
1157 import_list_t*l = state->wildcard_imports;
1159 //printf("does package %s contain a class %s?\n", l->import->package, name);
1160 c = registry_findclass(l->import->package, name);
1165 /* try global package */
1166 c = registry_findclass("", name);
1169 /* try local "filename" package */
1170 c = registry_findclass(current_filename, name);
1176 static char is_getlocal(code_t*c)
1178 if(!c || c->prev || c->next)
1180 return(c->opcode == OPCODE_GETLOCAL
1181 || c->opcode == OPCODE_GETLOCAL_0
1182 || c->opcode == OPCODE_GETLOCAL_1
1183 || c->opcode == OPCODE_GETLOCAL_2
1184 || c->opcode == OPCODE_GETLOCAL_3);
1186 static int getlocalnr(code_t*c)
1188 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1189 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1190 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1191 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1192 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1193 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1196 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1200 [prefix code] [read instruction]
1204 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1207 if(in && in->opcode == OPCODE_COERCE_A) {
1208 in = code_cutlast(in);
1211 syntaxerror("internal error");
1213 /* chop off read instruction */
1217 prefix = r->prev;r->prev = 0;
1223 char use_temp_var = readbefore;
1225 /* generate the write instruction, and maybe append a dup to the prefix code */
1226 code_t* write = abc_nop(0);
1227 if(r->opcode == OPCODE_GETPROPERTY) {
1228 write->opcode = OPCODE_SETPROPERTY;
1229 multiname_t*m = (multiname_t*)r->data[0];
1230 write->data[0] = multiname_clone(m);
1231 if(m->type == QNAME || m->type == MULTINAME) {
1233 prefix = abc_dup(prefix); // we need the object, too
1236 } else if(m->type == MULTINAMEL) {
1238 /* dupping two values on the stack requires 5 operations and one register-
1239 couldn't adobe just have given us a dup2? */
1240 int temp = gettempvar();
1241 prefix = abc_setlocal(prefix, temp);
1242 prefix = abc_dup(prefix);
1243 prefix = abc_getlocal(prefix, temp);
1244 prefix = abc_swap(prefix);
1245 prefix = abc_getlocal(prefix, temp);
1247 prefix = abc_kill(prefix, temp);
1251 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1253 } else if(r->opcode == OPCODE_GETSLOT) {
1254 write->opcode = OPCODE_SETSLOT;
1255 write->data[0] = r->data[0];
1257 prefix = abc_dup(prefix); // we need the object, too
1260 } else if(r->opcode == OPCODE_GETLOCAL) {
1261 write->opcode = OPCODE_SETLOCAL;
1262 write->data[0] = r->data[0];
1263 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1264 write->opcode = OPCODE_SETLOCAL_0;
1265 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1266 write->opcode = OPCODE_SETLOCAL_1;
1267 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1268 write->opcode = OPCODE_SETLOCAL_2;
1269 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1270 write->opcode = OPCODE_SETLOCAL_3;
1273 syntaxerror("illegal lvalue: can't assign a value to this expression");
1280 /* with getproperty/getslot, we have to be extra careful not
1281 to execute the read code twice, as it might have side-effects
1282 (e.g. if the property is in fact a setter/getter combination)
1284 So read the value, modify it, and write it again,
1285 using prefix only once and making sure (by using a temporary
1286 register) that the return value is what we just wrote */
1287 temp = gettempvar();
1288 c = code_append(c, prefix);
1289 c = code_append(c, r);
1292 c = abc_setlocal(c, temp);
1294 c = code_append(c, middlepart);
1297 c = abc_setlocal(c, temp);
1299 c = code_append(c, write);
1300 c = abc_getlocal(c, temp);
1301 c = abc_kill(c, temp);
1303 /* if we're allowed to execute the read code twice *and*
1304 the middlepart doesn't modify the code, things are easier.
1306 code_t* r2 = code_dup(r);
1307 //c = code_append(c, prefix);
1308 parserassert(!prefix);
1309 c = code_append(c, r);
1310 c = code_append(c, middlepart);
1311 c = code_append(c, write);
1312 c = code_append(c, r2);
1315 /* even smaller version: overwrite the value without reading
1319 c = code_append(c, prefix);
1322 c = code_append(c, middlepart);
1323 c = code_append(c, write);
1324 c = code_append(c, r);
1326 temp = gettempvar();
1328 c = code_append(c, prefix);
1330 c = code_append(c, middlepart);
1332 c = abc_setlocal(c, temp);
1333 c = code_append(c, write);
1334 c = abc_getlocal(c, temp);
1335 c = abc_kill(c, temp);
1341 char is_break_or_jump(code_t*c)
1345 if(c->opcode == OPCODE_JUMP ||
1346 c->opcode == OPCODE___BREAK__ ||
1347 c->opcode == OPCODE___CONTINUE__ ||
1348 c->opcode == OPCODE_THROW ||
1349 c->opcode == OPCODE_RETURNVOID ||
1350 c->opcode == OPCODE_RETURNVALUE) {
1356 #define NEED_EXTRA_STACK_ARG
1357 static code_t* insert_finally(code_t*c, code_t*finally)
1359 code_t*finally_label = abc_nop(0);
1360 NEW(lookupswitch_t, l);
1366 code_t*prev = i->prev;
1367 if(i->opcode == OPCODE___CONTINUE__ ||
1368 i->opcode == OPCODE___BREAK__ ||
1369 i->opcode == OPCODE_RETURNVOID ||
1370 i->opcode == OPCODE_RETURNVALUE ||
1371 i->opcode == OPCODE___RETHROW__)
1373 if(i->opcode == OPCODE___RETHROW__)
1374 i->opcode = OPCODE_NOP;
1376 p = abc_pushbyte(p, count++);
1377 p = abc_jump(p, finally_label);
1378 code_t*target = p = abc_label(p);
1379 #ifdef NEED_EXTRA_STACK_ARG
1382 p->next = i;i->prev = p;
1383 list_append(l->targets, target);
1389 c = abc_pushbyte(c, -1);
1390 c = code_append(c, finally_label);
1391 c = code_append(c, finally);
1393 #ifdef NEED_EXTRA_STACK_ARG
1396 c = abc_lookupswitch(c, l);
1397 c = l->def = abc_label(c);
1398 #ifdef NEED_EXTRA_STACK_ARG
1410 /* ------------ code blocks / statements ---------------- */
1412 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1414 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1415 PROGRAM_CODE_LIST: PROGRAM_CODE
1416 | PROGRAM_CODE_LIST PROGRAM_CODE
1418 PROGRAM_CODE: PACKAGE_DECLARATION
1419 | INTERFACE_DECLARATION
1421 | FUNCTION_DECLARATION
1426 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1427 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1428 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1430 INPACKAGE_CODE: INTERFACE_DECLARATION
1432 | FUNCTION_DECLARATION
1437 MAYBECODE: CODE {$$=$1;}
1438 MAYBECODE: {$$=code_new();}
1440 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1441 CODE: CODEPIECE {$$=$1;}
1443 // code which also may appear outside a method
1444 CODE_STATEMENT: IMPORT
1446 CODE_STATEMENT: FOR_IN
1447 CODE_STATEMENT: WHILE
1448 CODE_STATEMENT: DO_WHILE
1449 CODE_STATEMENT: SWITCH
1451 CODE_STATEMENT: WITH
1453 CODE_STATEMENT: VOIDEXPRESSION
1455 // code which may appear anywhere
1456 CODEPIECE: ';' {$$=0;}
1457 CODEPIECE: CODE_STATEMENT
1458 CODEPIECE: VARIABLE_DECLARATION
1464 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1465 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1467 CODEBLOCK : '{' CODE '}' {$$=$2;}
1468 CODEBLOCK : '{' '}' {$$=0;}
1469 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1470 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1472 /* ------------ package init code ------------------- */
1474 PACKAGE_INITCODE: CODE_STATEMENT {
1475 if($1) as3_warning("code ignored");
1478 /* ------------ variables --------------------------- */
1480 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1481 | {$$.c=abc_pushundefined(0);
1485 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1486 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1488 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1489 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1491 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1493 if(variable_exists($1))
1494 syntaxerror("Variable %s already defined", $1);
1496 if(!is_subtype_of($3.t, $2)) {
1497 syntaxerror("Can't convert %s to %s", $3.t->name,
1501 int index = new_variable($1, $2, 1);
1504 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1506 $$ = converttype($$, $3.t, $2);
1507 $$ = abc_setlocal($$, index);
1509 $$ = defaultvalue(0, $2);
1510 $$ = abc_setlocal($$, index);
1513 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1515 $$ = abc_coerce_a($$);
1516 $$ = abc_setlocal($$, index);
1522 /* that's the default for a local register, anyway
1524 state->method->initcode = abc_pushundefined(state->method->initcode);
1525 state->method->initcode = abc_setlocal(state->method->initcode, index);
1527 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1530 /* ------------ control flow ------------------------- */
1532 MAYBEELSE: %prec below_else {$$ = code_new();}
1533 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1534 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1536 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1539 $$ = code_append($$, $4.c);
1540 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1542 $$ = code_append($$, $6);
1544 myjmp = $$ = abc_jump($$, 0);
1546 myif->branch = $$ = abc_nop($$);
1548 $$ = code_append($$, $7);
1549 myjmp->branch = $$ = abc_nop($$);
1555 FOR_INIT : {$$=code_new();}
1556 FOR_INIT : VARIABLE_DECLARATION
1557 FOR_INIT : VOIDEXPRESSION
1559 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1560 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1561 $$=$2;new_variable($2,$3,1);
1563 FOR_IN_INIT : T_IDENTIFIER {
1567 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1568 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1570 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1571 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1573 $$ = code_append($$, $2);
1574 code_t*loopstart = $$ = abc_label($$);
1575 $$ = code_append($$, $4.c);
1576 code_t*myif = $$ = abc_iffalse($$, 0);
1577 $$ = code_append($$, $8);
1578 code_t*cont = $$ = abc_nop($$);
1579 $$ = code_append($$, $6);
1580 $$ = abc_jump($$, loopstart);
1581 code_t*out = $$ = abc_nop($$);
1582 breakjumpsto($$, $1.name, out);
1583 continuejumpsto($$, $1.name, cont);
1590 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1591 variable_t*var = find_variable($2);
1592 char*tmp1name = concat2($2, "__tmp1__");
1593 int it = new_variable(tmp1name, TYPE_INT, 0);
1594 char*tmp2name = concat2($2, "__array__");
1595 int array = new_variable(tmp1name, 0, 0);
1598 $$ = code_append($$, $4.c);
1599 $$ = abc_coerce_a($$);
1600 $$ = abc_setlocal($$, array);
1601 $$ = abc_pushbyte($$, 0);
1602 $$ = abc_setlocal($$, it);
1604 code_t*loopstart = $$ = abc_label($$);
1606 $$ = abc_hasnext2($$, array, it);
1607 code_t*myif = $$ = abc_iffalse($$, 0);
1608 $$ = abc_getlocal($$, array);
1609 $$ = abc_getlocal($$, it);
1611 $$ = abc_nextname($$);
1613 $$ = abc_nextvalue($$);
1614 $$ = converttype($$, 0, var->type);
1615 $$ = abc_setlocal($$, var->index);
1617 $$ = code_append($$, $6);
1618 $$ = abc_jump($$, loopstart);
1620 code_t*out = $$ = abc_nop($$);
1621 breakjumpsto($$, $1.name, out);
1622 continuejumpsto($$, $1.name, loopstart);
1633 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1637 code_t*myjmp = $$ = abc_jump($$, 0);
1638 code_t*loopstart = $$ = abc_label($$);
1639 $$ = code_append($$, $6);
1640 code_t*cont = $$ = abc_nop($$);
1641 myjmp->branch = cont;
1642 $$ = code_append($$, $4.c);
1643 $$ = abc_iftrue($$, loopstart);
1644 code_t*out = $$ = abc_nop($$);
1645 breakjumpsto($$, $1, out);
1646 continuejumpsto($$, $1, cont);
1652 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1654 code_t*loopstart = $$ = abc_label($$);
1655 $$ = code_append($$, $3);
1656 code_t*cont = $$ = abc_nop($$);
1657 $$ = code_append($$, $6.c);
1658 $$ = abc_iftrue($$, loopstart);
1659 code_t*out = $$ = abc_nop($$);
1660 breakjumpsto($$, $1, out);
1661 continuejumpsto($$, $1, cont);
1667 BREAK : "break" %prec prec_none {
1668 $$ = abc___break__(0, "");
1670 BREAK : "break" T_IDENTIFIER {
1671 $$ = abc___break__(0, $2);
1673 CONTINUE : "continue" %prec prec_none {
1674 $$ = abc___continue__(0, "");
1676 CONTINUE : "continue" T_IDENTIFIER {
1677 $$ = abc___continue__(0, $2);
1680 MAYBE_CASE_LIST : {$$=0;}
1681 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1682 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1683 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1684 CASE_LIST: CASE {$$=$1}
1685 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1687 CASE: "case" E ':' MAYBECODE {
1689 $$ = code_append($$, $2.c);
1690 code_t*j = $$ = abc_ifne($$, 0);
1691 $$ = code_append($$, $4);
1692 if($$->opcode != OPCODE___BREAK__) {
1693 $$ = abc___fallthrough__($$, "");
1695 code_t*e = $$ = abc_nop($$);
1698 DEFAULT: "default" ':' MAYBECODE {
1701 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1703 $$ = code_append($$, $7);
1704 code_t*out = $$ = abc_pop($$);
1705 breakjumpsto($$, $1, out);
1707 code_t*c = $$,*lastblock=0;
1709 if(c->opcode == OPCODE_IFNE) {
1710 if(!c->next) syntaxerror("internal error in fallthrough handling");
1712 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1714 c->opcode = OPCODE_JUMP;
1715 c->branch = lastblock;
1717 /* fall through end of switch */
1718 c->opcode = OPCODE_NOP;
1728 /* ------------ try / catch /finally ---------------- */
1730 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1732 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1733 multiname_t name = {QNAME, &name_ns, 0, $3};
1735 NEW(abc_exception_t, e)
1736 e->exc_type = sig2mname($4);
1737 e->var_name = multiname_clone(&name);
1741 int i = find_variable_safe($3)->index;
1742 e->target = c = abc_setlocal(0, i);
1743 c = code_append(c, $8);
1749 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
1750 NEW(abc_exception_t, e)
1751 e->exc_type = 0; //all exceptions
1752 e->var_name = 0; //no name
1755 e->to = var_block($4);
1759 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
1760 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
1761 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1};
1762 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
1763 $$ = $1;list_append($$.l,$2);
1764 $$.finally = $2->to;$2->to=0;
1766 CATCH_FINALLY_LIST: FINALLY {
1767 $$.l=list_new();list_append($$.l,$1);
1768 $$.finally = $1->to;$1->to=0;
1771 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
1772 code_t*start = abc_nop(0);
1773 code_t*end = $$ = code_append(start, $4);
1774 code_t*out = abc_nop(0);
1776 if(!is_break_or_jump($4)) {
1777 end = $$ = abc_jump($$, out);
1780 abc_exception_list_t*l = $6.l;
1783 abc_exception_t*e = l->abc_exception;
1785 $$ = code_append($$, e->target);
1786 $$ = abc_jump($$, out);
1789 int tmp = new_variable("__finally__", 0, 0);
1791 $$ = abc_coerce_a($$);
1792 $$ = abc_setlocal($$, tmp);
1793 $$ = abc___rethrow__($$);
1794 $$ = abc_getlocal($$, tmp);
1803 $$ = code_append($$, out);
1805 $$ = insert_finally($$, $6.finally);
1807 list_concat(state->method->exceptions, $6.l);
1813 /* ------------ throw ------------------------------- */
1815 THROW : "throw" EXPRESSION {
1819 THROW : "throw" %prec prec_none {
1820 if(!state->exception_name)
1821 syntaxerror("re-throw only possible within a catch block");
1822 variable_t*v = find_variable(state->exception_name);
1824 $$=abc_getlocal($$, v->index);
1828 /* ------------ with -------------------------------- */
1830 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1832 $$ = abc_pushscope($$);
1833 $$ = code_append($$, $5);
1834 $$ = abc_popscope($$);
1837 /* ------------ packages and imports ---------------- */
1839 X_IDENTIFIER: T_IDENTIFIER
1840 | "package" {$$="package";}
1842 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1843 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1845 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1846 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1848 IMPORT : "import" QNAME {
1851 syntaxerror("Couldn't import class\n");
1852 state_has_imports();
1853 dict_put(state->imports, c->name, c);
1856 IMPORT : "import" PACKAGE '.' '*' {
1859 state_has_imports();
1860 list_append(state->wildcard_imports, i);
1864 /* ------------ classes and interfaces (header) -------------- */
1866 MAYBE_MODIFIERS : %prec above_function {$$=0;}
1867 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1868 MODIFIER_LIST : MODIFIER {$$=$1;}
1869 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1871 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1872 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1873 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1874 | KW_STATIC {$$=FLAG_STATIC;}
1875 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1876 | KW_FINAL {$$=FLAG_FINAL;}
1877 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1878 | KW_NATIVE {$$=FLAG_NATIVE;}
1879 | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1881 EXTENDS : {$$=registry_getobjectclass();}
1882 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1884 EXTENDS_LIST : {$$=list_new();}
1885 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1887 IMPLEMENTS_LIST : {$$=list_new();}
1888 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1890 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1891 EXTENDS IMPLEMENTS_LIST
1892 '{' {startclass($1,$3,$4,$5, 0);}
1894 '}' {endclass();$$=0;}
1896 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1898 '{' {startclass($1,$3,0,$4,1);}
1899 MAYBE_INTERFACE_BODY
1900 '}' {endclass();$$=0;}
1902 /* ------------ classes and interfaces (body) -------------- */
1905 MAYBE_CLASS_BODY : CLASS_BODY
1906 CLASS_BODY : CLASS_BODY_ITEM
1907 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1908 CLASS_BODY_ITEM : ';'
1909 CLASS_BODY_ITEM : SLOT_DECLARATION
1910 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1912 CLASS_BODY_ITEM : CODE_STATEMENT {
1913 code_t*c = state->cls->static_init;
1914 c = code_append(c, $1);
1915 state->cls->static_init = c;
1918 MAYBE_INTERFACE_BODY :
1919 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1920 INTERFACE_BODY : IDECLARATION
1921 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1923 IDECLARATION : "var" T_IDENTIFIER {
1924 syntaxerror("variable declarations not allowed in interfaces");
1926 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1928 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
1929 syntaxerror("invalid method modifiers: interface methods always need to be public");
1931 startfunction(0,$1,$3,$4,&$6,$8);
1932 endfunction(0,$1,$3,$4,&$6,$8, 0);
1935 /* ------------ classes and interfaces (body, slots ) ------- */
1937 VARCONST: "var" | "const"
1939 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1941 memberinfo_t* info = state->cls?
1942 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1943 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1946 info->flags = flags;
1949 namespace_t mname_ns = {flags2access(flags), ""};
1950 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1952 trait_list_t**traits;
1956 traits = &global->init->traits;
1957 code = &global->init->method->body->code;
1958 } else if(flags&FLAG_STATIC) {
1960 traits = &state->cls->abc->static_traits;
1961 code = &state->cls->static_init;
1963 // instance variable
1964 traits = &state->cls->abc->traits;
1965 code = &state->cls->init;
1971 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1973 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1975 info->slot = t->slot_id;
1977 /* initalization code (if needed) */
1979 if($5.c && !is_pushundefined($5.c)) {
1980 c = abc_getlocal_0(c);
1981 c = code_append(c, $5.c);
1982 c = converttype(c, $5.t, $4);
1983 c = abc_setslot(c, t->slot_id);
1986 *code = code_append(*code, c);
1989 t->kind= TRAIT_CONST;
1995 /* ------------ constants -------------------------------------- */
1997 MAYBESTATICCONSTANT: {$$=0;}
1998 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2000 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2001 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2002 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2003 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2004 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
2005 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2006 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2007 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2008 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2010 /* ------------ classes and interfaces (body, functions) ------- */
2012 // non-vararg version
2014 memset(&$$,0,sizeof($$));
2016 MAYBE_PARAM_LIST: PARAM_LIST {
2021 MAYBE_PARAM_LIST: "..." PARAM {
2022 memset(&$$,0,sizeof($$));
2024 list_append($$.list, $2);
2026 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2029 list_append($$.list, $4);
2033 PARAM_LIST: PARAM_LIST ',' PARAM {
2035 list_append($$.list, $3);
2038 memset(&$$,0,sizeof($$));
2039 list_append($$.list, $1);
2042 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2043 $$ = malloc(sizeof(param_t));
2048 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2049 $$ = malloc(sizeof(param_t));
2051 $$->type = TYPE_ANY;
2054 GETSET : "get" {$$=$1;}
2058 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2059 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
2062 if(state->method->late_binding) {
2063 c = abc_getlocal_0(c);
2064 c = abc_pushscope(c);
2066 if(state->method->is_constructor && !state->method->has_super) {
2067 // call default constructor
2068 c = abc_getlocal_0(c);
2069 c = abc_constructsuper(c, 0);
2071 c = wrap_function(c, 0, $11);
2072 endfunction(0,$1,$3,$4,&$6,$8,c);
2076 MAYBE_IDENTIFIER: T_IDENTIFIER
2077 MAYBE_IDENTIFIER: {$$=0;}
2078 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
2080 syntaxerror("nested functions not supported yet");
2084 /* ------------- package + class ids --------------- */
2086 CLASS: T_IDENTIFIER {
2088 /* try current package */
2089 $$ = find_class($1);
2090 if(!$$) syntaxerror("Could not find class %s\n", $1);
2093 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2094 $$ = registry_findclass($1, $3);
2095 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
2099 QNAME: PACKAGEANDCLASS
2102 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
2103 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
2105 TYPE : QNAME {$$=$1;}
2106 | '*' {$$=registry_getanytype();}
2107 | "void" {$$=registry_getanytype();}
2109 | "String" {$$=registry_getstringclass();}
2110 | "int" {$$=registry_getintclass();}
2111 | "uint" {$$=registry_getuintclass();}
2112 | "Boolean" {$$=registry_getbooleanclass();}
2113 | "Number" {$$=registry_getnumberclass();}
2116 MAYBETYPE: ':' TYPE {$$=$2;}
2119 /* ----------function calls, delete, constructor calls ------ */
2121 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2122 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
2124 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2125 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2126 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2129 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2131 $$.cc = code_append($1.cc, $3.c);
2134 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2139 $$.c = abc_getglobalscope($$.c);
2140 $$.c = abc_getslot($$.c, $2->slot);
2142 $$.c = abc_findpropstrict2($$.c, &m);
2145 $$.c = code_append($$.c, $3.cc);
2148 $$.c = abc_construct($$.c, $3.len);
2150 $$.c = abc_constructprop2($$.c, &m, $3.len);
2154 /* TODO: use abc_call (for calling local variables),
2155 abc_callstatic (for calling own methods)
2158 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2161 if($$.c->opcode == OPCODE_COERCE_A) {
2162 $$.c = code_cutlast($$.c);
2164 code_t*paramcode = $3.cc;
2167 if($$.c->opcode == OPCODE_GETPROPERTY) {
2168 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2169 $$.c = code_cutlast($$.c);
2170 $$.c = code_append($$.c, paramcode);
2171 $$.c = abc_callproperty2($$.c, name, $3.len);
2172 multiname_destroy(name);
2173 } else if($$.c->opcode == OPCODE_GETSLOT) {
2174 int slot = (int)(ptroff_t)$$.c->data[0];
2175 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2176 if(t->kind!=TRAIT_METHOD) {
2177 //ok: flash allows to assign closures to members.
2179 multiname_t*name = t->name;
2180 $$.c = code_cutlast($$.c);
2181 $$.c = code_append($$.c, paramcode);
2182 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2183 $$.c = abc_callproperty2($$.c, name, $3.len);
2184 } else if($$.c->opcode == OPCODE_GETSUPER) {
2185 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2186 $$.c = code_cutlast($$.c);
2187 $$.c = code_append($$.c, paramcode);
2188 $$.c = abc_callsuper2($$.c, name, $3.len);
2189 multiname_destroy(name);
2191 $$.c = abc_getlocal_0($$.c);
2192 $$.c = code_append($$.c, paramcode);
2193 $$.c = abc_call($$.c, $3.len);
2198 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2199 $$.t = $1.t->function->return_type;
2201 $$.c = abc_coerce_a($$.c);
2206 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2207 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2208 if(!state->method) syntaxerror("super() not allowed outside of a function");
2209 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2212 $$.c = abc_getlocal_0($$.c);
2214 $$.c = code_append($$.c, $3.cc);
2216 this is dependent on the control path, check this somewhere else
2217 if(state->method->has_super)
2218 syntaxerror("constructor may call super() only once");
2220 state->method->has_super = 1;
2221 $$.c = abc_constructsuper($$.c, $3.len);
2222 $$.c = abc_pushundefined($$.c);
2226 DELETE: "delete" E {
2228 if($$.c->opcode == OPCODE_COERCE_A) {
2229 $$.c = code_cutlast($$.c);
2231 multiname_t*name = 0;
2232 if($$.c->opcode == OPCODE_GETPROPERTY) {
2233 $$.c->opcode = OPCODE_DELETEPROPERTY;
2234 } else if($$.c->opcode == OPCODE_GETSLOT) {
2235 int slot = (int)(ptroff_t)$$.c->data[0];
2236 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2237 $$.c = code_cutlast($$.c);
2238 $$.c = abc_deleteproperty2($$.c, name);
2240 $$.c = abc_getlocal_0($$.c);
2241 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2242 $$.c = abc_deleteproperty2($$.c, &m);
2244 $$.t = TYPE_BOOLEAN;
2247 RETURN: "return" %prec prec_none {
2248 $$ = abc_returnvoid(0);
2250 RETURN: "return" EXPRESSION {
2252 $$ = abc_returnvalue($$);
2255 // ----------------------- expression types -------------------------------------
2257 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2258 EXPRESSION : E %prec below_minus {$$ = $1;}
2259 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2261 $$.c = cut_last_push($$.c);
2262 $$.c = code_append($$.c,$3.c);
2265 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2266 $$=cut_last_push($1.c);
2269 // ----------------------- expression evaluation -------------------------------------
2271 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2272 //V : CONSTANT {$$ = 0;}
2274 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2275 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2276 //V : NEW {$$ = $1.c;}
2278 //V : DELETE {$$ = $1.c;}
2279 E : DELETE {$$ = $1;}
2283 namespace_t ns = {ACCESS_PACKAGE, ""};
2284 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2286 $$.c = abc_getlex2($$.c, &m);
2287 $$.c = abc_pushstring($$.c, $1.pattern);
2288 $$.c = abc_construct($$.c, 1);
2290 $$.c = abc_getlex2($$.c, &m);
2291 $$.c = abc_pushstring($$.c, $1.pattern);
2292 $$.c = abc_pushstring($$.c, $1.options);
2293 $$.c = abc_construct($$.c, 2);
2298 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2299 //MULTINAME(m, registry_getintclass());
2300 //$$.c = abc_coerce2($$.c, &m); // FIXME
2303 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2306 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2309 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2312 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2315 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2318 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2321 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2322 $$.t = TYPE_BOOLEAN;
2324 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2325 $$.t = TYPE_BOOLEAN;
2327 CONSTANT : "null" {$$.c = abc_pushnull(0);
2332 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2333 $$.t = TYPE_BOOLEAN;
2335 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2336 $$.t = TYPE_BOOLEAN;
2338 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2339 $$.t = TYPE_BOOLEAN;
2341 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2342 $$.t = TYPE_BOOLEAN;
2344 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2345 $$.t = TYPE_BOOLEAN;
2347 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2348 $$.t = TYPE_BOOLEAN;
2350 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2351 $$.t = TYPE_BOOLEAN;
2353 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2354 $$.t = TYPE_BOOLEAN;
2357 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2359 $$.c = converttype($$.c, $1.t, $$.t);
2360 $$.c = abc_dup($$.c);
2361 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2362 $$.c = cut_last_push($$.c);
2363 $$.c = code_append($$.c,$3.c);
2364 $$.c = converttype($$.c, $3.t, $$.t);
2365 code_t*label = $$.c = abc_label($$.c);
2366 jmp->branch = label;
2369 $$.t = join_types($1.t, $3.t, 'A');
2370 /*printf("%08x:\n",$1.t);
2371 code_dump($1.c, 0, 0, "", stdout);
2372 printf("%08x:\n",$3.t);
2373 code_dump($3.c, 0, 0, "", stdout);
2374 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2376 $$.c = converttype($$.c, $1.t, $$.t);
2377 $$.c = abc_dup($$.c);
2378 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2379 $$.c = cut_last_push($$.c);
2380 $$.c = code_append($$.c,$3.c);
2381 $$.c = converttype($$.c, $3.t, $$.t);
2382 code_t*label = $$.c = abc_label($$.c);
2383 jmp->branch = label;
2386 E : '!' E {$$.c=$2.c;
2387 $$.c = abc_not($$.c);
2388 $$.t = TYPE_BOOLEAN;
2391 E : '~' E {$$.c=$2.c;
2392 $$.c = abc_bitnot($$.c);
2396 E : E '&' E {$$.c = code_append($1.c,$3.c);
2397 $$.c = abc_bitand($$.c);
2401 E : E '^' E {$$.c = code_append($1.c,$3.c);
2402 $$.c = abc_bitxor($$.c);
2406 E : E '|' E {$$.c = code_append($1.c,$3.c);
2407 $$.c = abc_bitor($$.c);
2411 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2412 $$.c = abc_rshift($$.c);
2415 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2416 $$.c = abc_urshift($$.c);
2419 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2420 $$.c = abc_lshift($$.c);
2424 E : E '/' E {$$.c = code_append($1.c,$3.c);
2425 $$.c = abc_divide($$.c);
2428 E : E '%' E {$$.c = code_append($1.c,$3.c);
2429 $$.c = abc_modulo($$.c);
2432 E : E '+' E {$$.c = code_append($1.c,$3.c);
2433 if(BOTH_INT($1.t, $3.t)) {
2434 $$.c = abc_add_i($$.c);
2437 $$.c = abc_add($$.c);
2438 $$.t = join_types($1.t,$3.t,'+');
2441 E : E '-' E {$$.c = code_append($1.c,$3.c);
2442 if(BOTH_INT($1.t,$3.t)) {
2443 $$.c = abc_subtract_i($$.c);
2446 $$.c = abc_subtract($$.c);
2450 E : E '*' E {$$.c = code_append($1.c,$3.c);
2451 if(BOTH_INT($1.t,$3.t)) {
2452 $$.c = abc_multiply_i($$.c);
2455 $$.c = abc_multiply($$.c);
2460 E : E "in" E {$$.c = code_append($1.c,$3.c);
2461 $$.c = abc_in($$.c);
2462 $$.t = TYPE_BOOLEAN;
2465 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2466 if(use_astype && TYPE_IS_CLASS($3.t)) {
2467 MULTINAME(m,$3.t->cls);
2468 $$.c = abc_astype2($1.c, &m);
2471 $$.c = code_append($1.c, $3.c);
2472 $$.c = abc_astypelate($$.c);
2477 E : E "instanceof" E
2478 {$$.c = code_append($1.c, $3.c);
2479 $$.c = abc_instanceof($$.c);
2480 $$.t = TYPE_BOOLEAN;
2483 E : E "is" E {$$.c = code_append($1.c, $3.c);
2484 $$.c = abc_istypelate($$.c);
2485 $$.t = TYPE_BOOLEAN;
2488 E : "typeof" '(' E ')' {
2490 $$.c = abc_typeof($$.c);
2495 $$.c = cut_last_push($2.c);
2496 $$.c = abc_pushundefined($$.c);
2500 E : "void" { $$.c = abc_pushundefined(0);
2504 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2509 $$.c=abc_negate_i($$.c);
2512 $$.c=abc_negate($$.c);
2519 $$.c = code_append($$.c, $3.c);
2521 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2522 $$.c = abc_getproperty2($$.c, &m);
2523 $$.t = 0; // array elements have unknown type
2526 E : '[' MAYBE_EXPRESSION_LIST ']' {
2528 $$.c = code_append($$.c, $2.cc);
2529 $$.c = abc_newarray($$.c, $2.len);
2530 $$.t = registry_getarrayclass();
2533 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2534 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2536 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2538 $$.cc = code_append($$.cc, $1.c);
2539 $$.cc = code_append($$.cc, $3.c);
2542 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2545 $$.cc = code_append($$.cc, $3.c);
2546 $$.cc = code_append($$.cc, $5.c);
2551 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2553 $$.c = code_append($$.c, $2.cc);
2554 $$.c = abc_newobject($$.c, $2.len/2);
2555 $$.t = registry_getobjectclass();
2560 if(BOTH_INT($1.t,$3.t)) {
2561 c=abc_multiply_i(c);
2565 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2566 $$.c = toreadwrite($1.c, c, 0, 0);
2571 code_t*c = abc_modulo($3.c);
2572 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2573 $$.c = toreadwrite($1.c, c, 0, 0);
2577 code_t*c = abc_lshift($3.c);
2578 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2579 $$.c = toreadwrite($1.c, c, 0, 0);
2583 code_t*c = abc_rshift($3.c);
2584 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2585 $$.c = toreadwrite($1.c, c, 0, 0);
2589 code_t*c = abc_urshift($3.c);
2590 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2591 $$.c = toreadwrite($1.c, c, 0, 0);
2595 code_t*c = abc_divide($3.c);
2596 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2597 $$.c = toreadwrite($1.c, c, 0, 0);
2601 code_t*c = abc_bitor($3.c);
2602 c=converttype(c, TYPE_INT, $1.t);
2603 $$.c = toreadwrite($1.c, c, 0, 0);
2609 if(TYPE_IS_INT($1.t)) {
2613 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2616 $$.c = toreadwrite($1.c, c, 0, 0);
2619 E : E "-=" E { code_t*c = $3.c;
2620 if(TYPE_IS_INT($1.t)) {
2621 c=abc_subtract_i(c);
2624 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2627 $$.c = toreadwrite($1.c, c, 0, 0);
2630 E : E '=' E { code_t*c = 0;
2631 c = code_append(c, $3.c);
2632 c = converttype(c, $3.t, $1.t);
2633 $$.c = toreadwrite($1.c, c, 1, 0);
2637 E : E '?' E ':' E %prec below_assignment {
2638 $$.t = join_types($3.t,$5.t,'?');
2640 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2641 $$.c = code_append($$.c, $3.c);
2642 $$.c = converttype($$.c, $3.t, $$.t);
2643 code_t*j2 = $$.c = abc_jump($$.c, 0);
2644 $$.c = j1->branch = abc_label($$.c);
2645 $$.c = code_append($$.c, $5.c);
2646 $$.c = converttype($$.c, $3.t, $$.t);
2647 $$.c = j2->branch = abc_label($$.c);
2650 E : E "++" { code_t*c = 0;
2651 classinfo_t*type = $1.t;
2652 if(is_getlocal($1.c) && TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t)) {
2653 int nr = getlocalnr($1.c);
2654 code_free($1.c);$1.c=0;
2655 if(TYPE_IS_INT($1.t)) {
2656 $$.c = abc_getlocal(0, nr);
2657 $$.c = abc_inclocal_i($$.c, nr);
2658 } else if(TYPE_IS_NUMBER($1.t)) {
2659 $$.c = abc_getlocal(0, nr);
2660 $$.c = abc_inclocal($$.c, nr);
2661 } else syntaxerror("internal error");
2663 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2664 c=abc_increment_i(c);
2670 c=converttype(c, type, $1.t);
2671 $$.c = toreadwrite($1.c, c, 0, 1);
2676 // TODO: use inclocal, like with ++
2677 E : E "--" { code_t*c = 0;
2678 classinfo_t*type = $1.t;
2679 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2680 c=abc_decrement_i(c);
2686 c=converttype(c, type, $1.t);
2687 $$.c = toreadwrite($1.c, c, 0, 1);
2691 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2692 classinfo_t*type = $2.t;
2693 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2694 c=abc_increment_i(c);
2700 c=converttype(c, type, $2.t);
2701 $$.c = toreadwrite($2.c, c, 0, 0);
2705 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2706 classinfo_t*type = $2.t;
2707 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2708 c=abc_decrement_i(c);
2714 c=converttype(c, type, $2.t);
2715 $$.c = toreadwrite($2.c, c, 0, 0);
2719 E : "super" '.' T_IDENTIFIER
2720 { if(!state->cls->info)
2721 syntaxerror("super keyword not allowed outside a class");
2722 classinfo_t*t = state->cls->info->superclass;
2723 if(!t) t = TYPE_OBJECT;
2725 memberinfo_t*f = registry_findmember(t, $3, 1);
2726 namespace_t ns = flags2namespace(f->flags, "");
2727 MEMBER_MULTINAME(m, f, $3);
2729 $$.c = abc_getlocal_0($$.c);
2730 $$.c = abc_getsuper2($$.c, &m);
2731 $$.t = memberinfo_gettype(f);
2734 E : E '.' T_IDENTIFIER
2736 classinfo_t*t = $1.t;
2738 if(TYPE_IS_CLASS(t) && t->cls) {
2743 memberinfo_t*f = registry_findmember(t, $3, 1);
2745 if(f && !is_static != !(f->flags&FLAG_STATIC))
2747 if(f && f->slot && !noslot) {
2748 $$.c = abc_getslot($$.c, f->slot);
2750 MEMBER_MULTINAME(m, f, $3);
2751 $$.c = abc_getproperty2($$.c, &m);
2753 /* determine type */
2754 $$.t = memberinfo_gettype(f);
2756 $$.c = abc_coerce_a($$.c);
2758 /* when resolving a property on an unknown type, we do know the
2759 name of the property (and don't seem to need the package), but
2760 we need to make avm2 try out all access modes */
2761 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2762 $$.c = abc_getproperty2($$.c, &m);
2763 $$.c = abc_coerce_a($$.c);
2764 $$.t = registry_getanytype();
2768 VAR_READ : T_IDENTIFIER {
2775 /* look at variables */
2776 if((v = find_variable($1))) {
2777 // $1 is a local variable
2778 $$.c = abc_getlocal($$.c, v->index);
2781 /* look at current class' members */
2782 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2783 // $1 is a function in this class
2784 int var_is_static = (f->flags&FLAG_STATIC);
2785 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2786 if(var_is_static != i_am_static) {
2787 /* there doesn't seem to be any "static" way to access
2788 static properties of a class */
2789 state->method->late_binding = 1;
2791 namespace_t ns = {flags2access(f->flags), ""};
2792 multiname_t m = {QNAME, &ns, 0, $1};
2793 $$.c = abc_findpropstrict2($$.c, &m);
2794 $$.c = abc_getproperty2($$.c, &m);
2797 $$.c = abc_getlocal_0($$.c);
2798 $$.c = abc_getslot($$.c, f->slot);
2800 namespace_t ns = {flags2access(f->flags), ""};
2801 multiname_t m = {QNAME, &ns, 0, $1};
2802 $$.c = abc_getlocal_0($$.c);
2803 $$.c = abc_getproperty2($$.c, &m);
2806 if(f->kind == MEMBER_METHOD) {
2807 $$.t = TYPE_FUNCTION(f);
2812 /* look at actual classes, in the current package and imported */
2813 } else if((a = find_class($1))) {
2814 if(a->flags & FLAG_METHOD) {
2816 $$.c = abc_findpropstrict2($$.c, &m);
2817 $$.c = abc_getproperty2($$.c, &m);
2818 if(a->function->kind == MEMBER_METHOD) {
2819 $$.t = TYPE_FUNCTION(a->function);
2821 $$.t = a->function->type;
2825 $$.c = abc_getglobalscope($$.c);
2826 $$.c = abc_getslot($$.c, a->slot);
2829 $$.c = abc_getlex2($$.c, &m);
2831 $$.t = TYPE_CLASS(a);
2834 /* unknown object, let the avm2 resolve it */
2836 if(strcmp($1,"trace"))
2837 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
2838 state->method->late_binding = 1;
2840 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2843 $$.c = abc_findpropstrict2($$.c, &m);
2844 $$.c = abc_getproperty2($$.c, &m);
2849 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2850 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2851 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2853 // ----------------- namespaces -------------------------------------------------
2855 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2856 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2857 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2859 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}