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;
62 abc_exception_list_t *exception_list;
66 %token<id> T_IDENTIFIER
68 %token<token> T_REGEXP
70 %token<number_int> T_INT
71 %token<number_uint> T_UINT
72 %token<number_uint> T_BYTE
73 %token<number_uint> T_SHORT
74 %token<number_float> T_FLOAT
76 %token<id> T_FOR "for"
77 %token<id> T_WHILE "while"
79 %token<id> T_SWITCH "switch"
81 %token<token> KW_IMPLEMENTS "implements"
82 %token<token> KW_NAMESPACE "namespace"
83 %token<token> KW_PACKAGE "package"
84 %token<token> KW_PROTECTED "protected"
85 %token<token> KW_PUBLIC "public"
86 %token<token> KW_PRIVATE "private"
87 %token<token> KW_USE "use"
88 %token<token> KW_INTERNAL "internal"
89 %token<token> KW_NEW "new"
90 %token<token> KW_NATIVE "native"
91 %token<token> KW_FUNCTION "function"
92 %token<token> KW_UNDEFINED "undefined"
93 %token<token> KW_CONTINUE "continue"
94 %token<token> KW_CLASS "class"
95 %token<token> KW_CONST "const"
96 %token<token> KW_CATCH "catch"
97 %token<token> KW_CASE "case"
98 %token<token> KW_SET "set"
99 %token<token> KW_VOID "void"
100 %token<token> KW_THROW "throw"
101 %token<token> KW_STATIC "static"
102 %token<token> KW_WITH "with"
103 %token<token> KW_INSTANCEOF "instanceof"
104 %token<token> KW_IMPORT "import"
105 %token<token> KW_RETURN "return"
106 %token<token> KW_TYPEOF "typeof"
107 %token<token> KW_INTERFACE "interface"
108 %token<token> KW_NULL "null"
109 %token<token> KW_VAR "var"
110 %token<token> KW_DYNAMIC "dynamic"
111 %token<token> KW_OVERRIDE "override"
112 %token<token> KW_FINAL "final"
113 %token<token> KW_EACH "each"
114 %token<token> KW_GET "get"
115 %token<token> KW_TRY "try"
116 %token<token> KW_SUPER "super"
117 %token<token> KW_EXTENDS "extends"
118 %token<token> KW_FALSE "false"
119 %token<token> KW_TRUE "true"
120 %token<token> KW_BOOLEAN "Boolean"
121 %token<token> KW_UINT "uint"
122 %token<token> KW_INT "int"
123 %token<token> KW_NUMBER "Number"
124 %token<token> KW_STRING "String"
125 %token<token> KW_DEFAULT "default"
126 %token<token> KW_DELETE "delete"
127 %token<token> KW_IF "if"
128 %token<token> KW_ELSE "else"
129 %token<token> KW_BREAK "break"
130 %token<token> KW_IS "is"
131 %token<token> KW_IN "in"
132 %token<token> KW_AS "as"
134 %token<token> T_EQEQ "=="
135 %token<token> T_EQEQEQ "==="
136 %token<token> T_NE "!="
137 %token<token> T_NEE "!=="
138 %token<token> T_LE "<="
139 %token<token> T_GE ">="
140 %token<token> T_ORBY "|="
141 %token<token> T_DIVBY "/="
142 %token<token> T_MODBY "%="
143 %token<token> T_MULBY "*="
144 %token<token> T_PLUSBY "+="
145 %token<token> T_MINUSBY "-="
146 %token<token> T_SHRBY ">>="
147 %token<token> T_SHLBY "<<="
148 %token<token> T_USHRBY ">>>="
149 %token<token> T_OROR "||"
150 %token<token> T_ANDAND "&&"
151 %token<token> T_COLONCOLON "::"
152 %token<token> T_MINUSMINUS "--"
153 %token<token> T_PLUSPLUS "++"
154 %token<token> T_DOTDOT ".."
155 %token<token> T_DOTDOTDOT "..."
156 %token<token> T_SHL "<<"
157 %token<token> T_USHR ">>>"
158 %token<token> T_SHR ">>"
160 %type <for_start> FOR_START
161 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
162 %type <token> VARCONST
164 %type <code> CODEPIECE CODE_STATEMENT
165 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
166 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
167 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
168 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
169 %type <exception> CATCH
170 %type <exception_list> CATCH_LIST
171 %type <code> CLASS_DECLARATION
172 %type <code> NAMESPACE_DECLARATION
173 %type <code> INTERFACE_DECLARATION
174 %type <code> VOIDEXPRESSION
175 %type <value> EXPRESSION NONCOMMAEXPRESSION
176 %type <value> MAYBEEXPRESSION
177 %type <value> E DELETE
178 %type <value> CONSTANT
179 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
180 %type <token> USE_NAMESPACE
181 %type <code> FOR_INIT
183 %type <classinfo> MAYBETYPE
186 %type <params> PARAM_LIST
187 %type <params> MAYBE_PARAM_LIST
188 %type <flags> MAYBE_MODIFIERS
189 %type <flags> MODIFIER_LIST
190 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
191 %type <classinfo_list> IMPLEMENTS_LIST
192 %type <classinfo> EXTENDS
193 %type <classinfo_list> EXTENDS_LIST
194 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
195 %type <classinfo_list> QNAME_LIST
196 %type <classinfo> TYPE
197 //%type <token> VARIABLE
198 %type <value> VAR_READ
200 //%type <token> T_IDENTIFIER
201 %type <token> MODIFIER
202 %type <value> FUNCTIONCALL
203 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
205 // precedence: from low to high
209 %left below_semicolon
212 %nonassoc below_assignment // for ?:, contrary to spec
213 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
220 %nonassoc "==" "!=" "===" "!=="
221 %nonassoc "is" "as" "in"
222 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
223 %left "<<" ">>" ">>>"
227 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
229 %nonassoc below_curly
230 %left '[' ']' '{' "new" '.' ".." "::"
231 %nonassoc T_IDENTIFIER
232 %left above_identifier
237 // needed for "return" precedence:
238 %nonassoc T_STRING T_REGEXP
239 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
240 %nonassoc "false" "true" "null" "undefined" "super"
246 static int yyerror(char*s)
248 syntaxerror("%s", s);
251 static char* concat2(const char* t1, const char* t2)
255 char*text = malloc(l1+l2+1);
256 memcpy(text , t1, l1);
257 memcpy(text+l1, t2, l2);
261 static char* concat3(const char* t1, const char* t2, const char* t3)
266 char*text = malloc(l1+l2+l3+1);
267 memcpy(text , t1, l1);
268 memcpy(text+l1, t2, l2);
269 memcpy(text+l1+l2, t3, l3);
274 typedef struct _import {
278 DECLARE_LIST(import);
280 typedef struct _classstate {
286 char has_constructor;
289 typedef struct _methodstate {
293 /* code that needs to be executed at the start of
294 a method (like initializing local registers) */
299 abc_exception_list_t*exceptions;
302 typedef struct _state {
307 import_list_t*wildcard_imports;
309 char has_own_imports;
312 methodstate_t*method;
319 typedef struct _global {
326 static global_t*global = 0;
327 static state_t* state = 0;
331 #define MULTINAME(m,x) \
334 registry_fill_multiname(&m, &m##_ns, x);
336 #define MEMBER_MULTINAME(m,f,n) \
340 m##_ns.access = flags2access(f->flags); \
344 m.namespace_set = 0; \
347 m.type = MULTINAME; \
349 m.namespace_set = &nopackage_namespace_set; \
353 /* warning: list length of namespace set is undefined */
354 #define MULTINAME_LATE(m, access, package) \
355 namespace_t m##_ns = {access, package}; \
356 namespace_set_t m##_nsset; \
357 namespace_list_t m##_l;m##_l.next = 0; \
358 m##_nsset.namespaces = &m##_l; \
359 m##_nsset = m##_nsset; \
360 m##_l.namespace = &m##_ns; \
361 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
363 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
364 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
365 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
366 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
367 static namespace_list_t nl4 = {&ns4,0};
368 static namespace_list_t nl3 = {&ns3,&nl4};
369 static namespace_list_t nl2 = {&ns2,&nl3};
370 static namespace_list_t nl1 = {&ns1,&nl2};
371 static namespace_set_t nopackage_namespace_set = {&nl1};
373 static void new_state()
376 state_t*oldstate = state;
378 memcpy(s, state, sizeof(state_t)); //shallow copy
380 s->imports = dict_new();
384 state->has_own_imports = 0;
385 state->vars = dict_new();
386 state->old = oldstate;
388 static void state_has_imports()
390 state->wildcard_imports = list_clone(state->wildcard_imports);
391 state->imports = dict_clone(state->imports);
392 state->has_own_imports = 1;
395 static void state_destroy(state_t*state)
397 if(state->has_own_imports) {
398 list_free(state->wildcard_imports);
399 dict_destroy(state->imports);state->imports=0;
401 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
402 dict_destroy(state->imports);state->imports=0;
406 for(t=0;t<state->vars->hashsize;t++) {
407 dictentry_t*e =state->vars->slots[t];
409 free(e->data);e->data=0;
413 dict_destroy(state->vars);state->vars=0;
419 static void old_state()
421 if(!state || !state->old)
422 syntaxerror("invalid nesting");
423 state_t*leaving = state;
425 /*if(state->method->initcode) {
426 printf("residual initcode\n");
427 code_dump(state->method->initcode, 0, 0, "", stdout);
429 state_destroy(leaving);
431 void initialize_state()
433 global = rfx_calloc(sizeof(global_t));
436 state->package = current_filename;
438 global->file = abc_file_new();
439 global->file->flags &= ~ABCFILE_LAZY;
440 global->variable_count = 1;
442 global->init = abc_initscript(global->file, 0);
443 code_t*c = global->init->method->body->code;
445 c = abc_getlocal_0(c);
446 c = abc_pushscope(c);
448 /* findpropstrict doesn't just return a scope object- it
449 also makes it "active" somehow. Push local_0 on the
450 scope stack and read it back with findpropstrict, it'll
451 contain properties like "trace". Trying to find the same
452 property on a "vanilla" local_0 yields only a "undefined" */
453 //c = abc_findpropstrict(c, "[package]::trace");
455 /*c = abc_getlocal_0(c);
456 c = abc_findpropstrict(c, "[package]::trace");
458 c = abc_setlocal_1(c);
460 c = abc_pushbyte(c, 0);
461 c = abc_setlocal_2(c);
463 code_t*xx = c = abc_label(c);
464 c = abc_findpropstrict(c, "[package]::trace");
465 c = abc_pushstring(c, "prop:");
466 c = abc_hasnext2(c, 1, 2);
468 c = abc_setlocal_3(c);
469 c = abc_callpropvoid(c, "[package]::trace", 2);
470 c = abc_getlocal_3(c);
472 c = abc_iftrue(c,xx);*/
474 c = abc_findpropstrict(c, "[package]::trace");
475 c = abc_pushstring(c, "[entering global init function]");
476 c = abc_callpropvoid(c, "[package]::trace", 1);
478 global->init->method->body->code = c;
480 void* finalize_state()
482 if(state->level!=1) {
483 syntaxerror("unexpected end of file");
485 abc_method_body_t*m = global->init->method->body;
488 __ findpropstrict(m, "[package]::trace");
489 __ pushstring(m, "[leaving global init function]");
490 __ callpropvoid(m, "[package]::trace", 1);
493 state_destroy(state);
499 static void startpackage(char*name)
502 /*printf("entering package \"%s\"\n", name);*/
503 state->package = strdup(name);
504 global->variable_count = 1;
506 static void endpackage()
508 /*printf("leaving package \"%s\"\n", state->package);*/
510 //used e.g. in classinfo_register:
511 //free(state->package);state->package=0;
517 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
520 syntaxerror("inner classes now allowed");
523 global->variable_count = 1;
524 state->cls = rfx_calloc(sizeof(classstate_t));
527 classinfo_list_t*mlist=0;
528 /*printf("entering class %s\n", name);
529 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
531 printf(" extends: %s.%s\n", extends->package, extends->name);
532 printf(" implements (%d): ", list_length(implements));
533 for(mlist=implements;mlist;mlist=mlist->next) {
534 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
539 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
540 syntaxerror("invalid modifier(s)");
542 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
543 syntaxerror("public and internal not supported at the same time.");
545 /* create the class name, together with the proper attributes */
549 if(!(flags&FLAG_PUBLIC) && !state->package) {
550 access = ACCESS_PRIVATE; package = current_filename;
551 } else if(!(flags&FLAG_PUBLIC) && state->package) {
552 access = ACCESS_PACKAGEINTERNAL; package = state->package;
553 } else if(state->package) {
554 access = ACCESS_PACKAGE; package = state->package;
556 syntaxerror("public classes only allowed inside a package");
559 if(registry_findclass(package, classname)) {
560 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
564 /* build info struct */
565 int num_interfaces = (list_length(implements));
566 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
567 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
569 classinfo_list_t*l = implements;
570 for(l=implements;l;l=l->next) {
571 state->cls->info->interfaces[pos++] = l->classinfo;
574 multiname_t*extends2 = sig2mname(extends);
576 MULTINAME(classname2,state->cls->info);
579 state->cls_init = abc_getlocal_0(state->cls_init);
580 state->cls_init = abc_constructsuper(state->cls_init, 0);
583 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
584 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
585 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
587 state->cls->info->flags |= CLASS_INTERFACE;
588 abc_class_interface(state->cls->abc);
591 abc_class_protectedNS(state->cls->abc, classname);
593 for(mlist=implements;mlist;mlist=mlist->next) {
594 MULTINAME(m, mlist->classinfo);
595 abc_class_add_interface(state->cls->abc, &m);
598 /* now write the construction code for this class */
599 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
601 abc_method_body_t*m = global->init->method->body;
602 __ getglobalscope(m);
603 classinfo_t*s = extends;
608 //TODO: take a look at the current scope stack, maybe
609 // we can re-use something
614 multiname_t*s2 = sig2mname(s);
616 multiname_destroy(s2);
618 __ pushscope(m); count++;
619 m->code = m->code->prev->prev; // invert
621 /* continue appending after last op end */
622 while(m->code && m->code->next) m->code = m->code->next;
624 /* TODO: if this is one of *our* classes, we can also
625 do a getglobalscope/getslot <nr> (which references
626 the init function's slots) */
628 __ getlex2(m, extends2);
630 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
631 stack is not the superclass */
632 __ pushscope(m);count++;
635 /* notice: we get a verify error #1107 if the top element on the scope
636 stack is not the global object */
638 __ pushscope(m);count++;
640 __ newclass(m,state->cls->abc);
644 __ setslot(m, slotindex);
646 /* flash.display.MovieClip handling */
647 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
648 if(state->package && state->package[0]) {
649 globalclass = concat3(state->package, ".", classname);
651 globalclass = strdup(classname);
654 multiname_destroy(extends2);
657 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
659 c = code_append(c, initcode);
660 c = code_append(c, body);
661 /* append return if necessary */
662 if(!c || c->opcode != OPCODE_RETURNVOID &&
663 c->opcode != OPCODE_RETURNVALUE) {
664 c = abc_returnvoid(c);
669 static void endclass()
671 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
673 c = abc_getlocal_0(c);
674 c = abc_constructsuper(c, 0);
675 state->cls->init = code_append(state->cls->init, c);
678 if(state->cls->init) {
679 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
680 m->body->code = wrap_function(0, state->cls->init, m->body->code);
682 if(state->cls->static_init) {
683 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
684 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
686 // handy for scope testing
690 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
693 free(state->cls);state->cls=0;
697 typedef struct _variable {
702 static variable_t* find_variable(char*name)
708 v = dict_lookup(s->vars, name);
716 static variable_t* find_variable_safe(char*name)
718 variable_t* v = find_variable(name);
720 syntaxerror("undefined variable: %s", name);
723 static char variable_exists(char*name)
725 return dict_lookup(state->vars, name)!=0;
727 code_t*defaultvalue(code_t*c, classinfo_t*type);
728 static int new_variable(char*name, classinfo_t*type, char init)
731 v->index = global->variable_count;
734 dict_put(state->vars, name, v);
736 if(init && state->method && type) {
737 /* if this is a typed variable:
738 push default value for type on stack at the very beginning of the
739 method, so that it always has that type regardless of the control
741 state->method->initcode = defaultvalue(state->method->initcode, type);
742 state->method->initcode = abc_setlocal(state->method->initcode, v->index);
744 return global->variable_count++;
746 #define TEMPVARNAME "__as3_temp__"
747 static int gettempvar()
749 variable_t*v = find_variable(TEMPVARNAME);
752 return new_variable(TEMPVARNAME, 0, 0);
755 code_t* killvars(code_t*c)
758 for(t=0;t<state->vars->hashsize;t++) {
759 dictentry_t*e =state->vars->slots[t];
761 variable_t*v = (variable_t*)e->data;
762 //do this always, otherwise register types don't match
763 //in the verifier when doing nested loops
764 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
765 c = abc_kill(c, v->index);
772 void check_code_for_break(code_t*c)
775 if(c->opcode == OPCODE___BREAK__) {
776 char*name = string_cstr(c->data[0]);
777 syntaxerror("Unresolved \"break %s\"", name);
779 if(c->opcode == OPCODE___CONTINUE__) {
780 char*name = string_cstr(c->data[0]);
781 syntaxerror("Unresolved \"continue %s\"", name);
788 static void check_constant_against_type(classinfo_t*t, constant_t*c)
790 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
791 if(TYPE_IS_NUMBER(t)) {
792 xassert(c->type == CONSTANT_FLOAT
793 || c->type == CONSTANT_INT
794 || c->type == CONSTANT_UINT);
795 } else if(TYPE_IS_UINT(t)) {
796 xassert(c->type == CONSTANT_UINT ||
797 (c->type == CONSTANT_INT && c->i>0));
798 } else if(TYPE_IS_INT(t)) {
799 xassert(c->type == CONSTANT_INT);
800 } else if(TYPE_IS_BOOLEAN(t)) {
801 xassert(c->type == CONSTANT_TRUE
802 || c->type == CONSTANT_FALSE);
806 static int flags2access(int flags)
809 if(flags&FLAG_PUBLIC) {
810 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
811 access = ACCESS_PACKAGE;
812 } else if(flags&FLAG_PRIVATE) {
813 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
814 access = ACCESS_PRIVATE;
815 } else if(flags&FLAG_PROTECTED) {
816 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
817 access = ACCESS_PROTECTED;
819 access = ACCESS_PACKAGEINTERNAL;
824 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
826 memberinfo_t*minfo = 0;
829 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
830 minfo->return_type = return_type;
831 } else if(getset != KW_GET && getset != KW_SET) {
833 if((minfo = registry_findmember(state->cls->info, name, 0))) {
834 if(minfo->parent == state->cls->info) {
835 syntaxerror("class already contains a member/method called '%s'", name);
836 } else if(!minfo->parent) {
837 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
839 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
840 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
843 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
844 minfo->return_type = return_type;
845 // getslot on a member slot only returns "undefined", so no need
846 // to actually store these
847 //state->minfo->slot = state->method->abc->method->trait->slot_id;
849 //class getter/setter
850 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
854 else if(params->list)
855 type = params->list->param->type;
856 // not sure wether to look into superclasses here, too
857 if((minfo=registry_findmember(state->cls->info, name, 0))) {
858 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
859 syntaxerror("class already contains a member or method called '%s'", name);
861 syntaxerror("getter/setter for '%s' already defined", name);
862 /* make a setter or getter into a getset */
867 if(type && minfo->type != type)
868 syntaxerror("different type in getter and setter");
870 minfo = memberinfo_register(state->cls->info, name, gs);
873 /* can't assign a slot as getter and setter might have different slots */
874 //minfo->slot = slot;
876 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
877 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
878 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
879 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
880 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
881 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
885 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
886 params_t*params, classinfo_t*return_type)
889 syntaxerror("not able to start another method scope");
892 global->variable_count = 0;
893 state->method = rfx_calloc(sizeof(methodstate_t));
894 state->method->initcode = 0;
895 state->method->has_super = 0;
897 state->method->is_constructor = !strcmp(state->cls->info->name,name);
898 state->cls->has_constructor |= state->method->is_constructor;
900 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
902 state->method->is_global = 1;
903 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
905 new_variable("globalscope", 0, 0);
908 /* state->vars is initialized by state_new */
911 for(p=params->list;p;p=p->next) {
912 new_variable(p->param->name, p->param->type, 0);
914 if(state->method->is_constructor)
915 name = "__as3_constructor__";
916 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
919 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
920 params_t*params, classinfo_t*return_type, code_t*body)
924 multiname_t*type2 = sig2mname(return_type);
926 if(state->method->is_constructor) {
927 f = abc_class_getconstructor(state->cls->abc, type2);
928 } else if(!state->method->is_global) {
929 namespace_t mname_ns = {flags2access(flags), ""};
930 multiname_t mname = {QNAME, &mname_ns, 0, name};
932 if(flags&FLAG_STATIC)
933 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
935 f = abc_class_method(state->cls->abc, type2, &mname);
936 slot = f->trait->slot_id;
938 namespace_t mname_ns = {flags2access(flags), state->package};
939 multiname_t mname = {QNAME, &mname_ns, 0, name};
941 f = abc_method_new(global->file, type2, 1);
942 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
943 //abc_code_t*c = global->init->method->body->code;
945 //flash doesn't seem to allow us to access function slots
946 //state->method->info->slot = slot;
948 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
949 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
950 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
951 if(params->varargs) f->flags |= METHOD_NEED_REST;
955 for(p=params->list;p;p=p->next) {
956 if(params->varargs && !p->next) {
957 break; //varargs: omit last parameter in function signature
959 multiname_t*m = sig2mname(p->param->type);
960 list_append(f->parameters, m);
961 if(p->param->value) {
962 check_constant_against_type(p->param->type, p->param->value);
963 opt=1;list_append(f->optional_parameters, p->param->value);
965 syntaxerror("non-optional parameter not allowed after optional parameters");
968 check_code_for_break(body);
971 f->body->code = body;
972 f->body->exceptions = state->method->exceptions;
975 syntaxerror("interface methods can't have a method body");
978 free(state->method);state->method=0;
984 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
989 void breakjumpsto(code_t*c, char*name, code_t*jump)
992 if(c->opcode == OPCODE___BREAK__) {
993 string_t*name2 = c->data[0];
994 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
995 c->opcode = OPCODE_JUMP;
1002 void continuejumpsto(code_t*c, char*name, code_t*jump)
1005 if(c->opcode == OPCODE___CONTINUE__) {
1006 string_t*name2 = c->data[0];
1007 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1008 c->opcode = OPCODE_JUMP;
1016 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1018 if(!type1 || !type2)
1019 return registry_getanytype();
1020 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1021 return registry_getanytype();
1024 return registry_getanytype();
1026 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1031 return abc_coerce_a(c);
1035 // cast an "any" type to a specific type. subject to
1036 // runtime exceptions
1037 return abc_coerce2(c, &m);
1040 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1041 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1042 // allow conversion between number types
1043 return abc_coerce2(c, &m);
1045 //printf("%s.%s\n", from.package, from.name);
1046 //printf("%s.%s\n", to.package, to.name);
1048 classinfo_t*supertype = from;
1050 if(supertype == to) {
1051 // target type is one of from's superclasses
1052 return abc_coerce2(c, &m);
1055 while(supertype->interfaces[t]) {
1056 if(supertype->interfaces[t]==to) {
1057 // target type is one of from's interfaces
1058 return abc_coerce2(c, &m);
1062 supertype = supertype->superclass;
1064 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1066 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1068 syntaxerror("can't convert type %s to %s", from->name, to->name);
1071 code_t*defaultvalue(code_t*c, classinfo_t*type)
1073 if(TYPE_IS_INT(type)) {
1074 c = abc_pushbyte(c, 0);
1075 } else if(TYPE_IS_UINT(type)) {
1076 c = abc_pushuint(c, 0);
1077 } else if(TYPE_IS_FLOAT(type)) {
1079 } else if(TYPE_IS_BOOLEAN(type)) {
1080 c = abc_pushfalse(c);
1082 c = abc_pushnull(c);
1087 char is_pushundefined(code_t*c)
1089 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1092 void parserassert(int b)
1094 if(!b) syntaxerror("internal error: assertion failed");
1097 static classinfo_t* find_class(char*name)
1101 c = registry_findclass(state->package, name);
1104 /* try explicit imports */
1105 dictentry_t* e = dict_get_slot(state->imports, name);
1108 if(!strcmp(e->key, name)) {
1109 c = (classinfo_t*)e->data;
1115 /* try package.* imports */
1116 import_list_t*l = state->wildcard_imports;
1118 //printf("does package %s contain a class %s?\n", l->import->package, name);
1119 c = registry_findclass(l->import->package, name);
1124 /* try global package */
1125 c = registry_findclass("", name);
1128 /* try local "filename" package */
1129 c = registry_findclass(current_filename, name);
1135 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1139 [prefix code] [read instruction]
1143 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1146 if(in && in->opcode == OPCODE_COERCE_A) {
1147 in = code_cutlast(in);
1150 syntaxerror("internal error");
1152 /* chop off read instruction */
1156 prefix = r->prev;r->prev = 0;
1162 char use_temp_var = readbefore;
1164 /* generate the write instruction, and maybe append a dup to the prefix code */
1165 code_t* write = abc_nop(0);
1166 if(r->opcode == OPCODE_GETPROPERTY) {
1167 write->opcode = OPCODE_SETPROPERTY;
1168 multiname_t*m = (multiname_t*)r->data[0];
1169 write->data[0] = multiname_clone(m);
1170 if(m->type == QNAME || m->type == MULTINAME) {
1172 prefix = abc_dup(prefix); // we need the object, too
1175 } else if(m->type == MULTINAMEL) {
1177 /* dupping two values on the stack requires 5 operations and one register-
1178 couldn't adobe just have given us a dup2? */
1179 int temp = gettempvar();
1180 prefix = abc_setlocal(prefix, temp);
1181 prefix = abc_dup(prefix);
1182 prefix = abc_getlocal(prefix, temp);
1183 prefix = abc_swap(prefix);
1184 prefix = abc_getlocal(prefix, temp);
1186 prefix = abc_kill(prefix, temp);
1190 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1192 } else if(r->opcode == OPCODE_GETSLOT) {
1193 write->opcode = OPCODE_SETSLOT;
1194 write->data[0] = r->data[0];
1196 prefix = abc_dup(prefix); // we need the object, too
1199 } else if(r->opcode == OPCODE_GETLOCAL) {
1200 write->opcode = OPCODE_SETLOCAL;
1201 write->data[0] = r->data[0];
1202 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1203 write->opcode = OPCODE_SETLOCAL_0;
1204 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1205 write->opcode = OPCODE_SETLOCAL_1;
1206 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1207 write->opcode = OPCODE_SETLOCAL_2;
1208 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1209 write->opcode = OPCODE_SETLOCAL_3;
1211 code_dump(r, 0, 0, "", stdout);
1212 syntaxerror("illegal lvalue: can't assign a value to this expression");
1219 /* with getproperty/getslot, we have to be extra careful not
1220 to execute the read code twice, as it might have side-effects
1221 (e.g. if the property is in fact a setter/getter combination)
1223 So read the value, modify it, and write it again,
1224 using prefix only once and making sure (by using a temporary
1225 register) that the return value is what we just wrote */
1226 temp = gettempvar();
1227 c = code_append(c, prefix);
1228 c = code_append(c, r);
1231 c = abc_setlocal(c, temp);
1233 c = code_append(c, middlepart);
1236 c = abc_setlocal(c, temp);
1238 c = code_append(c, write);
1239 c = abc_getlocal(c, temp);
1240 c = abc_kill(c, temp);
1242 /* if we're allowed to execute the read code twice *and*
1243 the middlepart doesn't modify the code, things are easier.
1245 code_t* r2 = code_dup(r);
1246 //c = code_append(c, prefix);
1247 parserassert(!prefix);
1248 c = code_append(c, r);
1249 c = code_append(c, middlepart);
1250 c = code_append(c, write);
1251 c = code_append(c, r2);
1254 /* even smaller version: overwrite the value without reading
1258 c = code_append(c, prefix);
1261 c = code_append(c, middlepart);
1262 c = code_append(c, write);
1263 c = code_append(c, r);
1265 temp = gettempvar();
1267 c = code_append(c, prefix);
1269 c = code_append(c, middlepart);
1271 c = abc_setlocal(c, temp);
1272 c = code_append(c, write);
1273 c = abc_getlocal(c, temp);
1274 c = abc_kill(c, temp);
1281 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1282 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1289 /* ------------ code blocks / statements ---------------- */
1291 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1293 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1294 PROGRAM_CODE_LIST: PROGRAM_CODE
1295 | PROGRAM_CODE_LIST PROGRAM_CODE
1297 PROGRAM_CODE: PACKAGE_DECLARATION
1298 | INTERFACE_DECLARATION
1300 | FUNCTION_DECLARATION
1305 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1306 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1307 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1309 INPACKAGE_CODE: INTERFACE_DECLARATION
1311 | FUNCTION_DECLARATION
1316 MAYBECODE: CODE {$$=$1;}
1317 MAYBECODE: {$$=code_new();}
1319 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1320 CODE: CODEPIECE {$$=$1;}
1322 // code which also may appear outside a method
1323 CODE_STATEMENT: IMPORT
1324 CODE_STATEMENT: VOIDEXPRESSION
1326 CODE_STATEMENT: FOR_IN
1327 CODE_STATEMENT: WHILE
1328 CODE_STATEMENT: DO_WHILE
1329 CODE_STATEMENT: SWITCH
1331 CODE_STATEMENT: WITH
1334 // code which may appear anywhere
1335 CODEPIECE: ';' {$$=0;}
1336 CODEPIECE: VARIABLE_DECLARATION
1337 CODEPIECE: CODE_STATEMENT
1343 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1344 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1346 CODEBLOCK : '{' CODE '}' {$$=$2;}
1347 CODEBLOCK : '{' '}' {$$=0;}
1348 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1349 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1351 /* ------------ package init code ------------------- */
1353 PACKAGE_INITCODE: CODE_STATEMENT {
1354 if($1) warning("code ignored");
1357 /* ------------ variables --------------------------- */
1359 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1360 | {$$.c=abc_pushundefined(0);
1364 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1365 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1367 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1368 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1370 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1372 if(variable_exists($1))
1373 syntaxerror("Variable %s already defined", $1);
1375 if(!is_subtype_of($3.t, $2)) {
1376 syntaxerror("Can't convert %s to %s", $3.t->name,
1380 int index = new_variable($1, $2, 1);
1383 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1385 $$ = converttype($$, $3.t, $2);
1386 $$ = abc_setlocal($$, index);
1388 $$ = defaultvalue(0, $2);
1389 $$ = abc_setlocal($$, index);
1392 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1394 $$ = abc_coerce_a($$);
1395 $$ = abc_setlocal($$, index);
1401 /* that's the default for a local register, anyway
1403 state->method->initcode = abc_pushundefined(state->method->initcode);
1404 state->method->initcode = abc_setlocal(state->method->initcode, index);
1406 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1409 /* ------------ control flow ------------------------- */
1411 MAYBEELSE: %prec below_else {$$ = code_new();}
1412 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1413 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1415 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1417 $$ = code_append($$, $4.c);
1418 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1420 $$ = code_append($$, $6);
1422 myjmp = $$ = abc_jump($$, 0);
1424 myif->branch = $$ = abc_nop($$);
1426 $$ = code_append($$, $7);
1427 myjmp->branch = $$ = abc_nop($$);
1430 $$ = killvars($$);old_state();
1433 FOR_INIT : {$$=code_new();}
1434 FOR_INIT : VARIABLE_DECLARATION
1435 FOR_INIT : VOIDEXPRESSION
1436 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1437 $$=$2;new_variable($2,$3,1);
1439 FOR_IN_INIT : T_IDENTIFIER {
1443 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1444 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1446 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1447 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1449 $$ = code_append($$, $2);
1450 code_t*loopstart = $$ = abc_label($$);
1451 $$ = code_append($$, $4.c);
1452 code_t*myif = $$ = abc_iffalse($$, 0);
1453 $$ = code_append($$, $8);
1454 code_t*cont = $$ = abc_nop($$);
1455 $$ = code_append($$, $6);
1456 $$ = abc_jump($$, loopstart);
1457 code_t*out = $$ = abc_nop($$);
1458 breakjumpsto($$, $1.name, out);
1459 continuejumpsto($$, $1.name, cont);
1462 $$ = killvars($$);old_state();
1465 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1466 variable_t*var = find_variable($2);
1467 char*tmp1name = concat2($2, "__tmp1__");
1468 int it = new_variable(tmp1name, TYPE_INT, 0);
1469 char*tmp2name = concat2($2, "__array__");
1470 int array = new_variable(tmp1name, 0, 0);
1473 $$ = code_append($$, $4.c);
1474 $$ = abc_coerce_a($$);
1475 $$ = abc_setlocal($$, array);
1476 $$ = abc_pushbyte($$, 0);
1477 $$ = abc_setlocal($$, it);
1479 code_t*loopstart = $$ = abc_label($$);
1481 $$ = abc_hasnext2($$, array, it);
1482 code_t*myif = $$ = abc_iffalse($$, 0);
1483 $$ = abc_getlocal($$, array);
1484 $$ = abc_getlocal($$, it);
1486 $$ = abc_nextname($$);
1488 $$ = abc_nextvalue($$);
1489 $$ = converttype($$, 0, var->type);
1490 $$ = abc_setlocal($$, var->index);
1492 $$ = code_append($$, $6);
1493 $$ = abc_jump($$, loopstart);
1495 code_t*out = $$ = abc_nop($$);
1496 breakjumpsto($$, $1.name, out);
1497 continuejumpsto($$, $1.name, loopstart);
1508 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1511 code_t*myjmp = $$ = abc_jump($$, 0);
1512 code_t*loopstart = $$ = abc_label($$);
1513 $$ = code_append($$, $6);
1514 code_t*cont = $$ = abc_nop($$);
1515 myjmp->branch = cont;
1516 $$ = code_append($$, $4.c);
1517 $$ = abc_iftrue($$, loopstart);
1518 code_t*out = $$ = abc_nop($$);
1519 breakjumpsto($$, $1, out);
1520 continuejumpsto($$, $1, cont);
1526 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1528 code_t*loopstart = $$ = abc_label($$);
1529 $$ = code_append($$, $3);
1530 code_t*cont = $$ = abc_nop($$);
1531 $$ = code_append($$, $6.c);
1532 $$ = abc_iftrue($$, loopstart);
1533 code_t*out = $$ = abc_nop($$);
1534 breakjumpsto($$, $1, out);
1535 continuejumpsto($$, $1, cont);
1540 BREAK : "break" %prec prec_none {
1541 $$ = abc___break__(0, "");
1543 BREAK : "break" T_IDENTIFIER {
1544 $$ = abc___break__(0, $2);
1546 CONTINUE : "continue" %prec prec_none {
1547 $$ = abc___continue__(0, "");
1549 CONTINUE : "continue" T_IDENTIFIER {
1550 $$ = abc___continue__(0, $2);
1553 MAYBE_CASE_LIST : {$$=0;}
1554 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1555 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1556 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1557 CASE_LIST: CASE {$$=$1}
1558 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1560 CASE: "case" E ':' MAYBECODE {
1562 $$ = code_append($$, $2.c);
1563 code_t*j = $$ = abc_ifne($$, 0);
1564 $$ = code_append($$, $4);
1565 if($$->opcode != OPCODE___BREAK__) {
1566 $$ = abc___fallthrough__($$, "");
1568 code_t*e = $$ = abc_nop($$);
1571 DEFAULT: "default" ':' MAYBECODE {
1574 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1576 $$ = code_append($$, $7);
1577 code_t*out = $$ = abc_pop($$);
1578 breakjumpsto($$, $1, out);
1580 code_t*c = $$,*lastblock=0;
1582 if(c->opcode == OPCODE_IFNE) {
1583 if(!c->next) syntaxerror("internal error in fallthrough handling");
1585 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1587 c->opcode = OPCODE_JUMP;
1588 c->branch = lastblock;
1590 /* fall through end of switch */
1591 c->opcode = OPCODE_NOP;
1599 /* ------------ try / catch /finally ---------------- */
1601 FINALLY: "finally" '{' CODE '}'
1602 MAYBE_FINALLY: | FINALLY
1604 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1607 int i = find_variable_safe($3)->index;
1608 c = abc_setlocal(c, i);
1609 c = code_append(c, $8);
1612 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1613 multiname_t name = {QNAME, &name_ns, 0, $3};
1615 NEW(abc_exception_t, e)
1616 e->exc_type = sig2mname($4);
1617 e->var_name = multiname_clone(&name);
1618 e->target = code_start(c);
1623 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1624 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1626 TRY : "try" '{' CODE '}' CATCH_LIST MAYBE_FINALLY {
1627 code_t*start = code_start($3);
1630 code_t*out = abc_nop(0);
1631 code_t*jmp = $$ = abc_jump($$, out);
1633 abc_exception_list_t*l = $5;
1635 abc_exception_t*e = l->abc_exception;
1638 $$ = code_append($$, e->target);
1639 $$ = abc_jump($$, out);
1642 $$ = code_append($$, out);
1645 list_concat(state->method->exceptions, $5);
1648 /* ------------ throw ------------------------------- */
1650 THROW : "throw" EXPRESSION {
1654 THROW : "throw" %prec prec_none {
1655 if(!state->exception_name)
1656 syntaxerror("re-throw only possible within a catch block");
1657 variable_t*v = find_variable(state->exception_name);
1659 $$=abc_getlocal($$, v->index);
1663 /* ------------ with -------------------------------- */
1665 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1667 $$ = abc_pushscope($$);
1668 $$ = code_append($$, $5);
1669 $$ = abc_popscope($$);
1672 /* ------------ packages and imports ---------------- */
1674 X_IDENTIFIER: T_IDENTIFIER
1675 | "package" {$$="package";}
1677 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1678 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1680 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1681 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1683 IMPORT : "import" QNAME {
1686 syntaxerror("Couldn't import class\n");
1687 state_has_imports();
1688 dict_put(state->imports, c->name, c);
1691 IMPORT : "import" PACKAGE '.' '*' {
1694 state_has_imports();
1695 list_append(state->wildcard_imports, i);
1699 /* ------------ classes and interfaces (header) -------------- */
1701 MAYBE_MODIFIERS : {$$=0;}
1702 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1703 MODIFIER_LIST : MODIFIER {$$=$1;}
1704 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1706 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1707 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1708 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1709 | KW_STATIC {$$=FLAG_STATIC;}
1710 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1711 | KW_FINAL {$$=FLAG_FINAL;}
1712 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1713 | KW_NATIVE {$$=FLAG_NATIVE;}
1714 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1716 EXTENDS : {$$=registry_getobjectclass();}
1717 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1719 EXTENDS_LIST : {$$=list_new();}
1720 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1722 IMPLEMENTS_LIST : {$$=list_new();}
1723 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1725 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1726 EXTENDS IMPLEMENTS_LIST
1727 '{' {startclass($1,$3,$4,$5, 0);}
1729 '}' {endclass();$$=0;}
1731 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1733 '{' {startclass($1,$3,0,$4,1);}
1734 MAYBE_INTERFACE_BODY
1735 '}' {endclass();$$=0;}
1737 /* ------------ classes and interfaces (body) -------------- */
1740 MAYBE_CLASS_BODY : CLASS_BODY
1741 CLASS_BODY : CLASS_BODY_ITEM
1742 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1743 CLASS_BODY_ITEM : ';'
1744 CLASS_BODY_ITEM : SLOT_DECLARATION
1745 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1747 CLASS_BODY_ITEM : CODE_STATEMENT {
1748 code_t*c = state->cls->static_init;
1749 c = code_append(c, $1);
1750 state->cls->static_init = c;
1753 MAYBE_INTERFACE_BODY :
1754 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1755 INTERFACE_BODY : IDECLARATION
1756 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1758 IDECLARATION : "var" T_IDENTIFIER {
1759 syntaxerror("variable declarations not allowed in interfaces");
1761 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1763 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1764 syntaxerror("invalid method modifiers: interface methods always need to be public");
1766 startfunction(0,$1,$3,$4,&$6,$8);
1767 endfunction(0,$1,$3,$4,&$6,$8, 0);
1770 /* ------------ classes and interfaces (body, slots ) ------- */
1772 VARCONST: "var" | "const"
1774 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1776 memberinfo_t* info = state->cls?
1777 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1778 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1781 info->flags = flags;
1784 namespace_t mname_ns = {flags2access(flags), ""};
1785 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1787 trait_list_t**traits;
1791 traits = &global->init->traits;
1792 code = &global->init->method->body->code;
1793 } else if(flags&FLAG_STATIC) {
1795 traits = &state->cls->abc->static_traits;
1796 code = &state->cls->static_init;
1798 // instance variable
1799 traits = &state->cls->abc->traits;
1800 code = &state->cls->init;
1806 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1808 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1810 info->slot = t->slot_id;
1812 /* initalization code (if needed) */
1814 if($5.c && !is_pushundefined($5.c)) {
1815 c = abc_getlocal_0(c);
1816 c = code_append(c, $5.c);
1817 c = converttype(c, $5.t, $4);
1818 c = abc_setslot(c, t->slot_id);
1821 *code = code_append(*code, c);
1824 t->kind= TRAIT_CONST;
1830 /* ------------ constants -------------------------------------- */
1832 MAYBESTATICCONSTANT: {$$=0;}
1833 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1835 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1836 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1837 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1838 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1839 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1840 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1841 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1842 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1843 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1845 /* ------------ classes and interfaces (body, functions) ------- */
1847 // non-vararg version
1849 memset(&$$,0,sizeof($$));
1851 MAYBE_PARAM_LIST: PARAM_LIST {
1856 MAYBE_PARAM_LIST: "..." PARAM {
1857 memset(&$$,0,sizeof($$));
1859 list_append($$.list, $2);
1861 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1864 list_append($$.list, $4);
1868 PARAM_LIST: PARAM_LIST ',' PARAM {
1870 list_append($$.list, $3);
1873 memset(&$$,0,sizeof($$));
1874 list_append($$.list, $1);
1877 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1878 $$ = malloc(sizeof(param_t));
1883 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1884 $$ = malloc(sizeof(param_t));
1886 $$->type = TYPE_ANY;
1889 GETSET : "get" {$$=$1;}
1893 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1894 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1897 if(state->method->late_binding) {
1898 c = abc_getlocal_0(c);
1899 c = abc_pushscope(c);
1901 if(state->method->is_constructor && !state->method->has_super) {
1902 // call default constructor
1903 c = abc_getlocal_0(c);
1904 c = abc_constructsuper(c, 0);
1906 c = wrap_function(c, state->method->initcode, $11);
1907 endfunction(0,$1,$3,$4,&$6,$8,c);
1911 /* ------------- package + class ids --------------- */
1913 CLASS: T_IDENTIFIER {
1915 /* try current package */
1916 $$ = find_class($1);
1917 if(!$$) syntaxerror("Could not find class %s\n", $1);
1920 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1921 $$ = registry_findclass($1, $3);
1922 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1926 QNAME: PACKAGEANDCLASS
1929 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1930 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1932 TYPE : QNAME {$$=$1;}
1933 | '*' {$$=registry_getanytype();}
1934 | "void" {$$=registry_getanytype();}
1936 | "String" {$$=registry_getstringclass();}
1937 | "int" {$$=registry_getintclass();}
1938 | "uint" {$$=registry_getuintclass();}
1939 | "Boolean" {$$=registry_getbooleanclass();}
1940 | "Number" {$$=registry_getnumberclass();}
1943 MAYBETYPE: ':' TYPE {$$=$2;}
1946 /* ----------function calls, delete, constructor calls ------ */
1948 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
1949 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1951 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1952 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1953 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
1956 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1958 $$.cc = code_append($1.cc, $3.c);
1961 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1966 $$.c = abc_getglobalscope($$.c);
1967 $$.c = abc_getslot($$.c, $2->slot);
1969 $$.c = abc_findpropstrict2($$.c, &m);
1972 $$.c = code_append($$.c, $3.cc);
1975 $$.c = abc_construct($$.c, $3.len);
1977 $$.c = abc_constructprop2($$.c, &m, $3.len);
1981 /* TODO: use abc_call (for calling local variables),
1982 abc_callstatic (for calling own methods)
1985 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1988 if($$.c->opcode == OPCODE_COERCE_A) {
1989 $$.c = code_cutlast($$.c);
1991 code_t*paramcode = $3.cc;
1994 if($$.c->opcode == OPCODE_GETPROPERTY) {
1995 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1996 $$.c = code_cutlast($$.c);
1997 $$.c = code_append($$.c, paramcode);
1998 $$.c = abc_callproperty2($$.c, name, $3.len);
1999 multiname_destroy(name);
2000 } else if($$.c->opcode == OPCODE_GETSLOT) {
2001 int slot = (int)(ptroff_t)$$.c->data[0];
2002 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2003 if(t->kind!=TRAIT_METHOD) {
2004 //ok: flash allows to assign closures to members.
2006 multiname_t*name = t->name;
2007 $$.c = code_cutlast($$.c);
2008 $$.c = code_append($$.c, paramcode);
2009 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2010 $$.c = abc_callproperty2($$.c, name, $3.len);
2011 } else if($$.c->opcode == OPCODE_GETSUPER) {
2012 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2013 $$.c = code_cutlast($$.c);
2014 $$.c = code_append($$.c, paramcode);
2015 $$.c = abc_callsuper2($$.c, name, $3.len);
2016 multiname_destroy(name);
2018 $$.c = abc_getlocal_0($$.c);
2019 $$.c = code_append($$.c, paramcode);
2020 $$.c = abc_call($$.c, $3.len);
2025 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2026 $$.t = $1.t->function->return_type;
2028 $$.c = abc_coerce_a($$.c);
2033 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2034 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2035 if(!state->method) syntaxerror("super() not allowed outside of a function");
2036 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2039 $$.c = abc_getlocal_0($$.c);
2041 $$.c = code_append($$.c, $3.cc);
2043 this is dependent on the control path, check this somewhere else
2044 if(state->method->has_super)
2045 syntaxerror("constructor may call super() only once");
2047 state->method->has_super = 1;
2048 $$.c = abc_constructsuper($$.c, $3.len);
2049 $$.c = abc_pushundefined($$.c);
2053 DELETE: "delete" E {
2055 if($$.c->opcode == OPCODE_COERCE_A) {
2056 $$.c = code_cutlast($$.c);
2058 multiname_t*name = 0;
2059 if($$.c->opcode == OPCODE_GETPROPERTY) {
2060 $$.c->opcode = OPCODE_DELETEPROPERTY;
2061 } else if($$.c->opcode == OPCODE_GETSLOT) {
2062 int slot = (int)(ptroff_t)$$.c->data[0];
2063 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2064 $$.c = code_cutlast($$.c);
2065 $$.c = abc_deleteproperty2($$.c, name);
2067 $$.c = abc_getlocal_0($$.c);
2068 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2069 $$.c = abc_deleteproperty2($$.c, &m);
2071 $$.t = TYPE_BOOLEAN;
2074 RETURN: "return" %prec prec_none {
2075 $$ = abc_returnvoid(0);
2077 RETURN: "return" EXPRESSION {
2079 $$ = abc_returnvalue($$);
2082 // ----------------------- expression types -------------------------------------
2084 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2085 EXPRESSION : E %prec below_minus {$$ = $1;}
2086 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2088 $$.c = cut_last_push($$.c);
2089 $$.c = code_append($$.c,$3.c);
2092 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2093 $$=cut_last_push($1.c);
2096 // ----------------------- expression evaluation -------------------------------------
2099 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2101 E : DELETE {$$ = $1;}
2102 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
2106 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2107 //MULTINAME(m, registry_getintclass());
2108 //$$.c = abc_coerce2($$.c, &m); // FIXME
2111 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2114 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2117 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2120 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2123 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2126 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2129 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2130 $$.t = TYPE_BOOLEAN;
2132 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2133 $$.t = TYPE_BOOLEAN;
2135 CONSTANT : "null" {$$.c = abc_pushnull(0);
2140 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2141 $$.t = TYPE_BOOLEAN;
2143 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2144 $$.t = TYPE_BOOLEAN;
2146 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2147 $$.t = TYPE_BOOLEAN;
2149 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2150 $$.t = TYPE_BOOLEAN;
2152 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2153 $$.t = TYPE_BOOLEAN;
2155 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2156 $$.t = TYPE_BOOLEAN;
2158 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2159 $$.t = TYPE_BOOLEAN;
2161 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2162 $$.t = TYPE_BOOLEAN;
2165 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2167 $$.c = converttype($$.c, $1.t, $$.t);
2168 $$.c = abc_dup($$.c);
2169 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2170 $$.c = cut_last_push($$.c);
2171 $$.c = code_append($$.c,$3.c);
2172 $$.c = converttype($$.c, $3.t, $$.t);
2173 code_t*label = $$.c = abc_label($$.c);
2174 jmp->branch = label;
2177 $$.t = join_types($1.t, $3.t, 'A');
2178 /*printf("%08x:\n",$1.t);
2179 code_dump($1.c, 0, 0, "", stdout);
2180 printf("%08x:\n",$3.t);
2181 code_dump($3.c, 0, 0, "", stdout);
2182 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2184 $$.c = converttype($$.c, $1.t, $$.t);
2185 $$.c = abc_dup($$.c);
2186 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2187 $$.c = cut_last_push($$.c);
2188 $$.c = code_append($$.c,$3.c);
2189 $$.c = converttype($$.c, $3.t, $$.t);
2190 code_t*label = $$.c = abc_label($$.c);
2191 jmp->branch = label;
2194 E : '!' E {$$.c=$2.c;
2195 $$.c = abc_not($$.c);
2196 $$.t = TYPE_BOOLEAN;
2199 E : '~' E {$$.c=$2.c;
2200 $$.c = abc_bitnot($$.c);
2204 E : E '&' E {$$.c = code_append($1.c,$3.c);
2205 $$.c = abc_bitand($$.c);
2209 E : E '^' E {$$.c = code_append($1.c,$3.c);
2210 $$.c = abc_bitxor($$.c);
2214 E : E '|' E {$$.c = code_append($1.c,$3.c);
2215 $$.c = abc_bitor($$.c);
2219 E : E '-' E {$$.c = code_append($1.c,$3.c);
2220 if(BOTH_INT($1,$3)) {
2221 $$.c = abc_subtract_i($$.c);
2224 $$.c = abc_subtract($$.c);
2228 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2229 $$.c = abc_rshift($$.c);
2232 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2233 $$.c = abc_urshift($$.c);
2236 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2237 $$.c = abc_lshift($$.c);
2241 E : E '/' E {$$.c = code_append($1.c,$3.c);
2242 $$.c = abc_divide($$.c);
2245 E : E '+' E {$$.c = code_append($1.c,$3.c);
2246 $$.c = abc_add($$.c);
2249 E : E '%' E {$$.c = code_append($1.c,$3.c);
2250 $$.c = abc_modulo($$.c);
2253 E : E '*' E {$$.c = code_append($1.c,$3.c);
2254 if(BOTH_INT($1,$3)) {
2255 $$.c = abc_multiply_i($$.c);
2258 $$.c = abc_multiply($$.c);
2263 E : E "in" E {$$.c = code_append($1.c,$3.c);
2264 $$.c = abc_in($$.c);
2265 $$.t = TYPE_BOOLEAN;
2268 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2269 if(use_astype && TYPE_IS_CLASS($3.t)) {
2270 MULTINAME(m,$3.t->cls);
2271 $$.c = abc_astype2($1.c, &m);
2274 $$.c = code_append($1.c, $3.c);
2275 $$.c = abc_astypelate($$.c);
2280 E : E "instanceof" E
2281 {$$.c = code_append($1.c, $3.c);
2282 $$.c = abc_instanceof($$.c);
2283 $$.t = TYPE_BOOLEAN;
2286 E : E "is" E {$$.c = code_append($1.c, $3.c);
2287 $$.c = abc_istypelate($$.c);
2288 $$.t = TYPE_BOOLEAN;
2291 E : "typeof" '(' E ')' {
2293 $$.c = abc_typeof($$.c);
2298 $$.c = cut_last_push($2.c);
2299 $$.c = abc_pushundefined($$.c);
2303 E : "void" { $$.c = abc_pushundefined(0);
2307 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2312 $$.c=abc_negate_i($$.c);
2315 $$.c=abc_negate($$.c);
2322 $$.c = code_append($$.c, $3.c);
2324 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2325 $$.c = abc_getproperty2($$.c, &m);
2326 $$.t = 0; // array elements have unknown type
2329 E : '[' MAYBE_EXPRESSION_LIST ']' {
2331 $$.c = code_append($$.c, $2.cc);
2332 $$.c = abc_newarray($$.c, $2.len);
2333 $$.t = registry_getarrayclass();
2336 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2337 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2339 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2341 $$.cc = code_append($$.cc, $1.c);
2342 $$.cc = code_append($$.cc, $3.c);
2345 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2348 $$.cc = code_append($$.cc, $3.c);
2349 $$.cc = code_append($$.cc, $5.c);
2354 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2356 $$.c = code_append($$.c, $2.cc);
2357 $$.c = abc_newobject($$.c, $2.len/2);
2358 $$.t = registry_getobjectclass();
2363 if(BOTH_INT($1,$3)) {
2364 c=abc_multiply_i(c);
2368 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2369 $$.c = toreadwrite($1.c, c, 0, 0);
2374 code_t*c = abc_modulo($3.c);
2375 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2376 $$.c = toreadwrite($1.c, c, 0, 0);
2380 code_t*c = abc_lshift($3.c);
2381 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2382 $$.c = toreadwrite($1.c, c, 0, 0);
2386 code_t*c = abc_rshift($3.c);
2387 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2388 $$.c = toreadwrite($1.c, c, 0, 0);
2392 code_t*c = abc_urshift($3.c);
2393 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2394 $$.c = toreadwrite($1.c, c, 0, 0);
2398 code_t*c = abc_divide($3.c);
2399 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2400 $$.c = toreadwrite($1.c, c, 0, 0);
2404 code_t*c = abc_bitor($3.c);
2405 c=converttype(c, TYPE_INT, $1.t);
2406 $$.c = toreadwrite($1.c, c, 0, 0);
2411 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2416 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2418 $$.c = toreadwrite($1.c, c, 0, 0);
2421 E : E "-=" E { code_t*c = $3.c;
2422 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2423 c=abc_subtract_i(c);
2427 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2429 $$.c = toreadwrite($1.c, c, 0, 0);
2432 E : E '=' E { code_t*c = 0;
2433 c = code_append(c, $3.c);
2434 c = converttype(c, $3.t, $1.t);
2435 $$.c = toreadwrite($1.c, c, 1, 0);
2439 E : E '?' E ':' E %prec below_assignment {
2441 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2442 $$.c = code_append($$.c, $3.c);
2443 code_t*j2 = $$.c = abc_jump($$.c, 0);
2444 $$.c = j1->branch = abc_label($$.c);
2445 $$.c = code_append($$.c, $5.c);
2446 $$.c = j2->branch = abc_label($$.c);
2447 $$.t = join_types($3.t,$5.t,'?');
2450 // TODO: use inclocal where appropriate
2451 E : E "++" { code_t*c = 0;
2452 classinfo_t*type = $1.t;
2453 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2454 c=abc_increment_i(c);
2460 c=converttype(c, type, $1.t);
2461 $$.c = toreadwrite($1.c, c, 0, 1);
2464 E : E "--" { code_t*c = 0;
2465 classinfo_t*type = $1.t;
2466 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2467 c=abc_decrement_i(c);
2473 c=converttype(c, type, $1.t);
2474 $$.c = toreadwrite($1.c, c, 0, 1);
2478 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2479 classinfo_t*type = $2.t;
2480 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2481 c=abc_increment_i(c);
2487 c=converttype(c, type, $2.t);
2488 $$.c = toreadwrite($2.c, c, 0, 0);
2492 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2493 classinfo_t*type = $2.t;
2494 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2495 c=abc_decrement_i(c);
2501 c=converttype(c, type, $2.t);
2502 $$.c = toreadwrite($2.c, c, 0, 0);
2506 E : "super" '.' T_IDENTIFIER
2507 { if(!state->cls->info)
2508 syntaxerror("super keyword not allowed outside a class");
2509 classinfo_t*t = state->cls->info->superclass;
2510 if(!t) t = TYPE_OBJECT;
2512 memberinfo_t*f = registry_findmember(t, $3, 1);
2513 namespace_t ns = {flags2access(f->flags), ""};
2514 MEMBER_MULTINAME(m, f, $3);
2516 $$.c = abc_getlocal_0($$.c);
2517 $$.c = abc_getsuper2($$.c, &m);
2518 $$.t = memberinfo_gettype(f);
2521 E : E '.' T_IDENTIFIER
2523 classinfo_t*t = $1.t;
2525 if(TYPE_IS_CLASS(t) && t->cls) {
2530 memberinfo_t*f = registry_findmember(t, $3, 1);
2532 if(f && !is_static != !(f->flags&FLAG_STATIC))
2534 if(f && f->slot && !noslot) {
2535 $$.c = abc_getslot($$.c, f->slot);
2537 MEMBER_MULTINAME(m, f, $3);
2538 $$.c = abc_getproperty2($$.c, &m);
2540 /* determine type */
2541 $$.t = memberinfo_gettype(f);
2543 $$.c = abc_coerce_a($$.c);
2545 /* when resolving a property on an unknown type, we do know the
2546 name of the property (and don't seem to need the package), but
2547 we need to make avm2 try out all access modes */
2548 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2549 $$.c = abc_getproperty2($$.c, &m);
2550 $$.c = abc_coerce_a($$.c);
2551 $$.t = registry_getanytype();
2555 VAR_READ : T_IDENTIFIER {
2562 /* look at variables */
2563 if((v = find_variable($1))) {
2564 // $1 is a local variable
2565 $$.c = abc_getlocal($$.c, v->index);
2568 /* look at current class' members */
2569 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2570 // $1 is a function in this class
2571 int var_is_static = (f->flags&FLAG_STATIC);
2572 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2573 if(var_is_static != i_am_static) {
2574 /* there doesn't seem to be any "static" way to access
2575 static properties of a class */
2576 state->method->late_binding = 1;
2578 namespace_t ns = {flags2access(f->flags), ""};
2579 multiname_t m = {QNAME, &ns, 0, $1};
2580 $$.c = abc_findpropstrict2($$.c, &m);
2581 $$.c = abc_getproperty2($$.c, &m);
2584 $$.c = abc_getlocal_0($$.c);
2585 $$.c = abc_getslot($$.c, f->slot);
2587 namespace_t ns = {flags2access(f->flags), ""};
2588 multiname_t m = {QNAME, &ns, 0, $1};
2589 $$.c = abc_getlocal_0($$.c);
2590 $$.c = abc_getproperty2($$.c, &m);
2593 if(f->kind == MEMBER_METHOD) {
2594 $$.t = TYPE_FUNCTION(f);
2599 /* look at actual classes, in the current package and imported */
2600 } else if((a = find_class($1))) {
2601 if(a->flags & FLAG_METHOD) {
2603 $$.c = abc_findpropstrict2($$.c, &m);
2604 $$.c = abc_getproperty2($$.c, &m);
2605 $$.t = TYPE_FUNCTION(a->function);
2608 $$.c = abc_getglobalscope($$.c);
2609 $$.c = abc_getslot($$.c, a->slot);
2612 $$.c = abc_getlex2($$.c, &m);
2614 $$.t = TYPE_CLASS(a);
2617 /* unknown object, let the avm2 resolve it */
2619 if(strcmp($1,"trace"))
2620 warning("Couldn't resolve '%s', doing late binding", $1);
2621 state->method->late_binding = 1;
2623 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2626 $$.c = abc_findpropstrict2($$.c, &m);
2627 $$.c = abc_getproperty2($$.c, &m);
2632 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2633 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2634 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2636 // ----------------- namespaces -------------------------------------------------
2638 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2639 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2640 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2642 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}