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
82 %token<token> KW_NAMESPACE "namespace"
83 %token<token> KW_PACKAGE "package"
84 %token<token> KW_PROTECTED
85 %token<token> KW_PUBLIC
86 %token<token> KW_PRIVATE
87 %token<token> KW_USE "use"
88 %token<token> KW_INTERNAL
89 %token<token> KW_NEW "new"
90 %token<token> KW_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
102 %token<token> KW_INSTANCEOF "instanceof"
103 %token<token> KW_IMPORT "import"
104 %token<token> KW_RETURN "return"
105 %token<token> KW_TYPEOF "typeof"
106 %token<token> KW_INTERFACE "interface"
107 %token<token> KW_NULL "null"
108 %token<token> KW_VAR "var"
109 %token<token> KW_DYNAMIC "dynamic"
110 %token<token> KW_OVERRIDE
111 %token<token> KW_FINAL
112 %token<token> KW_EACH "each"
113 %token<token> KW_GET "get"
114 %token<token> KW_TRY "try"
115 %token<token> KW_SUPER "super"
116 %token<token> KW_EXTENDS
117 %token<token> KW_FALSE "false"
118 %token<token> KW_TRUE "true"
119 %token<token> KW_BOOLEAN "Boolean"
120 %token<token> KW_UINT "uint"
121 %token<token> KW_INT "int"
122 %token<token> KW_NUMBER "Number"
123 %token<token> KW_STRING "String"
124 %token<token> KW_DEFAULT "default"
125 %token<token> KW_DELETE "delete"
126 %token<token> KW_IF "if"
127 %token<token> KW_ELSE "else"
128 %token<token> KW_BREAK "break"
129 %token<token> KW_IS "is"
130 %token<token> KW_IN "in"
131 %token<token> KW_AS "as"
133 %token<token> T_EQEQ "=="
134 %token<token> T_EQEQEQ "==="
135 %token<token> T_NE "!="
136 %token<token> T_NEE "!=="
137 %token<token> T_LE "<="
138 %token<token> T_GE ">="
139 %token<token> T_DIVBY "/="
140 %token<token> T_MODBY "%="
141 %token<token> T_MULBY "*="
142 %token<token> T_PLUSBY "+="
143 %token<token> T_MINUSBY "-="
144 %token<token> T_SHRBY ">>="
145 %token<token> T_SHLBY "<<="
146 %token<token> T_USHRBY ">>>="
147 %token<token> T_OROR "||"
148 %token<token> T_ANDAND "&&"
149 %token<token> T_COLONCOLON "::"
150 %token<token> T_MINUSMINUS "--"
151 %token<token> T_PLUSPLUS "++"
152 %token<token> T_DOTDOT ".."
153 %token<token> T_DOTDOTDOT "..."
154 %token<token> T_SHL "<<"
155 %token<token> T_USHR ">>>"
156 %token<token> T_SHR ">>"
158 %type <for_start> FOR_START
159 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
160 %type <token> VARCONST
162 %type <code> CODEPIECE CODE_STATEMENT
163 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
164 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
165 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
166 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
167 %type <exception> CATCH
168 %type <exception_list> CATCH_LIST
169 %type <code> CLASS_DECLARATION
170 %type <code> NAMESPACE_DECLARATION
171 %type <code> INTERFACE_DECLARATION
172 %type <code> VOIDEXPRESSION
173 %type <value> EXPRESSION NONCOMMAEXPRESSION
174 %type <value> MAYBEEXPRESSION
175 %type <value> E DELETE
176 %type <value> CONSTANT
177 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
178 %type <token> USE_NAMESPACE
179 %type <code> FOR_INIT
181 %type <classinfo> MAYBETYPE
184 %type <params> PARAM_LIST
185 %type <params> MAYBE_PARAM_LIST
186 %type <flags> MAYBE_MODIFIERS
187 %type <flags> MODIFIER_LIST
188 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
189 %type <classinfo_list> IMPLEMENTS_LIST
190 %type <classinfo> EXTENDS
191 %type <classinfo_list> EXTENDS_LIST
192 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
193 %type <classinfo_list> QNAME_LIST
194 %type <classinfo> TYPE
195 //%type <token> VARIABLE
196 %type <value> VAR_READ
198 //%type <token> T_IDENTIFIER
199 %type <token> MODIFIER
200 %type <value> FUNCTIONCALL
201 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
203 // precedence: from low to high
207 %left below_semicolon
210 %nonassoc below_assignment // for ?:, contrary to spec
211 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
218 %nonassoc "==" "!=" "===" "!=="
219 %nonassoc "is" "as" "in"
220 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
221 %left "<<" ">>" ">>>"
225 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
227 %nonassoc below_curly
228 %left '[' ']' '{' "new" '.' ".." "::"
229 %nonassoc T_IDENTIFIER
230 %left above_identifier
235 // needed for "return" precedence:
236 %nonassoc T_STRING T_REGEXP
237 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
238 %nonassoc "false" "true" "null" "undefined" "super"
244 static int yyerror(char*s)
246 syntaxerror("%s", s);
249 static char* concat2(const char* t1, const char* t2)
253 char*text = malloc(l1+l2+1);
254 memcpy(text , t1, l1);
255 memcpy(text+l1, t2, l2);
259 static char* concat3(const char* t1, const char* t2, const char* t3)
264 char*text = malloc(l1+l2+l3+1);
265 memcpy(text , t1, l1);
266 memcpy(text+l1, t2, l2);
267 memcpy(text+l1+l2, t3, l3);
272 typedef struct _import {
276 DECLARE_LIST(import);
278 typedef struct _classstate {
284 char has_constructor;
287 typedef struct _methodstate {
291 /* code that needs to be executed at the start of
292 a method (like initializing local registers) */
297 abc_exception_list_t*exceptions;
300 typedef struct _state {
305 import_list_t*wildcard_imports;
307 char has_own_imports;
310 methodstate_t*method;
317 typedef struct _global {
324 static global_t*global = 0;
325 static state_t* state = 0;
329 #define MULTINAME(m,x) \
332 registry_fill_multiname(&m, &m##_ns, x);
334 #define MEMBER_MULTINAME(m,f,n) \
338 m##_ns.access = flags2access(f->flags); \
342 m.namespace_set = 0; \
345 m.type = MULTINAME; \
347 m.namespace_set = &nopackage_namespace_set; \
351 /* warning: list length of namespace set is undefined */
352 #define MULTINAME_LATE(m, access, package) \
353 namespace_t m##_ns = {access, package}; \
354 namespace_set_t m##_nsset; \
355 namespace_list_t m##_l;m##_l.next = 0; \
356 m##_nsset.namespaces = &m##_l; \
357 m##_nsset = m##_nsset; \
358 m##_l.namespace = &m##_ns; \
359 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
361 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
362 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
363 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
364 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
365 static namespace_list_t nl4 = {&ns4,0};
366 static namespace_list_t nl3 = {&ns3,&nl4};
367 static namespace_list_t nl2 = {&ns2,&nl3};
368 static namespace_list_t nl1 = {&ns1,&nl2};
369 static namespace_set_t nopackage_namespace_set = {&nl1};
371 static void new_state()
374 state_t*oldstate = state;
376 memcpy(s, state, sizeof(state_t)); //shallow copy
378 s->imports = dict_new();
382 state->has_own_imports = 0;
383 state->vars = dict_new();
384 state->old = oldstate;
386 static void state_has_imports()
388 state->wildcard_imports = list_clone(state->wildcard_imports);
389 state->imports = dict_clone(state->imports);
390 state->has_own_imports = 1;
393 static void state_destroy(state_t*state)
395 if(state->has_own_imports) {
396 list_free(state->wildcard_imports);
397 dict_destroy(state->imports);state->imports=0;
399 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
400 dict_destroy(state->imports);state->imports=0;
404 for(t=0;t<state->vars->hashsize;t++) {
405 dictentry_t*e =state->vars->slots[t];
407 free(e->data);e->data=0;
411 dict_destroy(state->vars);state->vars=0;
417 static void old_state()
419 if(!state || !state->old)
420 syntaxerror("invalid nesting");
421 state_t*leaving = state;
423 /*if(state->method->initcode) {
424 printf("residual initcode\n");
425 code_dump(state->method->initcode, 0, 0, "", stdout);
427 state_destroy(leaving);
429 void initialize_state()
431 global = rfx_calloc(sizeof(global_t));
434 state->package = current_filename;
436 global->file = abc_file_new();
437 global->file->flags &= ~ABCFILE_LAZY;
438 global->variable_count = 1;
440 global->init = abc_initscript(global->file, 0);
441 code_t*c = global->init->method->body->code;
443 c = abc_getlocal_0(c);
444 c = abc_pushscope(c);
446 /* findpropstrict doesn't just return a scope object- it
447 also makes it "active" somehow. Push local_0 on the
448 scope stack and read it back with findpropstrict, it'll
449 contain properties like "trace". Trying to find the same
450 property on a "vanilla" local_0 yields only a "undefined" */
451 //c = abc_findpropstrict(c, "[package]::trace");
453 /*c = abc_getlocal_0(c);
454 c = abc_findpropstrict(c, "[package]::trace");
456 c = abc_setlocal_1(c);
458 c = abc_pushbyte(c, 0);
459 c = abc_setlocal_2(c);
461 code_t*xx = c = abc_label(c);
462 c = abc_findpropstrict(c, "[package]::trace");
463 c = abc_pushstring(c, "prop:");
464 c = abc_hasnext2(c, 1, 2);
466 c = abc_setlocal_3(c);
467 c = abc_callpropvoid(c, "[package]::trace", 2);
468 c = abc_getlocal_3(c);
470 c = abc_iftrue(c,xx);*/
472 c = abc_findpropstrict(c, "[package]::trace");
473 c = abc_pushstring(c, "[entering global init function]");
474 c = abc_callpropvoid(c, "[package]::trace", 1);
476 global->init->method->body->code = c;
478 void* finalize_state()
480 if(state->level!=1) {
481 syntaxerror("unexpected end of file");
483 abc_method_body_t*m = global->init->method->body;
486 __ findpropstrict(m, "[package]::trace");
487 __ pushstring(m, "[leaving global init function]");
488 __ callpropvoid(m, "[package]::trace", 1);
491 state_destroy(state);
497 static void startpackage(char*name)
500 /*printf("entering package \"%s\"\n", name);*/
501 state->package = strdup(name);
502 global->variable_count = 1;
504 static void endpackage()
506 /*printf("leaving package \"%s\"\n", state->package);*/
508 //used e.g. in classinfo_register:
509 //free(state->package);state->package=0;
515 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
518 syntaxerror("inner classes now allowed");
521 global->variable_count = 1;
522 state->cls = rfx_calloc(sizeof(classstate_t));
525 classinfo_list_t*mlist=0;
526 /*printf("entering class %s\n", name);
527 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
529 printf(" extends: %s.%s\n", extends->package, extends->name);
530 printf(" implements (%d): ", list_length(implements));
531 for(mlist=implements;mlist;mlist=mlist->next) {
532 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
537 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
538 syntaxerror("invalid modifier(s)");
540 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
541 syntaxerror("public and internal not supported at the same time.");
543 /* create the class name, together with the proper attributes */
547 if(!(flags&FLAG_PUBLIC) && !state->package) {
548 access = ACCESS_PRIVATE; package = current_filename;
549 } else if(!(flags&FLAG_PUBLIC) && state->package) {
550 access = ACCESS_PACKAGEINTERNAL; package = state->package;
551 } else if(state->package) {
552 access = ACCESS_PACKAGE; package = state->package;
554 syntaxerror("public classes only allowed inside a package");
557 if(registry_findclass(package, classname)) {
558 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
562 /* build info struct */
563 int num_interfaces = (list_length(implements));
564 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
565 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
567 classinfo_list_t*l = implements;
568 for(l=implements;l;l=l->next) {
569 state->cls->info->interfaces[pos++] = l->classinfo;
572 multiname_t*extends2 = sig2mname(extends);
574 MULTINAME(classname2,state->cls->info);
577 state->cls_init = abc_getlocal_0(state->cls_init);
578 state->cls_init = abc_constructsuper(state->cls_init, 0);
581 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
582 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
583 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
585 state->cls->info->flags |= CLASS_INTERFACE;
586 abc_class_interface(state->cls->abc);
589 abc_class_protectedNS(state->cls->abc, classname);
591 for(mlist=implements;mlist;mlist=mlist->next) {
592 MULTINAME(m, mlist->classinfo);
593 abc_class_add_interface(state->cls->abc, &m);
596 /* now write the construction code for this class */
597 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
599 abc_method_body_t*m = global->init->method->body;
600 __ getglobalscope(m);
601 classinfo_t*s = extends;
606 //TODO: take a look at the current scope stack, maybe
607 // we can re-use something
612 multiname_t*s2 = sig2mname(s);
614 multiname_destroy(s2);
616 __ pushscope(m); count++;
617 m->code = m->code->prev->prev; // invert
619 /* continue appending after last op end */
620 while(m->code && m->code->next) m->code = m->code->next;
622 /* TODO: if this is one of *our* classes, we can also
623 do a getglobalscope/getslot <nr> (which references
624 the init function's slots) */
626 __ getlex2(m, extends2);
628 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
629 stack is not the superclass */
630 __ pushscope(m);count++;
633 /* notice: we get a verify error #1107 if the top element on the scope
634 stack is not the global object */
636 __ pushscope(m);count++;
638 __ newclass(m,state->cls->abc);
642 __ setslot(m, slotindex);
644 /* flash.display.MovieClip handling */
645 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
646 if(state->package && state->package[0]) {
647 globalclass = concat3(state->package, ".", classname);
649 globalclass = strdup(classname);
652 multiname_destroy(extends2);
655 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
657 c = code_append(c, initcode);
658 c = code_append(c, body);
659 /* append return if necessary */
660 if(!c || c->opcode != OPCODE_RETURNVOID &&
661 c->opcode != OPCODE_RETURNVALUE) {
662 c = abc_returnvoid(c);
667 static void endclass()
669 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
671 c = abc_getlocal_0(c);
672 c = abc_constructsuper(c, 0);
673 state->cls->init = code_append(state->cls->init, c);
676 if(state->cls->init) {
677 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
678 m->body->code = wrap_function(0, state->cls->init, m->body->code);
680 if(state->cls->static_init) {
681 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
682 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
684 // handy for scope testing
688 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
691 free(state->cls);state->cls=0;
695 typedef struct _variable {
700 static variable_t* find_variable(char*name)
706 v = dict_lookup(s->vars, name);
714 static variable_t* find_variable_safe(char*name)
716 variable_t* v = find_variable(name);
718 syntaxerror("undefined variable: %s", name);
721 static char variable_exists(char*name)
723 return dict_lookup(state->vars, name)!=0;
725 code_t*defaultvalue(code_t*c, classinfo_t*type);
726 static int new_variable(char*name, classinfo_t*type, char init)
729 v->index = global->variable_count;
732 dict_put(state->vars, name, v);
734 if(init && state->method && type) {
735 /* if this is a typed variable:
736 push default value for type on stack at the very beginning of the
737 method, so that it always has that type regardless of the control
739 state->method->initcode = defaultvalue(state->method->initcode, type);
740 state->method->initcode = abc_setlocal(state->method->initcode, v->index);
742 return global->variable_count++;
744 #define TEMPVARNAME "__as3_temp__"
745 static int gettempvar()
747 variable_t*v = find_variable(TEMPVARNAME);
750 return new_variable(TEMPVARNAME, 0, 0);
753 code_t* killvars(code_t*c)
756 for(t=0;t<state->vars->hashsize;t++) {
757 dictentry_t*e =state->vars->slots[t];
759 variable_t*v = (variable_t*)e->data;
760 //do this always, otherwise register types don't match
761 //in the verifier when doing nested loops
762 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
763 c = abc_kill(c, v->index);
770 void check_code_for_break(code_t*c)
773 if(c->opcode == OPCODE___BREAK__) {
774 char*name = string_cstr(c->data[0]);
775 syntaxerror("Unresolved \"break %s\"", name);
777 if(c->opcode == OPCODE___CONTINUE__) {
778 char*name = string_cstr(c->data[0]);
779 syntaxerror("Unresolved \"continue %s\"", name);
786 static void check_constant_against_type(classinfo_t*t, constant_t*c)
788 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
789 if(TYPE_IS_NUMBER(t)) {
790 xassert(c->type == CONSTANT_FLOAT
791 || c->type == CONSTANT_INT
792 || c->type == CONSTANT_UINT);
793 } else if(TYPE_IS_UINT(t)) {
794 xassert(c->type == CONSTANT_UINT ||
795 (c->type == CONSTANT_INT && c->i>0));
796 } else if(TYPE_IS_INT(t)) {
797 xassert(c->type == CONSTANT_INT);
798 } else if(TYPE_IS_BOOLEAN(t)) {
799 xassert(c->type == CONSTANT_TRUE
800 || c->type == CONSTANT_FALSE);
804 static int flags2access(int flags)
807 if(flags&FLAG_PUBLIC) {
808 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
809 access = ACCESS_PACKAGE;
810 } else if(flags&FLAG_PRIVATE) {
811 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
812 access = ACCESS_PRIVATE;
813 } else if(flags&FLAG_PROTECTED) {
814 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
815 access = ACCESS_PROTECTED;
817 access = ACCESS_PACKAGEINTERNAL;
822 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
824 memberinfo_t*minfo = 0;
827 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
828 minfo->return_type = return_type;
829 } else if(getset != KW_GET && getset != KW_SET) {
831 if((minfo = registry_findmember(state->cls->info, name, 0))) {
832 if(minfo->parent == state->cls->info) {
833 syntaxerror("class already contains a member/method called '%s'", name);
834 } else if(!minfo->parent) {
835 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
837 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
838 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
841 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
842 minfo->return_type = return_type;
843 // getslot on a member slot only returns "undefined", so no need
844 // to actually store these
845 //state->minfo->slot = state->method->abc->method->trait->slot_id;
847 //class getter/setter
848 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
852 else if(params->list)
853 type = params->list->param->type;
854 // not sure wether to look into superclasses here, too
855 if((minfo=registry_findmember(state->cls->info, name, 0))) {
856 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
857 syntaxerror("class already contains a member or method called '%s'", name);
859 syntaxerror("getter/setter for '%s' already defined", name);
860 /* make a setter or getter into a getset */
865 if(type && minfo->type != type)
866 syntaxerror("different type in getter and setter");
868 minfo = memberinfo_register(state->cls->info, name, gs);
871 /* can't assign a slot as getter and setter might have different slots */
872 //minfo->slot = slot;
874 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
875 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
876 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
877 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
878 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
879 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
883 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
884 params_t*params, classinfo_t*return_type)
887 syntaxerror("not able to start another method scope");
890 global->variable_count = 0;
891 state->method = rfx_calloc(sizeof(methodstate_t));
892 state->method->initcode = 0;
893 state->method->has_super = 0;
895 state->method->is_constructor = !strcmp(state->cls->info->name,name);
896 state->cls->has_constructor |= state->method->is_constructor;
898 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
900 state->method->is_global = 1;
901 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
903 new_variable("globalscope", 0, 0);
906 /* state->vars is initialized by state_new */
909 for(p=params->list;p;p=p->next) {
910 new_variable(p->param->name, p->param->type, 0);
912 if(state->method->is_constructor)
913 name = "__as3_constructor__";
914 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
917 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
918 params_t*params, classinfo_t*return_type, code_t*body)
922 multiname_t*type2 = sig2mname(return_type);
924 if(state->method->is_constructor) {
925 f = abc_class_getconstructor(state->cls->abc, type2);
926 } else if(!state->method->is_global) {
927 namespace_t mname_ns = {flags2access(flags), ""};
928 multiname_t mname = {QNAME, &mname_ns, 0, name};
930 if(flags&FLAG_STATIC)
931 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
933 f = abc_class_method(state->cls->abc, type2, &mname);
934 slot = f->trait->slot_id;
936 namespace_t mname_ns = {flags2access(flags), state->package};
937 multiname_t mname = {QNAME, &mname_ns, 0, name};
939 f = abc_method_new(global->file, type2, 1);
940 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
941 //abc_code_t*c = global->init->method->body->code;
943 //flash doesn't seem to allow us to access function slots
944 //state->method->info->slot = slot;
946 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
947 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
948 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
949 if(params->varargs) f->flags |= METHOD_NEED_REST;
953 for(p=params->list;p;p=p->next) {
954 if(params->varargs && !p->next) {
955 break; //varargs: omit last parameter in function signature
957 multiname_t*m = sig2mname(p->param->type);
958 list_append(f->parameters, m);
959 if(p->param->value) {
960 check_constant_against_type(p->param->type, p->param->value);
961 opt=1;list_append(f->optional_parameters, p->param->value);
963 syntaxerror("non-optional parameter not allowed after optional parameters");
966 check_code_for_break(body);
969 f->body->code = body;
970 f->body->exceptions = state->method->exceptions;
973 syntaxerror("interface methods can't have a method body");
976 free(state->method);state->method=0;
982 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
987 void breakjumpsto(code_t*c, char*name, code_t*jump)
990 if(c->opcode == OPCODE___BREAK__) {
991 string_t*name2 = c->data[0];
992 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
993 c->opcode = OPCODE_JUMP;
1000 void continuejumpsto(code_t*c, char*name, code_t*jump)
1003 if(c->opcode == OPCODE___CONTINUE__) {
1004 string_t*name2 = c->data[0];
1005 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1006 c->opcode = OPCODE_JUMP;
1014 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1016 if(!type1 || !type2)
1017 return registry_getanytype();
1018 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1019 return registry_getanytype();
1022 return registry_getanytype();
1024 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1029 return abc_coerce_a(c);
1033 // cast an "any" type to a specific type. subject to
1034 // runtime exceptions
1035 return abc_coerce2(c, &m);
1038 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1039 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1040 // allow conversion between number types
1041 return abc_coerce2(c, &m);
1043 //printf("%s.%s\n", from.package, from.name);
1044 //printf("%s.%s\n", to.package, to.name);
1046 classinfo_t*supertype = from;
1048 if(supertype == to) {
1049 // target type is one of from's superclasses
1050 return abc_coerce2(c, &m);
1053 while(supertype->interfaces[t]) {
1054 if(supertype->interfaces[t]==to) {
1055 // target type is one of from's interfaces
1056 return abc_coerce2(c, &m);
1060 supertype = supertype->superclass;
1062 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1064 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1066 syntaxerror("can't convert type %s to %s", from->name, to->name);
1069 code_t*defaultvalue(code_t*c, classinfo_t*type)
1071 if(TYPE_IS_INT(type)) {
1072 c = abc_pushbyte(c, 0);
1073 } else if(TYPE_IS_UINT(type)) {
1074 c = abc_pushuint(c, 0);
1075 } else if(TYPE_IS_FLOAT(type)) {
1077 } else if(TYPE_IS_BOOLEAN(type)) {
1078 c = abc_pushfalse(c);
1080 c = abc_pushnull(c);
1085 char is_pushundefined(code_t*c)
1087 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1090 void parserassert(int b)
1092 if(!b) syntaxerror("internal error: assertion failed");
1095 static classinfo_t* find_class(char*name)
1099 c = registry_findclass(state->package, name);
1102 /* try explicit imports */
1103 dictentry_t* e = dict_get_slot(state->imports, name);
1106 if(!strcmp(e->key, name)) {
1107 c = (classinfo_t*)e->data;
1113 /* try package.* imports */
1114 import_list_t*l = state->wildcard_imports;
1116 //printf("does package %s contain a class %s?\n", l->import->package, name);
1117 c = registry_findclass(l->import->package, name);
1122 /* try global package */
1123 c = registry_findclass("", name);
1126 /* try local "filename" package */
1127 c = registry_findclass(current_filename, name);
1133 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1137 [prefix code] [read instruction]
1141 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1144 if(in && in->opcode == OPCODE_COERCE_A) {
1145 in = code_cutlast(in);
1148 syntaxerror("internal error");
1150 /* chop off read instruction */
1154 prefix = r->prev;r->prev = 0;
1160 char use_temp_var = readbefore;
1162 /* generate the write instruction, and maybe append a dup to the prefix code */
1163 code_t* write = abc_nop(0);
1164 if(r->opcode == OPCODE_GETPROPERTY) {
1165 write->opcode = OPCODE_SETPROPERTY;
1166 multiname_t*m = (multiname_t*)r->data[0];
1167 write->data[0] = multiname_clone(m);
1168 if(m->type == QNAME || m->type == MULTINAME) {
1170 prefix = abc_dup(prefix); // we need the object, too
1173 } else if(m->type == MULTINAMEL) {
1175 /* dupping two values on the stack requires 5 operations and one register-
1176 couldn't adobe just have given us a dup2? */
1177 int temp = gettempvar();
1178 prefix = abc_setlocal(prefix, temp);
1179 prefix = abc_dup(prefix);
1180 prefix = abc_getlocal(prefix, temp);
1181 prefix = abc_swap(prefix);
1182 prefix = abc_getlocal(prefix, temp);
1184 prefix = abc_kill(prefix, temp);
1188 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1190 } else if(r->opcode == OPCODE_GETSLOT) {
1191 write->opcode = OPCODE_SETSLOT;
1192 write->data[0] = r->data[0];
1194 prefix = abc_dup(prefix); // we need the object, too
1197 } else if(r->opcode == OPCODE_GETLOCAL) {
1198 write->opcode = OPCODE_SETLOCAL;
1199 write->data[0] = r->data[0];
1200 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1201 write->opcode = OPCODE_SETLOCAL_0;
1202 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1203 write->opcode = OPCODE_SETLOCAL_1;
1204 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1205 write->opcode = OPCODE_SETLOCAL_2;
1206 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1207 write->opcode = OPCODE_SETLOCAL_3;
1209 code_dump(r, 0, 0, "", stdout);
1210 syntaxerror("illegal lvalue: can't assign a value to this expression");
1217 /* with getproperty/getslot, we have to be extra careful not
1218 to execute the read code twice, as it might have side-effects
1219 (e.g. if the property is in fact a setter/getter combination)
1221 So read the value, modify it, and write it again,
1222 using prefix only once and making sure (by using a temporary
1223 register) that the return value is what we just wrote */
1224 temp = gettempvar();
1225 c = code_append(c, prefix);
1226 c = code_append(c, r);
1229 c = abc_setlocal(c, temp);
1231 c = code_append(c, middlepart);
1234 c = abc_setlocal(c, temp);
1236 c = code_append(c, write);
1237 c = abc_getlocal(c, temp);
1238 c = abc_kill(c, temp);
1240 /* if we're allowed to execute the read code twice *and*
1241 the middlepart doesn't modify the code, things are easier.
1243 code_t* r2 = code_dup(r);
1244 //c = code_append(c, prefix);
1245 parserassert(!prefix);
1246 c = code_append(c, r);
1247 c = code_append(c, middlepart);
1248 c = code_append(c, write);
1249 c = code_append(c, r2);
1252 /* even smaller version: overwrite the value without reading
1256 c = code_append(c, prefix);
1259 c = code_append(c, middlepart);
1260 c = code_append(c, write);
1261 c = code_append(c, r);
1263 temp = gettempvar();
1265 c = code_append(c, prefix);
1267 c = code_append(c, middlepart);
1269 c = abc_setlocal(c, temp);
1270 c = code_append(c, write);
1271 c = abc_getlocal(c, temp);
1272 c = abc_kill(c, temp);
1279 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1280 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1287 /* ------------ code blocks / statements ---------------- */
1289 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1291 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1292 PROGRAM_CODE_LIST: PROGRAM_CODE
1293 | PROGRAM_CODE_LIST PROGRAM_CODE
1295 PROGRAM_CODE: PACKAGE_DECLARATION
1296 | INTERFACE_DECLARATION
1298 | FUNCTION_DECLARATION
1303 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1304 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1305 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1307 INPACKAGE_CODE: INTERFACE_DECLARATION
1309 | FUNCTION_DECLARATION
1314 MAYBECODE: CODE {$$=$1;}
1315 MAYBECODE: {$$=code_new();}
1317 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1318 CODE: CODEPIECE {$$=$1;}
1320 // code which also may appear outside a method
1321 CODE_STATEMENT: IMPORT
1322 CODE_STATEMENT: VOIDEXPRESSION
1324 CODE_STATEMENT: FOR_IN
1325 CODE_STATEMENT: WHILE
1326 CODE_STATEMENT: DO_WHILE
1327 CODE_STATEMENT: SWITCH
1331 // code which may appear anywhere
1332 CODEPIECE: ';' {$$=0;}
1333 CODEPIECE: VARIABLE_DECLARATION
1334 CODEPIECE: CODE_STATEMENT
1340 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1341 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1343 CODEBLOCK : '{' CODE '}' {$$=$2;}
1344 CODEBLOCK : '{' '}' {$$=0;}
1345 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1346 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1348 /* ------------ package init code ------------------- */
1350 PACKAGE_INITCODE: CODE_STATEMENT {
1351 if($1) warning("code ignored");
1354 /* ------------ variables --------------------------- */
1356 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1357 | {$$.c=abc_pushundefined(0);
1361 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1362 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1364 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1365 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1367 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1369 if(variable_exists($1))
1370 syntaxerror("Variable %s already defined", $1);
1372 if(!is_subtype_of($3.t, $2)) {
1373 syntaxerror("Can't convert %s to %s", $3.t->name,
1377 int index = new_variable($1, $2, 1);
1380 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1382 $$ = converttype($$, $3.t, $2);
1383 $$ = abc_setlocal($$, index);
1385 $$ = defaultvalue(0, $2);
1386 $$ = abc_setlocal($$, index);
1389 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1391 $$ = abc_coerce_a($$);
1392 $$ = abc_setlocal($$, index);
1398 /* that's the default for a local register, anyway
1400 state->method->initcode = abc_pushundefined(state->method->initcode);
1401 state->method->initcode = abc_setlocal(state->method->initcode, index);
1403 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1406 /* ------------ control flow ------------------------- */
1408 MAYBEELSE: %prec below_else {$$ = code_new();}
1409 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1410 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1412 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1414 $$ = code_append($$, $4.c);
1415 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1417 $$ = code_append($$, $6);
1419 myjmp = $$ = abc_jump($$, 0);
1421 myif->branch = $$ = abc_nop($$);
1423 $$ = code_append($$, $7);
1424 myjmp->branch = $$ = abc_nop($$);
1427 $$ = killvars($$);old_state();
1430 FOR_INIT : {$$=code_new();}
1431 FOR_INIT : VARIABLE_DECLARATION
1432 FOR_INIT : VOIDEXPRESSION
1433 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1434 $$=$2;new_variable($2,$3,1);
1436 FOR_IN_INIT : T_IDENTIFIER {
1440 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1441 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1443 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1444 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1446 $$ = code_append($$, $2);
1447 code_t*loopstart = $$ = abc_label($$);
1448 $$ = code_append($$, $4.c);
1449 code_t*myif = $$ = abc_iffalse($$, 0);
1450 $$ = code_append($$, $8);
1451 code_t*cont = $$ = abc_nop($$);
1452 $$ = code_append($$, $6);
1453 $$ = abc_jump($$, loopstart);
1454 code_t*out = $$ = abc_nop($$);
1455 breakjumpsto($$, $1.name, out);
1456 continuejumpsto($$, $1.name, cont);
1459 $$ = killvars($$);old_state();
1462 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1463 variable_t*var = find_variable($2);
1464 char*tmp1name = concat2($2, "__tmp1__");
1465 int it = new_variable(tmp1name, TYPE_INT, 0);
1466 char*tmp2name = concat2($2, "__array__");
1467 int array = new_variable(tmp1name, 0, 0);
1470 $$ = code_append($$, $4.c);
1471 $$ = abc_coerce_a($$);
1472 $$ = abc_setlocal($$, array);
1473 $$ = abc_pushbyte($$, 0);
1474 $$ = abc_setlocal($$, it);
1476 code_t*loopstart = $$ = abc_label($$);
1478 $$ = abc_hasnext2($$, array, it);
1479 code_t*myif = $$ = abc_iffalse($$, 0);
1480 $$ = abc_getlocal($$, array);
1481 $$ = abc_getlocal($$, it);
1483 $$ = abc_nextname($$);
1485 $$ = abc_nextvalue($$);
1486 $$ = converttype($$, 0, var->type);
1487 $$ = abc_setlocal($$, var->index);
1489 $$ = code_append($$, $6);
1490 $$ = abc_jump($$, loopstart);
1492 code_t*out = $$ = abc_nop($$);
1493 breakjumpsto($$, $1.name, out);
1494 continuejumpsto($$, $1.name, loopstart);
1505 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1508 code_t*myjmp = $$ = abc_jump($$, 0);
1509 code_t*loopstart = $$ = abc_label($$);
1510 $$ = code_append($$, $6);
1511 code_t*cont = $$ = abc_nop($$);
1512 myjmp->branch = cont;
1513 $$ = code_append($$, $4.c);
1514 $$ = abc_iftrue($$, loopstart);
1515 code_t*out = $$ = abc_nop($$);
1516 breakjumpsto($$, $1, out);
1517 continuejumpsto($$, $1, cont);
1523 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1525 code_t*loopstart = $$ = abc_label($$);
1526 $$ = code_append($$, $3);
1527 code_t*cont = $$ = abc_nop($$);
1528 $$ = code_append($$, $6.c);
1529 $$ = abc_iftrue($$, loopstart);
1530 code_t*out = $$ = abc_nop($$);
1531 breakjumpsto($$, $1, out);
1532 continuejumpsto($$, $1, cont);
1537 BREAK : "break" %prec prec_none {
1538 $$ = abc___break__(0, "");
1540 BREAK : "break" T_IDENTIFIER {
1541 $$ = abc___break__(0, $2);
1543 CONTINUE : "continue" %prec prec_none {
1544 $$ = abc___continue__(0, "");
1546 CONTINUE : "continue" T_IDENTIFIER {
1547 $$ = abc___continue__(0, $2);
1550 MAYBE_CASE_LIST : {$$=0;}
1551 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1552 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1553 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1554 CASE_LIST: CASE {$$=$1}
1555 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1557 CASE: "case" E ':' MAYBECODE {
1559 $$ = code_append($$, $2.c);
1560 code_t*j = $$ = abc_ifne($$, 0);
1561 $$ = code_append($$, $4);
1562 if($$->opcode != OPCODE___BREAK__) {
1563 $$ = abc___fallthrough__($$, "");
1565 code_t*e = $$ = abc_nop($$);
1568 DEFAULT: "default" ':' MAYBECODE {
1571 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1573 $$ = code_append($$, $7);
1574 code_t*out = $$ = abc_pop($$);
1575 breakjumpsto($$, $1, out);
1577 code_t*c = $$,*lastblock=0;
1579 if(c->opcode == OPCODE_IFNE) {
1580 if(!c->next) syntaxerror("internal error in fallthrough handling");
1582 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1584 c->opcode = OPCODE_JUMP;
1585 c->branch = lastblock;
1587 /* fall through end of switch */
1588 c->opcode = OPCODE_NOP;
1596 /* ------------ try / catch /finally ---------------- */
1598 FINALLY: "finally" '{' CODE '}'
1599 MAYBE_FINALLY: | FINALLY
1601 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1604 int i = find_variable_safe($3)->index;
1605 c = abc_setlocal(c, i);
1606 c = code_append(c, $8);
1609 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1610 multiname_t name = {QNAME, &name_ns, 0, $3};
1612 NEW(abc_exception_t, e)
1613 e->exc_type = sig2mname($4);
1614 e->var_name = multiname_clone(&name);
1615 e->target = code_start(c);
1620 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1621 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1623 TRY : "try" '{' CODE '}' CATCH_LIST MAYBE_FINALLY {
1624 code_t*start = code_start($3);
1627 code_t*out = abc_nop(0);
1628 code_t*jmp = $$ = abc_jump($$, out);
1630 abc_exception_list_t*l = $5;
1632 abc_exception_t*e = l->abc_exception;
1635 $$ = code_append($$, e->target);
1636 $$ = abc_jump($$, out);
1639 $$ = code_append($$, out);
1642 list_concat(state->method->exceptions, $5);
1645 /* ------------ throw ------------------------------- */
1647 THROW : "throw" EXPRESSION {
1651 THROW : "throw" %prec prec_none {
1652 if(!state->exception_name)
1653 syntaxerror("re-throw only possible within a catch block");
1654 variable_t*v = find_variable(state->exception_name);
1656 $$=abc_getlocal($$, v->index);
1660 /* ------------ packages and imports ---------------- */
1662 X_IDENTIFIER: T_IDENTIFIER
1663 | "package" {$$="package";}
1665 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1666 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1668 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1669 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1671 IMPORT : "import" QNAME {
1674 syntaxerror("Couldn't import class\n");
1675 state_has_imports();
1676 dict_put(state->imports, c->name, c);
1679 IMPORT : "import" PACKAGE '.' '*' {
1682 state_has_imports();
1683 list_append(state->wildcard_imports, i);
1687 /* ------------ classes and interfaces (header) -------------- */
1689 MAYBE_MODIFIERS : {$$=0;}
1690 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1691 MODIFIER_LIST : MODIFIER {$$=$1;}
1692 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1694 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1695 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1696 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1697 | KW_STATIC {$$=FLAG_STATIC;}
1698 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1699 | KW_FINAL {$$=FLAG_FINAL;}
1700 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1701 | KW_NATIVE {$$=FLAG_NATIVE;}
1702 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1704 EXTENDS : {$$=registry_getobjectclass();}
1705 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1707 EXTENDS_LIST : {$$=list_new();}
1708 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1710 IMPLEMENTS_LIST : {$$=list_new();}
1711 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1713 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1714 EXTENDS IMPLEMENTS_LIST
1715 '{' {startclass($1,$3,$4,$5, 0);}
1717 '}' {endclass();$$=0;}
1719 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1721 '{' {startclass($1,$3,0,$4,1);}
1722 MAYBE_INTERFACE_BODY
1723 '}' {endclass();$$=0;}
1725 /* ------------ classes and interfaces (body) -------------- */
1728 MAYBE_CLASS_BODY : CLASS_BODY
1729 CLASS_BODY : CLASS_BODY_ITEM
1730 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1731 CLASS_BODY_ITEM : ';'
1732 CLASS_BODY_ITEM : SLOT_DECLARATION
1733 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1735 CLASS_BODY_ITEM : CODE_STATEMENT {
1736 code_t*c = state->cls->static_init;
1737 c = code_append(c, $1);
1738 state->cls->static_init = c;
1741 MAYBE_INTERFACE_BODY :
1742 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1743 INTERFACE_BODY : IDECLARATION
1744 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1746 IDECLARATION : "var" T_IDENTIFIER {
1747 syntaxerror("variable declarations not allowed in interfaces");
1749 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1751 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1752 syntaxerror("invalid method modifiers: interface methods always need to be public");
1754 startfunction(0,$1,$3,$4,&$6,$8);
1755 endfunction(0,$1,$3,$4,&$6,$8, 0);
1758 /* ------------ classes and interfaces (body, slots ) ------- */
1760 VARCONST: "var" | "const"
1762 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1764 memberinfo_t* info = state->cls?
1765 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1766 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1769 info->flags = flags;
1772 namespace_t mname_ns = {flags2access(flags), ""};
1773 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1775 trait_list_t**traits;
1779 traits = &global->init->traits;
1780 code = &global->init->method->body->code;
1781 } else if(flags&FLAG_STATIC) {
1783 traits = &state->cls->abc->static_traits;
1784 code = &state->cls->static_init;
1786 // instance variable
1787 traits = &state->cls->abc->traits;
1788 code = &state->cls->init;
1794 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1796 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1798 info->slot = t->slot_id;
1800 /* initalization code (if needed) */
1802 if($5.c && !is_pushundefined($5.c)) {
1803 c = abc_getlocal_0(c);
1804 c = code_append(c, $5.c);
1805 c = converttype(c, $5.t, $4);
1806 c = abc_setslot(c, t->slot_id);
1809 *code = code_append(*code, c);
1812 t->kind= TRAIT_CONST;
1818 /* ------------ constants -------------------------------------- */
1820 MAYBESTATICCONSTANT: {$$=0;}
1821 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1823 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1824 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1825 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1826 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1827 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1828 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1829 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1830 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1831 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1833 /* ------------ classes and interfaces (body, functions) ------- */
1835 // non-vararg version
1837 memset(&$$,0,sizeof($$));
1839 MAYBE_PARAM_LIST: PARAM_LIST {
1844 MAYBE_PARAM_LIST: "..." PARAM {
1845 memset(&$$,0,sizeof($$));
1847 list_append($$.list, $2);
1849 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1852 list_append($$.list, $4);
1856 PARAM_LIST: PARAM_LIST ',' PARAM {
1858 list_append($$.list, $3);
1861 memset(&$$,0,sizeof($$));
1862 list_append($$.list, $1);
1865 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1866 $$ = malloc(sizeof(param_t));
1871 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1872 $$ = malloc(sizeof(param_t));
1874 $$->type = TYPE_ANY;
1877 GETSET : "get" {$$=$1;}
1881 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1882 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1885 if(state->method->late_binding) {
1886 c = abc_getlocal_0(c);
1887 c = abc_pushscope(c);
1889 if(state->method->is_constructor && !state->method->has_super) {
1890 // call default constructor
1891 c = abc_getlocal_0(c);
1892 c = abc_constructsuper(c, 0);
1894 c = wrap_function(c, state->method->initcode, $11);
1895 endfunction(0,$1,$3,$4,&$6,$8,c);
1899 /* ------------- package + class ids --------------- */
1901 CLASS: T_IDENTIFIER {
1903 /* try current package */
1904 $$ = find_class($1);
1905 if(!$$) syntaxerror("Could not find class %s\n", $1);
1908 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1909 $$ = registry_findclass($1, $3);
1910 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1914 QNAME: PACKAGEANDCLASS
1917 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1918 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1920 TYPE : QNAME {$$=$1;}
1921 | '*' {$$=registry_getanytype();}
1922 | "void" {$$=registry_getanytype();}
1924 | "String" {$$=registry_getstringclass();}
1925 | "int" {$$=registry_getintclass();}
1926 | "uint" {$$=registry_getuintclass();}
1927 | "Boolean" {$$=registry_getbooleanclass();}
1928 | "Number" {$$=registry_getnumberclass();}
1931 MAYBETYPE: ':' TYPE {$$=$2;}
1934 /* ----------function calls, delete, constructor calls ------ */
1936 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
1937 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1939 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1940 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1941 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
1944 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1946 $$.cc = code_append($1.cc, $3.c);
1949 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1954 $$.c = abc_getglobalscope($$.c);
1955 $$.c = abc_getslot($$.c, $2->slot);
1957 $$.c = abc_findpropstrict2($$.c, &m);
1960 $$.c = code_append($$.c, $3.cc);
1963 $$.c = abc_construct($$.c, $3.len);
1965 $$.c = abc_constructprop2($$.c, &m, $3.len);
1969 /* TODO: use abc_call (for calling local variables),
1970 abc_callstatic (for calling own methods)
1973 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1976 if($$.c->opcode == OPCODE_COERCE_A) {
1977 $$.c = code_cutlast($$.c);
1979 code_t*paramcode = $3.cc;
1982 if($$.c->opcode == OPCODE_GETPROPERTY) {
1983 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1984 $$.c = code_cutlast($$.c);
1985 $$.c = code_append($$.c, paramcode);
1986 $$.c = abc_callproperty2($$.c, name, $3.len);
1987 multiname_destroy(name);
1988 } else if($$.c->opcode == OPCODE_GETSLOT) {
1989 int slot = (int)(ptroff_t)$$.c->data[0];
1990 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1991 if(t->kind!=TRAIT_METHOD) {
1992 //ok: flash allows to assign closures to members.
1994 multiname_t*name = t->name;
1995 $$.c = code_cutlast($$.c);
1996 $$.c = code_append($$.c, paramcode);
1997 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1998 $$.c = abc_callproperty2($$.c, name, $3.len);
1999 } else if($$.c->opcode == OPCODE_GETSUPER) {
2000 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2001 $$.c = code_cutlast($$.c);
2002 $$.c = code_append($$.c, paramcode);
2003 $$.c = abc_callsuper2($$.c, name, $3.len);
2004 multiname_destroy(name);
2006 $$.c = abc_getlocal_0($$.c);
2007 $$.c = code_append($$.c, paramcode);
2008 $$.c = abc_call($$.c, $3.len);
2013 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2014 $$.t = $1.t->function->return_type;
2016 $$.c = abc_coerce_a($$.c);
2021 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2022 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2023 if(!state->method) syntaxerror("super() not allowed outside of a function");
2024 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2027 $$.c = abc_getlocal_0($$.c);
2029 $$.c = code_append($$.c, $3.cc);
2031 this is dependent on the control path, check this somewhere else
2032 if(state->method->has_super)
2033 syntaxerror("constructor may call super() only once");
2035 state->method->has_super = 1;
2036 $$.c = abc_constructsuper($$.c, $3.len);
2037 $$.c = abc_pushundefined($$.c);
2041 DELETE: "delete" E {
2043 if($$.c->opcode == OPCODE_COERCE_A) {
2044 $$.c = code_cutlast($$.c);
2046 multiname_t*name = 0;
2047 if($$.c->opcode == OPCODE_GETPROPERTY) {
2048 $$.c->opcode = OPCODE_DELETEPROPERTY;
2049 } else if($$.c->opcode == OPCODE_GETSLOT) {
2050 int slot = (int)(ptroff_t)$$.c->data[0];
2051 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2052 $$.c = code_cutlast($$.c);
2053 $$.c = abc_deleteproperty2($$.c, name);
2055 $$.c = abc_getlocal_0($$.c);
2056 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2057 $$.c = abc_deleteproperty2($$.c, &m);
2059 $$.t = TYPE_BOOLEAN;
2062 RETURN: "return" %prec prec_none {
2063 $$ = abc_returnvoid(0);
2065 RETURN: "return" EXPRESSION {
2067 $$ = abc_returnvalue($$);
2070 // ----------------------- expression types -------------------------------------
2072 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2073 EXPRESSION : E %prec below_minus {$$ = $1;}
2074 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2076 $$.c = cut_last_push($$.c);
2077 $$.c = code_append($$.c,$3.c);
2080 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2081 $$=cut_last_push($1.c);
2084 // ----------------------- expression evaluation -------------------------------------
2087 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2089 E : DELETE {$$ = $1;}
2090 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
2094 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2095 //MULTINAME(m, registry_getintclass());
2096 //$$.c = abc_coerce2($$.c, &m); // FIXME
2099 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2102 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2105 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2108 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2111 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2114 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2117 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2118 $$.t = TYPE_BOOLEAN;
2120 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2121 $$.t = TYPE_BOOLEAN;
2123 CONSTANT : "null" {$$.c = abc_pushnull(0);
2128 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2129 $$.t = TYPE_BOOLEAN;
2131 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2132 $$.t = TYPE_BOOLEAN;
2134 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2135 $$.t = TYPE_BOOLEAN;
2137 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2138 $$.t = TYPE_BOOLEAN;
2140 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2141 $$.t = TYPE_BOOLEAN;
2143 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2144 $$.t = TYPE_BOOLEAN;
2146 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2147 $$.t = TYPE_BOOLEAN;
2149 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2150 $$.t = TYPE_BOOLEAN;
2153 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2155 $$.c = converttype($$.c, $1.t, $$.t);
2156 $$.c = abc_dup($$.c);
2157 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2158 $$.c = cut_last_push($$.c);
2159 $$.c = code_append($$.c,$3.c);
2160 $$.c = converttype($$.c, $3.t, $$.t);
2161 code_t*label = $$.c = abc_label($$.c);
2162 jmp->branch = label;
2165 $$.t = join_types($1.t, $3.t, 'A');
2166 /*printf("%08x:\n",$1.t);
2167 code_dump($1.c, 0, 0, "", stdout);
2168 printf("%08x:\n",$3.t);
2169 code_dump($3.c, 0, 0, "", stdout);
2170 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2172 $$.c = converttype($$.c, $1.t, $$.t);
2173 $$.c = abc_dup($$.c);
2174 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2175 $$.c = cut_last_push($$.c);
2176 $$.c = code_append($$.c,$3.c);
2177 $$.c = converttype($$.c, $3.t, $$.t);
2178 code_t*label = $$.c = abc_label($$.c);
2179 jmp->branch = label;
2182 E : '!' E {$$.c=$2.c;
2183 $$.c = abc_not($$.c);
2184 $$.t = TYPE_BOOLEAN;
2187 E : '~' E {$$.c=$2.c;
2188 $$.c = abc_bitnot($$.c);
2192 E : E '&' E {$$.c = code_append($1.c,$3.c);
2193 $$.c = abc_bitand($$.c);
2197 E : E '^' E {$$.c = code_append($1.c,$3.c);
2198 $$.c = abc_bitxor($$.c);
2202 E : E '|' E {$$.c = code_append($1.c,$3.c);
2203 $$.c = abc_bitor($$.c);
2207 E : E '-' E {$$.c = code_append($1.c,$3.c);
2208 if(BOTH_INT($1,$3)) {
2209 $$.c = abc_subtract_i($$.c);
2212 $$.c = abc_subtract($$.c);
2216 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2217 $$.c = abc_rshift($$.c);
2220 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2221 $$.c = abc_urshift($$.c);
2224 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2225 $$.c = abc_lshift($$.c);
2229 E : E '/' E {$$.c = code_append($1.c,$3.c);
2230 $$.c = abc_divide($$.c);
2233 E : E '+' E {$$.c = code_append($1.c,$3.c);
2234 $$.c = abc_add($$.c);
2237 E : E '%' E {$$.c = code_append($1.c,$3.c);
2238 $$.c = abc_modulo($$.c);
2241 E : E '*' E {$$.c = code_append($1.c,$3.c);
2242 if(BOTH_INT($1,$3)) {
2243 $$.c = abc_multiply_i($$.c);
2246 $$.c = abc_multiply($$.c);
2251 E : E "in" E {$$.c = code_append($1.c,$3.c);
2252 $$.c = abc_in($$.c);
2253 $$.t = TYPE_BOOLEAN;
2256 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2257 if(use_astype && TYPE_IS_CLASS($3.t)) {
2258 MULTINAME(m,$3.t->cls);
2259 $$.c = abc_astype2($1.c, &m);
2262 $$.c = code_append($1.c, $3.c);
2263 $$.c = abc_astypelate($$.c);
2268 E : E "instanceof" E
2269 {$$.c = code_append($1.c, $3.c);
2270 $$.c = abc_instanceof($$.c);
2271 $$.t = TYPE_BOOLEAN;
2274 E : E "is" E {$$.c = code_append($1.c, $3.c);
2275 $$.c = abc_istypelate($$.c);
2276 $$.t = TYPE_BOOLEAN;
2279 E : "typeof" '(' E ')' {
2281 $$.c = abc_typeof($$.c);
2286 $$.c = cut_last_push($2.c);
2287 $$.c = abc_pushundefined($$.c);
2291 E : "void" { $$.c = abc_pushundefined(0);
2295 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2300 $$.c=abc_negate_i($$.c);
2303 $$.c=abc_negate($$.c);
2310 $$.c = code_append($$.c, $3.c);
2312 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2313 $$.c = abc_getproperty2($$.c, &m);
2314 $$.t = 0; // array elements have unknown type
2317 E : '[' MAYBE_EXPRESSION_LIST ']' {
2319 $$.c = code_append($$.c, $2.cc);
2320 $$.c = abc_newarray($$.c, $2.len);
2321 $$.t = registry_getarrayclass();
2324 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2325 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2327 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2329 $$.cc = code_append($$.cc, $1.c);
2330 $$.cc = code_append($$.cc, $3.c);
2333 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2336 $$.cc = code_append($$.cc, $3.c);
2337 $$.cc = code_append($$.cc, $5.c);
2342 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2344 $$.c = code_append($$.c, $2.cc);
2345 $$.c = abc_newobject($$.c, $2.len/2);
2346 $$.t = registry_getobjectclass();
2351 if(BOTH_INT($1,$3)) {
2352 c=abc_multiply_i(c);
2356 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2357 $$.c = toreadwrite($1.c, c, 0, 0);
2362 code_t*c = abc_modulo($3.c);
2363 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2364 $$.c = toreadwrite($1.c, c, 0, 0);
2368 code_t*c = abc_lshift($3.c);
2369 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2370 $$.c = toreadwrite($1.c, c, 0, 0);
2374 code_t*c = abc_rshift($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_urshift($3.c);
2381 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2382 $$.c = toreadwrite($1.c, c, 0, 0);
2386 code_t*c = abc_divide($3.c);
2387 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2388 $$.c = toreadwrite($1.c, c, 0, 0);
2393 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2398 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2400 $$.c = toreadwrite($1.c, c, 0, 0);
2403 E : E "-=" E { code_t*c = $3.c;
2404 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2405 c=abc_subtract_i(c);
2409 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2411 $$.c = toreadwrite($1.c, c, 0, 0);
2414 E : E '=' E { code_t*c = 0;
2415 c = code_append(c, $3.c);
2416 c = converttype(c, $3.t, $1.t);
2417 $$.c = toreadwrite($1.c, c, 1, 0);
2421 E : E '?' E ':' E %prec below_assignment {
2423 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2424 $$.c = code_append($$.c, $3.c);
2425 code_t*j2 = $$.c = abc_jump($$.c, 0);
2426 $$.c = j1->branch = abc_label($$.c);
2427 $$.c = code_append($$.c, $5.c);
2428 $$.c = j2->branch = abc_label($$.c);
2429 $$.t = join_types($3.t,$5.t,'?');
2432 // TODO: use inclocal where appropriate
2433 E : E "++" { code_t*c = 0;
2434 classinfo_t*type = $1.t;
2435 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2436 c=abc_increment_i(c);
2442 c=converttype(c, type, $1.t);
2443 $$.c = toreadwrite($1.c, c, 0, 1);
2446 E : E "--" { code_t*c = 0;
2447 classinfo_t*type = $1.t;
2448 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2449 c=abc_decrement_i(c);
2455 c=converttype(c, type, $1.t);
2456 $$.c = toreadwrite($1.c, c, 0, 1);
2460 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2461 classinfo_t*type = $2.t;
2462 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2463 c=abc_increment_i(c);
2469 c=converttype(c, type, $2.t);
2470 $$.c = toreadwrite($2.c, c, 0, 0);
2474 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2475 classinfo_t*type = $2.t;
2476 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2477 c=abc_decrement_i(c);
2483 c=converttype(c, type, $2.t);
2484 $$.c = toreadwrite($2.c, c, 0, 0);
2488 E : "super" '.' T_IDENTIFIER
2489 { if(!state->cls->info)
2490 syntaxerror("super keyword not allowed outside a class");
2491 classinfo_t*t = state->cls->info->superclass;
2492 if(!t) t = TYPE_OBJECT;
2494 memberinfo_t*f = registry_findmember(t, $3, 1);
2495 namespace_t ns = {flags2access(f->flags), ""};
2496 MEMBER_MULTINAME(m, f, $3);
2498 $$.c = abc_getlocal_0($$.c);
2499 $$.c = abc_getsuper2($$.c, &m);
2500 $$.t = memberinfo_gettype(f);
2503 E : E '.' T_IDENTIFIER
2505 classinfo_t*t = $1.t;
2507 if(TYPE_IS_CLASS(t) && t->cls) {
2512 memberinfo_t*f = registry_findmember(t, $3, 1);
2514 if(f && !is_static != !(f->flags&FLAG_STATIC))
2516 if(f && f->slot && !noslot) {
2517 $$.c = abc_getslot($$.c, f->slot);
2519 MEMBER_MULTINAME(m, f, $3);
2520 $$.c = abc_getproperty2($$.c, &m);
2522 /* determine type */
2523 $$.t = memberinfo_gettype(f);
2525 $$.c = abc_coerce_a($$.c);
2527 /* when resolving a property on an unknown type, we do know the
2528 name of the property (and don't seem to need the package), but
2529 we need to make avm2 try out all access modes */
2530 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2531 $$.c = abc_getproperty2($$.c, &m);
2532 $$.c = abc_coerce_a($$.c);
2533 $$.t = registry_getanytype();
2537 VAR_READ : T_IDENTIFIER {
2544 /* look at variables */
2545 if((v = find_variable($1))) {
2546 // $1 is a local variable
2547 $$.c = abc_getlocal($$.c, v->index);
2550 /* look at current class' members */
2551 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2552 // $1 is a function in this class
2553 int var_is_static = (f->flags&FLAG_STATIC);
2554 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2555 if(var_is_static != i_am_static) {
2556 /* there doesn't seem to be any "static" way to access
2557 static properties of a class */
2558 state->method->late_binding = 1;
2560 namespace_t ns = {flags2access(f->flags), ""};
2561 multiname_t m = {QNAME, &ns, 0, $1};
2562 $$.c = abc_findpropstrict2($$.c, &m);
2563 $$.c = abc_getproperty2($$.c, &m);
2566 $$.c = abc_getlocal_0($$.c);
2567 $$.c = abc_getslot($$.c, f->slot);
2569 namespace_t ns = {flags2access(f->flags), ""};
2570 multiname_t m = {QNAME, &ns, 0, $1};
2571 $$.c = abc_getlocal_0($$.c);
2572 $$.c = abc_getproperty2($$.c, &m);
2575 if(f->kind == MEMBER_METHOD) {
2576 $$.t = TYPE_FUNCTION(f);
2581 /* look at actual classes, in the current package and imported */
2582 } else if((a = find_class($1))) {
2583 if(a->flags & FLAG_METHOD) {
2585 $$.c = abc_findpropstrict2($$.c, &m);
2586 $$.c = abc_getproperty2($$.c, &m);
2587 $$.t = TYPE_FUNCTION(a->function);
2590 $$.c = abc_getglobalscope($$.c);
2591 $$.c = abc_getslot($$.c, a->slot);
2594 $$.c = abc_getlex2($$.c, &m);
2596 $$.t = TYPE_CLASS(a);
2599 /* unknown object, let the avm2 resolve it */
2601 if(strcmp($1,"trace"))
2602 warning("Couldn't resolve '%s', doing late binding", $1);
2603 state->method->late_binding = 1;
2605 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2608 $$.c = abc_findpropstrict2($$.c, &m);
2609 $$.c = abc_getproperty2($$.c, &m);
2614 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2615 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2616 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2618 // ----------------- namespaces -------------------------------------------------
2620 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2621 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2622 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2624 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}