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;
64 %token<id> T_IDENTIFIER
66 %token<token> T_REGEXP
68 %token<number_int> T_INT
69 %token<number_uint> T_UINT
70 %token<number_uint> T_BYTE
71 %token<number_uint> T_SHORT
72 %token<number_float> T_FLOAT
74 %token<id> T_FOR "for"
75 %token<id> T_WHILE "while"
77 %token<id> T_SWITCH "switch"
79 %token<token> KW_IMPLEMENTS
80 %token<token> KW_NAMESPACE "namespace"
81 %token<token> KW_PACKAGE "package"
82 %token<token> KW_PROTECTED
83 %token<token> KW_PUBLIC
84 %token<token> KW_PRIVATE
85 %token<token> KW_USE "use"
86 %token<token> KW_INTERNAL
87 %token<token> KW_NEW "new"
88 %token<token> KW_NATIVE
89 %token<token> KW_FUNCTION "function"
90 %token<token> KW_UNDEFINED "undefined"
91 %token<token> KW_CONTINUE "continue"
92 %token<token> KW_CLASS "class"
93 %token<token> KW_CONST "const"
94 %token<token> KW_CATCH "catch"
95 %token<token> KW_CASE "case"
96 %token<token> KW_SET "set"
97 %token<token> KW_VOID "void"
98 %token<token> KW_STATIC
99 %token<token> KW_INSTANCEOF "instanceof"
100 %token<token> KW_IMPORT "import"
101 %token<token> KW_RETURN "return"
102 %token<token> KW_TYPEOF "typeof"
103 %token<token> KW_INTERFACE "interface"
104 %token<token> KW_NULL "null"
105 %token<token> KW_VAR "var"
106 %token<token> KW_DYNAMIC "dynamic"
107 %token<token> KW_OVERRIDE
108 %token<token> KW_FINAL
109 %token<token> KW_EACH "each"
110 %token<token> KW_GET "get"
111 %token<token> KW_TRY "try"
112 %token<token> KW_SUPER "super"
113 %token<token> KW_EXTENDS
114 %token<token> KW_FALSE "false"
115 %token<token> KW_TRUE "true"
116 %token<token> KW_BOOLEAN "Boolean"
117 %token<token> KW_UINT "uint"
118 %token<token> KW_INT "int"
119 %token<token> KW_NUMBER "Number"
120 %token<token> KW_STRING "String"
121 %token<token> KW_DEFAULT "default"
122 %token<token> KW_DELETE "delete"
123 %token<token> KW_IF "if"
124 %token<token> KW_ELSE "else"
125 %token<token> KW_BREAK "break"
126 %token<token> KW_IS "is"
127 %token<token> KW_IN "in"
128 %token<token> KW_AS "as"
130 %token<token> T_EQEQ "=="
131 %token<token> T_EQEQEQ "==="
132 %token<token> T_NE "!="
133 %token<token> T_NEE "!=="
134 %token<token> T_LE "<="
135 %token<token> T_GE ">="
136 %token<token> T_DIVBY "/="
137 %token<token> T_MODBY "%="
138 %token<token> T_MULBY "*="
139 %token<token> T_PLUSBY "+="
140 %token<token> T_MINUSBY "-="
141 %token<token> T_SHRBY ">>="
142 %token<token> T_SHLBY "<<="
143 %token<token> T_USHRBY ">>>="
144 %token<token> T_OROR "||"
145 %token<token> T_ANDAND "&&"
146 %token<token> T_COLONCOLON "::"
147 %token<token> T_MINUSMINUS "--"
148 %token<token> T_PLUSPLUS "++"
149 %token<token> T_DOTDOT ".."
150 %token<token> T_DOTDOTDOT "..."
151 %token<token> T_SHL "<<"
152 %token<token> T_USHR ">>>"
153 %token<token> T_SHR ">>"
155 %type <for_start> FOR_START
156 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
157 %type <token> VARCONST
159 %type <code> CODEPIECE CODE_STATEMENT
160 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
161 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
162 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
163 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
164 %type <code> CLASS_DECLARATION
165 %type <code> NAMESPACE_DECLARATION
166 %type <code> INTERFACE_DECLARATION
167 %type <code> VOIDEXPRESSION
168 %type <value> EXPRESSION NONCOMMAEXPRESSION
169 %type <value> MAYBEEXPRESSION
170 %type <value> E DELETE
171 %type <value> CONSTANT
172 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
173 %type <token> USE_NAMESPACE
174 %type <code> FOR_INIT
176 %type <classinfo> MAYBETYPE
179 %type <params> PARAM_LIST
180 %type <params> MAYBE_PARAM_LIST
181 %type <flags> MAYBE_MODIFIERS
182 %type <flags> MODIFIER_LIST
183 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
184 %type <classinfo_list> IMPLEMENTS_LIST
185 %type <classinfo> EXTENDS
186 %type <classinfo_list> EXTENDS_LIST
187 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
188 %type <classinfo_list> QNAME_LIST
189 %type <classinfo> TYPE
190 //%type <token> VARIABLE
191 %type <value> VAR_READ
193 //%type <token> T_IDENTIFIER
194 %type <token> MODIFIER
195 %type <value> FUNCTIONCALL
196 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
198 // precedence: from low to high
202 %left below_semicolon
205 %nonassoc below_assignment // for ?:, contrary to spec
206 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
213 %nonassoc "==" "!=" "===" "!=="
214 %nonassoc "is" "as" "in"
215 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
216 %left "<<" ">>" ">>>"
220 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
222 %nonassoc below_curly
223 %left '[' ']' '{' "new" '.' ".." "::"
224 %nonassoc T_IDENTIFIER
225 %left above_identifier
230 // needed for "return" precedence:
231 %nonassoc T_STRING T_REGEXP
232 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
233 %nonassoc "false" "true" "null" "undefined" "super"
239 static int yyerror(char*s)
241 syntaxerror("%s", s);
244 static char* concat2(const char* t1, const char* t2)
248 char*text = malloc(l1+l2+1);
249 memcpy(text , t1, l1);
250 memcpy(text+l1, t2, l2);
254 static char* concat3(const char* t1, const char* t2, const char* t3)
259 char*text = malloc(l1+l2+l3+1);
260 memcpy(text , t1, l1);
261 memcpy(text+l1, t2, l2);
262 memcpy(text+l1+l2, t3, l3);
267 typedef struct _import {
271 DECLARE_LIST(import);
273 typedef struct _classstate {
279 char has_constructor;
282 typedef struct _methodstate {
286 /* code that needs to be executed at the start of
287 a method (like initializing local registers) */
294 typedef struct _state {
299 import_list_t*wildcard_imports;
301 char has_own_imports;
304 methodstate_t*method;
309 typedef struct _global {
316 static global_t*global = 0;
317 static state_t* state = 0;
321 #define MULTINAME(m,x) \
324 registry_fill_multiname(&m, &m##_ns, x);
326 #define MEMBER_MULTINAME(m,f,n) \
330 m##_ns.access = flags2access(f->flags); \
334 m.namespace_set = 0; \
337 m.type = MULTINAME; \
339 m.namespace_set = &nopackage_namespace_set; \
343 /* warning: list length of namespace set is undefined */
344 #define MULTINAME_LATE(m, access, package) \
345 namespace_t m##_ns = {access, package}; \
346 namespace_set_t m##_nsset; \
347 namespace_list_t m##_l;m##_l.next = 0; \
348 m##_nsset.namespaces = &m##_l; \
349 m##_nsset = m##_nsset; \
350 m##_l.namespace = &m##_ns; \
351 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
353 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
354 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
355 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
356 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
357 static namespace_list_t nl4 = {&ns4,0};
358 static namespace_list_t nl3 = {&ns3,&nl4};
359 static namespace_list_t nl2 = {&ns2,&nl3};
360 static namespace_list_t nl1 = {&ns1,&nl2};
361 static namespace_set_t nopackage_namespace_set = {&nl1};
363 static void new_state()
366 state_t*oldstate = state;
368 memcpy(s, state, sizeof(state_t)); //shallow copy
370 s->imports = dict_new();
374 state->has_own_imports = 0;
375 state->vars = dict_new();
376 state->old = oldstate;
378 static void state_has_imports()
380 state->wildcard_imports = list_clone(state->wildcard_imports);
381 state->imports = dict_clone(state->imports);
382 state->has_own_imports = 1;
385 static void state_destroy(state_t*state)
387 if(state->has_own_imports) {
388 list_free(state->wildcard_imports);
389 dict_destroy(state->imports);state->imports=0;
391 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
392 dict_destroy(state->imports);state->imports=0;
396 for(t=0;t<state->vars->hashsize;t++) {
397 dictentry_t*e =state->vars->slots[t];
399 free(e->data);e->data=0;
403 dict_destroy(state->vars);state->vars=0;
409 static void old_state()
411 if(!state || !state->old)
412 syntaxerror("invalid nesting");
413 state_t*leaving = state;
415 /*if(state->method->initcode) {
416 printf("residual initcode\n");
417 code_dump(state->method->initcode, 0, 0, "", stdout);
419 state_destroy(leaving);
421 void initialize_state()
423 global = rfx_calloc(sizeof(global_t));
426 state->package = current_filename;
428 global->file = abc_file_new();
429 global->file->flags &= ~ABCFILE_LAZY;
430 global->variable_count = 1;
432 global->init = abc_initscript(global->file, 0);
433 code_t*c = global->init->method->body->code;
435 c = abc_getlocal_0(c);
436 c = abc_pushscope(c);
438 /* findpropstrict doesn't just return a scope object- it
439 also makes it "active" somehow. Push local_0 on the
440 scope stack and read it back with findpropstrict, it'll
441 contain properties like "trace". Trying to find the same
442 property on a "vanilla" local_0 yields only a "undefined" */
443 //c = abc_findpropstrict(c, "[package]::trace");
445 /*c = abc_getlocal_0(c);
446 c = abc_findpropstrict(c, "[package]::trace");
448 c = abc_setlocal_1(c);
450 c = abc_pushbyte(c, 0);
451 c = abc_setlocal_2(c);
453 code_t*xx = c = abc_label(c);
454 c = abc_findpropstrict(c, "[package]::trace");
455 c = abc_pushstring(c, "prop:");
456 c = abc_hasnext2(c, 1, 2);
458 c = abc_setlocal_3(c);
459 c = abc_callpropvoid(c, "[package]::trace", 2);
460 c = abc_getlocal_3(c);
462 c = abc_iftrue(c,xx);*/
464 c = abc_findpropstrict(c, "[package]::trace");
465 c = abc_pushstring(c, "[entering global init function]");
466 c = abc_callpropvoid(c, "[package]::trace", 1);
468 global->init->method->body->code = c;
470 void* finalize_state()
472 if(state->level!=1) {
473 syntaxerror("unexpected end of file");
475 abc_method_body_t*m = global->init->method->body;
478 __ findpropstrict(m, "[package]::trace");
479 __ pushstring(m, "[leaving global init function]");
480 __ callpropvoid(m, "[package]::trace", 1);
483 state_destroy(state);
489 static void startpackage(char*name)
492 /*printf("entering package \"%s\"\n", name);*/
493 state->package = strdup(name);
494 global->variable_count = 1;
496 static void endpackage()
498 /*printf("leaving package \"%s\"\n", state->package);*/
500 //used e.g. in classinfo_register:
501 //free(state->package);state->package=0;
507 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
510 syntaxerror("inner classes now allowed");
513 global->variable_count = 1;
514 state->cls = rfx_calloc(sizeof(classstate_t));
517 classinfo_list_t*mlist=0;
518 /*printf("entering class %s\n", name);
519 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
521 printf(" extends: %s.%s\n", extends->package, extends->name);
522 printf(" implements (%d): ", list_length(implements));
523 for(mlist=implements;mlist;mlist=mlist->next) {
524 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
529 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
530 syntaxerror("invalid modifier(s)");
532 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
533 syntaxerror("public and internal not supported at the same time.");
535 /* create the class name, together with the proper attributes */
539 if(!(flags&FLAG_PUBLIC) && !state->package) {
540 access = ACCESS_PRIVATE; package = current_filename;
541 } else if(!(flags&FLAG_PUBLIC) && state->package) {
542 access = ACCESS_PACKAGEINTERNAL; package = state->package;
543 } else if(state->package) {
544 access = ACCESS_PACKAGE; package = state->package;
546 syntaxerror("public classes only allowed inside a package");
549 if(registry_findclass(package, classname)) {
550 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
554 /* build info struct */
555 int num_interfaces = (list_length(implements));
556 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
557 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
559 classinfo_list_t*l = implements;
560 for(l=implements;l;l=l->next) {
561 state->cls->info->interfaces[pos++] = l->classinfo;
564 multiname_t*extends2 = sig2mname(extends);
566 MULTINAME(classname2,state->cls->info);
569 state->cls_init = abc_getlocal_0(state->cls_init);
570 state->cls_init = abc_constructsuper(state->cls_init, 0);
573 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
574 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
575 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
577 state->cls->info->flags |= CLASS_INTERFACE;
578 abc_class_interface(state->cls->abc);
581 abc_class_protectedNS(state->cls->abc, classname);
583 for(mlist=implements;mlist;mlist=mlist->next) {
584 MULTINAME(m, mlist->classinfo);
585 abc_class_add_interface(state->cls->abc, &m);
588 /* now write the construction code for this class */
589 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
591 abc_method_body_t*m = global->init->method->body;
592 __ getglobalscope(m);
593 classinfo_t*s = extends;
598 //TODO: take a look at the current scope stack, maybe
599 // we can re-use something
604 multiname_t*s2 = sig2mname(s);
606 multiname_destroy(s2);
608 __ pushscope(m); count++;
609 m->code = m->code->prev->prev; // invert
611 /* continue appending after last op end */
612 while(m->code && m->code->next) m->code = m->code->next;
614 /* TODO: if this is one of *our* classes, we can also
615 do a getglobalscope/getslot <nr> (which references
616 the init function's slots) */
618 __ getlex2(m, extends2);
620 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
621 stack is not the superclass */
622 __ pushscope(m);count++;
625 /* notice: we get a verify error #1107 if the top element on the scope
626 stack is not the global object */
628 __ pushscope(m);count++;
630 __ newclass(m,state->cls->abc);
634 __ setslot(m, slotindex);
636 /* flash.display.MovieClip handling */
637 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
638 if(state->package && state->package[0]) {
639 globalclass = concat3(state->package, ".", classname);
641 globalclass = strdup(classname);
644 multiname_destroy(extends2);
647 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
649 c = code_append(c, initcode);
650 c = code_append(c, body);
651 /* append return if necessary */
652 if(!c || c->opcode != OPCODE_RETURNVOID &&
653 c->opcode != OPCODE_RETURNVALUE) {
654 c = abc_returnvoid(c);
659 static void endclass()
661 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
663 c = abc_getlocal_0(c);
664 c = abc_constructsuper(c, 0);
665 state->cls->init = code_append(state->cls->init, c);
668 if(state->cls->init) {
669 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
670 m->body->code = wrap_function(0, state->cls->init, m->body->code);
672 if(state->cls->static_init) {
673 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
674 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
676 // handy for scope testing
680 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
683 free(state->cls);state->cls=0;
687 typedef struct _variable {
692 static variable_t* find_variable(char*name)
698 v = dict_lookup(s->vars, name);
706 static variable_t* find_variable_safe(char*name)
708 variable_t* v = find_variable(name);
710 syntaxerror("undefined variable: %s", name);
713 static char variable_exists(char*name)
715 return dict_lookup(state->vars, name)!=0;
717 code_t*defaultvalue(code_t*c, classinfo_t*type);
718 static int new_variable(char*name, classinfo_t*type, char init)
721 v->index = global->variable_count;
724 dict_put(state->vars, name, v);
726 if(init && state->method && type) {
727 /* if this is a typed variable:
728 push default value for type on stack at the very beginning of the
729 method, so that it always has that type regardless of the control
731 state->method->initcode = defaultvalue(state->method->initcode, type);
732 state->method->initcode = abc_setlocal(state->method->initcode, v->index);
734 return global->variable_count++;
736 #define TEMPVARNAME "__as3_temp__"
737 static int gettempvar()
739 variable_t*v = find_variable(TEMPVARNAME);
742 return new_variable(TEMPVARNAME, 0, 0);
745 code_t* killvars(code_t*c)
748 for(t=0;t<state->vars->hashsize;t++) {
749 dictentry_t*e =state->vars->slots[t];
751 variable_t*v = (variable_t*)e->data;
752 //do this always, otherwise register types don't match
753 //in the verifier when doing nested loops
754 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
755 c = abc_kill(c, v->index);
762 void check_code_for_break(code_t*c)
765 if(c->opcode == OPCODE___BREAK__) {
766 char*name = string_cstr(c->data[0]);
767 syntaxerror("Unresolved \"break %s\"", name);
769 if(c->opcode == OPCODE___CONTINUE__) {
770 char*name = string_cstr(c->data[0]);
771 syntaxerror("Unresolved \"continue %s\"", name);
778 static void check_constant_against_type(classinfo_t*t, constant_t*c)
780 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
781 if(TYPE_IS_NUMBER(t)) {
782 xassert(c->type == CONSTANT_FLOAT
783 || c->type == CONSTANT_INT
784 || c->type == CONSTANT_UINT);
785 } else if(TYPE_IS_UINT(t)) {
786 xassert(c->type == CONSTANT_UINT ||
787 (c->type == CONSTANT_INT && c->i>0));
788 } else if(TYPE_IS_INT(t)) {
789 xassert(c->type == CONSTANT_INT);
790 } else if(TYPE_IS_BOOLEAN(t)) {
791 xassert(c->type == CONSTANT_TRUE
792 || c->type == CONSTANT_FALSE);
796 static int flags2access(int flags)
799 if(flags&FLAG_PUBLIC) {
800 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
801 access = ACCESS_PACKAGE;
802 } else if(flags&FLAG_PRIVATE) {
803 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
804 access = ACCESS_PRIVATE;
805 } else if(flags&FLAG_PROTECTED) {
806 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
807 access = ACCESS_PROTECTED;
809 access = ACCESS_PACKAGEINTERNAL;
814 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
816 memberinfo_t*minfo = 0;
819 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
820 minfo->return_type = return_type;
821 } else if(getset != KW_GET && getset != KW_SET) {
823 if((minfo = registry_findmember(state->cls->info, name, 0))) {
824 if(minfo->parent == state->cls->info) {
825 syntaxerror("class already contains a member/method called '%s'", name);
826 } else if(!minfo->parent) {
827 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
829 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
830 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
833 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
834 minfo->return_type = return_type;
835 // getslot on a member slot only returns "undefined", so no need
836 // to actually store these
837 //state->minfo->slot = state->method->abc->method->trait->slot_id;
839 //class getter/setter
840 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
844 else if(params->list)
845 type = params->list->param->type;
846 // not sure wether to look into superclasses here, too
847 if((minfo=registry_findmember(state->cls->info, name, 0))) {
848 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
849 syntaxerror("class already contains a member or method called '%s'", name);
851 syntaxerror("getter/setter for '%s' already defined", name);
852 /* make a setter or getter into a getset */
857 if(type && minfo->type != type)
858 syntaxerror("different type in getter and setter");
860 minfo = memberinfo_register(state->cls->info, name, gs);
863 /* can't assign a slot as getter and setter might have different slots */
864 //minfo->slot = slot;
866 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
867 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
868 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
869 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
870 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
871 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
875 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
876 params_t*params, classinfo_t*return_type)
879 syntaxerror("not able to start another method scope");
882 global->variable_count = 0;
883 state->method = rfx_calloc(sizeof(methodstate_t));
884 state->method->initcode = 0;
885 state->method->has_super = 0;
887 state->method->is_constructor = !strcmp(state->cls->info->name,name);
888 state->cls->has_constructor |= state->method->is_constructor;
890 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
892 state->method->is_global = 1;
893 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
895 new_variable("globalscope", 0, 0);
898 /* state->vars is initialized by state_new */
901 for(p=params->list;p;p=p->next) {
902 new_variable(p->param->name, p->param->type, 0);
904 if(state->method->is_constructor)
905 name = "__as3_constructor__";
906 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
909 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
910 params_t*params, classinfo_t*return_type, code_t*body)
914 multiname_t*type2 = sig2mname(return_type);
916 if(state->method->is_constructor) {
917 f = abc_class_getconstructor(state->cls->abc, type2);
918 } else if(!state->method->is_global) {
919 namespace_t mname_ns = {flags2access(flags), ""};
920 multiname_t mname = {QNAME, &mname_ns, 0, name};
922 if(flags&FLAG_STATIC)
923 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
925 f = abc_class_method(state->cls->abc, type2, &mname);
926 slot = f->trait->slot_id;
928 namespace_t mname_ns = {flags2access(flags), state->package};
929 multiname_t mname = {QNAME, &mname_ns, 0, name};
931 f = abc_method_new(global->file, type2, 1);
932 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
933 //abc_code_t*c = global->init->method->body->code;
935 //flash doesn't seem to allow us to access function slots
936 //state->method->info->slot = slot;
938 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
939 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
940 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
941 if(params->varargs) f->flags |= METHOD_NEED_REST;
945 for(p=params->list;p;p=p->next) {
946 if(params->varargs && !p->next) {
947 break; //varargs: omit last parameter in function signature
949 multiname_t*m = sig2mname(p->param->type);
950 list_append(f->parameters, m);
951 if(p->param->value) {
952 check_constant_against_type(p->param->type, p->param->value);
953 opt=1;list_append(f->optional_parameters, p->param->value);
955 syntaxerror("non-optional parameter not allowed after optional parameters");
958 check_code_for_break(body);
961 f->body->code = body;
964 syntaxerror("interface methods can't have a method body");
966 free(state->method);state->method=0;
972 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
977 void breakjumpsto(code_t*c, char*name, code_t*jump)
980 if(c->opcode == OPCODE___BREAK__) {
981 string_t*name2 = c->data[0];
982 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
983 c->opcode = OPCODE_JUMP;
990 void continuejumpsto(code_t*c, char*name, code_t*jump)
993 if(c->opcode == OPCODE___CONTINUE__) {
994 string_t*name2 = c->data[0];
995 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
996 c->opcode = OPCODE_JUMP;
1004 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1006 if(!type1 || !type2)
1007 return registry_getanytype();
1008 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1009 return registry_getanytype();
1012 return registry_getanytype();
1014 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1019 return abc_coerce_a(c);
1023 // cast an "any" type to a specific type. subject to
1024 // runtime exceptions
1025 return abc_coerce2(c, &m);
1028 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1029 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1030 // allow conversion between number types
1031 return abc_coerce2(c, &m);
1033 //printf("%s.%s\n", from.package, from.name);
1034 //printf("%s.%s\n", to.package, to.name);
1036 classinfo_t*supertype = from;
1038 if(supertype == to) {
1039 // target type is one of from's superclasses
1040 return abc_coerce2(c, &m);
1043 while(supertype->interfaces[t]) {
1044 if(supertype->interfaces[t]==to) {
1045 // target type is one of from's interfaces
1046 return abc_coerce2(c, &m);
1050 supertype = supertype->superclass;
1052 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1054 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1056 syntaxerror("can't convert type %s to %s", from->name, to->name);
1059 code_t*defaultvalue(code_t*c, classinfo_t*type)
1061 if(TYPE_IS_INT(type)) {
1062 c = abc_pushbyte(c, 0);
1063 } else if(TYPE_IS_UINT(type)) {
1064 c = abc_pushuint(c, 0);
1065 } else if(TYPE_IS_FLOAT(type)) {
1067 } else if(TYPE_IS_BOOLEAN(type)) {
1068 c = abc_pushfalse(c);
1070 c = abc_pushnull(c);
1075 char is_pushundefined(code_t*c)
1077 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1080 void parserassert(int b)
1082 if(!b) syntaxerror("internal error: assertion failed");
1085 static classinfo_t* find_class(char*name)
1089 c = registry_findclass(state->package, name);
1092 /* try explicit imports */
1093 dictentry_t* e = dict_get_slot(state->imports, name);
1096 if(!strcmp(e->key, name)) {
1097 c = (classinfo_t*)e->data;
1103 /* try package.* imports */
1104 import_list_t*l = state->wildcard_imports;
1106 //printf("does package %s contain a class %s?\n", l->import->package, name);
1107 c = registry_findclass(l->import->package, name);
1112 /* try global package */
1113 c = registry_findclass("", name);
1116 /* try local "filename" package */
1117 c = registry_findclass(current_filename, name);
1123 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1127 [prefix code] [read instruction]
1131 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1134 if(in && in->opcode == OPCODE_COERCE_A) {
1135 in = code_cutlast(in);
1138 syntaxerror("internal error");
1140 /* chop off read instruction */
1144 prefix = r->prev;r->prev = 0;
1150 char use_temp_var = readbefore;
1152 /* generate the write instruction, and maybe append a dup to the prefix code */
1153 code_t* write = abc_nop(0);
1154 if(r->opcode == OPCODE_GETPROPERTY) {
1155 write->opcode = OPCODE_SETPROPERTY;
1156 multiname_t*m = (multiname_t*)r->data[0];
1157 write->data[0] = multiname_clone(m);
1158 if(m->type == QNAME || m->type == MULTINAME) {
1160 prefix = abc_dup(prefix); // we need the object, too
1163 } else if(m->type == MULTINAMEL) {
1165 /* dupping two values on the stack requires 5 operations and one register-
1166 couldn't adobe just have given us a dup2? */
1167 int temp = gettempvar();
1168 prefix = abc_setlocal(prefix, temp);
1169 prefix = abc_dup(prefix);
1170 prefix = abc_getlocal(prefix, temp);
1171 prefix = abc_swap(prefix);
1172 prefix = abc_getlocal(prefix, temp);
1174 prefix = abc_kill(prefix, temp);
1178 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1180 } else if(r->opcode == OPCODE_GETSLOT) {
1181 write->opcode = OPCODE_SETSLOT;
1182 write->data[0] = r->data[0];
1184 prefix = abc_dup(prefix); // we need the object, too
1187 } else if(r->opcode == OPCODE_GETLOCAL) {
1188 write->opcode = OPCODE_SETLOCAL;
1189 write->data[0] = r->data[0];
1190 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1191 write->opcode = OPCODE_SETLOCAL_0;
1192 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1193 write->opcode = OPCODE_SETLOCAL_1;
1194 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1195 write->opcode = OPCODE_SETLOCAL_2;
1196 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1197 write->opcode = OPCODE_SETLOCAL_3;
1199 code_dump(r, 0, 0, "", stdout);
1200 syntaxerror("illegal lvalue: can't assign a value to this expression");
1207 /* with getproperty/getslot, we have to be extra careful not
1208 to execute the read code twice, as it might have side-effects
1209 (e.g. if the property is in fact a setter/getter combination)
1211 So read the value, modify it, and write it again,
1212 using prefix only once and making sure (by using a temporary
1213 register) that the return value is what we just wrote */
1214 temp = gettempvar();
1215 c = code_append(c, prefix);
1216 c = code_append(c, r);
1219 c = abc_setlocal(c, temp);
1221 c = code_append(c, middlepart);
1224 c = abc_setlocal(c, temp);
1226 c = code_append(c, write);
1227 c = abc_getlocal(c, temp);
1228 c = abc_kill(c, temp);
1230 /* if we're allowed to execute the read code twice *and*
1231 the middlepart doesn't modify the code, things are easier.
1233 code_t* r2 = code_dup(r);
1234 //c = code_append(c, prefix);
1235 parserassert(!prefix);
1236 c = code_append(c, r);
1237 c = code_append(c, middlepart);
1238 c = code_append(c, write);
1239 c = code_append(c, r2);
1242 /* even smaller version: overwrite the value without reading
1246 c = code_append(c, prefix);
1249 c = code_append(c, middlepart);
1250 c = code_append(c, write);
1251 c = code_append(c, r);
1253 temp = gettempvar();
1255 c = code_append(c, prefix);
1257 c = code_append(c, middlepart);
1259 c = abc_setlocal(c, temp);
1260 c = code_append(c, write);
1261 c = abc_getlocal(c, temp);
1262 c = abc_kill(c, temp);
1269 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1270 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1277 /* ------------ code blocks / statements ---------------- */
1279 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1281 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1282 PROGRAM_CODE_LIST: PROGRAM_CODE
1283 | PROGRAM_CODE_LIST PROGRAM_CODE
1285 PROGRAM_CODE: PACKAGE_DECLARATION
1286 | INTERFACE_DECLARATION
1288 | FUNCTION_DECLARATION
1293 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1294 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1295 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1297 INPACKAGE_CODE: INTERFACE_DECLARATION
1299 | FUNCTION_DECLARATION
1304 MAYBECODE: CODE {$$=$1;}
1305 MAYBECODE: {$$=code_new();}
1307 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1308 CODE: CODEPIECE {$$=$1;}
1310 // code which also may appear outside a method
1311 CODE_STATEMENT: IMPORT
1312 CODE_STATEMENT: VOIDEXPRESSION
1314 CODE_STATEMENT: FOR_IN
1315 CODE_STATEMENT: WHILE
1316 CODE_STATEMENT: DO_WHILE
1317 CODE_STATEMENT: SWITCH
1320 // code which may appear anywhere
1321 //CODEPIECE: PACKAGE_DECLARATION
1322 //CODEPIECE: CLASS_DECLARATION
1323 //CODEPIECE: FUNCTION_DECLARATION
1324 //CODEPIECE: INTERFACE_DECLARATION
1325 CODEPIECE: ';' {$$=0;}
1326 CODEPIECE: VARIABLE_DECLARATION
1327 CODEPIECE: CODE_STATEMENT
1332 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1333 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1335 CODEBLOCK : '{' CODE '}' {$$=$2;}
1336 CODEBLOCK : '{' '}' {$$=0;}
1337 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1338 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1340 /* ------------ package init code ------------------- */
1342 PACKAGE_INITCODE: CODE_STATEMENT {
1343 if($1) warning("code ignored");
1346 /* ------------ variables --------------------------- */
1348 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1349 | {$$.c=abc_pushundefined(0);
1353 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1354 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1356 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1357 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1359 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1361 if(variable_exists($1))
1362 syntaxerror("Variable %s already defined", $1);
1364 if(!is_subtype_of($3.t, $2)) {
1365 syntaxerror("Can't convert %s to %s", $3.t->name,
1369 int index = new_variable($1, $2, 1);
1372 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1374 $$ = converttype($$, $3.t, $2);
1375 $$ = abc_setlocal($$, index);
1377 $$ = defaultvalue(0, $2);
1378 $$ = abc_setlocal($$, index);
1381 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1383 $$ = abc_coerce_a($$);
1384 $$ = abc_setlocal($$, index);
1390 /* that's the default for a local register, anyway
1392 state->method->initcode = abc_pushundefined(state->method->initcode);
1393 state->method->initcode = abc_setlocal(state->method->initcode, index);
1395 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1398 /* ------------ control flow ------------------------- */
1400 MAYBEELSE: %prec below_else {$$ = code_new();}
1401 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1402 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1404 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1406 $$ = code_append($$, $4.c);
1407 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1409 $$ = code_append($$, $6);
1411 myjmp = $$ = abc_jump($$, 0);
1413 myif->branch = $$ = abc_nop($$);
1415 $$ = code_append($$, $7);
1416 myjmp->branch = $$ = abc_nop($$);
1419 $$ = killvars($$);old_state();
1422 FOR_INIT : {$$=code_new();}
1423 FOR_INIT : VARIABLE_DECLARATION
1424 FOR_INIT : VOIDEXPRESSION
1425 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1426 $$=$2;new_variable($2,$3,1);
1428 FOR_IN_INIT : T_IDENTIFIER {
1432 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1433 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1435 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1436 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1438 $$ = code_append($$, $2);
1439 code_t*loopstart = $$ = abc_label($$);
1440 $$ = code_append($$, $4.c);
1441 code_t*myif = $$ = abc_iffalse($$, 0);
1442 $$ = code_append($$, $8);
1443 code_t*cont = $$ = abc_nop($$);
1444 $$ = code_append($$, $6);
1445 $$ = abc_jump($$, loopstart);
1446 code_t*out = $$ = abc_nop($$);
1447 breakjumpsto($$, $1.name, out);
1448 continuejumpsto($$, $1.name, cont);
1451 $$ = killvars($$);old_state();
1454 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1455 variable_t*var = find_variable($2);
1456 char*tmp1name = concat2($2, "__tmp1__");
1457 int it = new_variable(tmp1name, TYPE_INT, 0);
1458 char*tmp2name = concat2($2, "__array__");
1459 int array = new_variable(tmp1name, 0, 0);
1462 $$ = code_append($$, $4.c);
1463 $$ = abc_coerce_a($$);
1464 $$ = abc_setlocal($$, array);
1465 $$ = abc_pushbyte($$, 0);
1466 $$ = abc_setlocal($$, it);
1468 code_t*loopstart = $$ = abc_label($$);
1470 $$ = abc_hasnext2($$, array, it);
1471 code_t*myif = $$ = abc_iffalse($$, 0);
1472 $$ = abc_getlocal($$, array);
1473 $$ = abc_getlocal($$, it);
1475 $$ = abc_nextname($$);
1477 $$ = abc_nextvalue($$);
1478 $$ = converttype($$, 0, var->type);
1479 $$ = abc_setlocal($$, var->index);
1481 $$ = code_append($$, $6);
1482 $$ = abc_jump($$, loopstart);
1484 code_t*out = $$ = abc_nop($$);
1485 breakjumpsto($$, $1.name, out);
1486 continuejumpsto($$, $1.name, loopstart);
1497 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1500 code_t*myjmp = $$ = abc_jump($$, 0);
1501 code_t*loopstart = $$ = abc_label($$);
1502 $$ = code_append($$, $6);
1503 code_t*cont = $$ = abc_nop($$);
1504 myjmp->branch = cont;
1505 $$ = code_append($$, $4.c);
1506 $$ = abc_iftrue($$, loopstart);
1507 code_t*out = $$ = abc_nop($$);
1508 breakjumpsto($$, $1, out);
1509 continuejumpsto($$, $1, cont);
1515 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1517 code_t*loopstart = $$ = abc_label($$);
1518 $$ = code_append($$, $3);
1519 code_t*cont = $$ = abc_nop($$);
1520 $$ = code_append($$, $6.c);
1521 $$ = abc_iftrue($$, loopstart);
1522 code_t*out = $$ = abc_nop($$);
1523 breakjumpsto($$, $1, out);
1524 continuejumpsto($$, $1, cont);
1529 BREAK : "break" %prec prec_none {
1530 $$ = abc___break__(0, "");
1532 BREAK : "break" T_IDENTIFIER {
1533 $$ = abc___break__(0, $2);
1535 CONTINUE : "continue" %prec prec_none {
1536 $$ = abc___continue__(0, "");
1538 CONTINUE : "continue" T_IDENTIFIER {
1539 $$ = abc___continue__(0, $2);
1542 MAYBE_CASE_LIST : {$$=0;}
1543 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1544 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1545 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1546 CASE_LIST: CASE {$$=$1}
1547 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1549 CASE: "case" E ':' MAYBECODE {
1551 $$ = code_append($$, $2.c);
1552 code_t*j = $$ = abc_ifne($$, 0);
1553 $$ = code_append($$, $4);
1554 if($$->opcode != OPCODE___BREAK__) {
1555 $$ = abc___fallthrough__($$, "");
1557 code_t*e = $$ = abc_nop($$);
1560 DEFAULT: "default" ':' MAYBECODE {
1563 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1565 $$ = code_append($$, $7);
1566 code_t*out = $$ = abc_pop($$);
1567 breakjumpsto($$, $1, out);
1569 code_t*c = $$,*lastblock=0;
1571 if(c->opcode == OPCODE_IFNE) {
1572 if(!c->next) syntaxerror("internal error in fallthrough handling");
1574 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1576 c->opcode = OPCODE_JUMP;
1577 c->branch = lastblock;
1579 /* fall through end of switch */
1580 c->opcode = OPCODE_NOP;
1588 /* ------------ packages and imports ---------------- */
1590 X_IDENTIFIER: T_IDENTIFIER
1591 | "package" {$$="package";}
1593 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1594 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1596 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1597 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1599 IMPORT : "import" QNAME {
1602 syntaxerror("Couldn't import class\n");
1603 state_has_imports();
1604 dict_put(state->imports, c->name, c);
1607 IMPORT : "import" PACKAGE '.' '*' {
1610 state_has_imports();
1611 list_append(state->wildcard_imports, i);
1615 /* ------------ classes and interfaces (header) -------------- */
1617 MAYBE_MODIFIERS : {$$=0;}
1618 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1619 MODIFIER_LIST : MODIFIER {$$=$1;}
1620 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1622 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1623 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1624 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1625 | KW_STATIC {$$=FLAG_STATIC;}
1626 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1627 | KW_FINAL {$$=FLAG_FINAL;}
1628 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1629 | KW_NATIVE {$$=FLAG_NATIVE;}
1630 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1632 EXTENDS : {$$=registry_getobjectclass();}
1633 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1635 EXTENDS_LIST : {$$=list_new();}
1636 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1638 IMPLEMENTS_LIST : {$$=list_new();}
1639 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1641 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1642 EXTENDS IMPLEMENTS_LIST
1643 '{' {startclass($1,$3,$4,$5, 0);}
1645 '}' {endclass();$$=0;}
1647 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1649 '{' {startclass($1,$3,0,$4,1);}
1650 MAYBE_INTERFACE_BODY
1651 '}' {endclass();$$=0;}
1653 /* ------------ classes and interfaces (body) -------------- */
1656 MAYBE_CLASS_BODY : CLASS_BODY
1657 CLASS_BODY : CLASS_BODY_ITEM
1658 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1659 CLASS_BODY_ITEM : ';'
1660 CLASS_BODY_ITEM : SLOT_DECLARATION
1661 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1663 CLASS_BODY_ITEM : CODE_STATEMENT {
1664 code_t*c = state->cls->static_init;
1665 c = code_append(c, $1);
1666 state->cls->static_init = c;
1669 MAYBE_INTERFACE_BODY :
1670 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1671 INTERFACE_BODY : IDECLARATION
1672 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1674 IDECLARATION : "var" T_IDENTIFIER {
1675 syntaxerror("variable declarations not allowed in interfaces");
1677 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1679 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1680 syntaxerror("invalid method modifiers: interface methods always need to be public");
1682 startfunction(0,$1,$3,$4,&$6,$8);
1683 endfunction(0,$1,$3,$4,&$6,$8, 0);
1686 /* ------------ classes and interfaces (body, slots ) ------- */
1688 VARCONST: "var" | "const"
1690 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1692 memberinfo_t* info = state->cls?
1693 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1694 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1697 info->flags = flags;
1700 namespace_t mname_ns = {flags2access(flags), ""};
1701 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1703 trait_list_t**traits;
1707 traits = &global->init->traits;
1708 code = &global->init->method->body->code;
1709 } else if(flags&FLAG_STATIC) {
1711 traits = &state->cls->abc->static_traits;
1712 code = &state->cls->static_init;
1714 // instance variable
1715 traits = &state->cls->abc->traits;
1716 code = &state->cls->init;
1722 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1724 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1726 info->slot = t->slot_id;
1728 /* initalization code (if needed) */
1730 if($5.c && !is_pushundefined($5.c)) {
1731 c = abc_getlocal_0(c);
1732 c = code_append(c, $5.c);
1733 c = converttype(c, $5.t, $4);
1734 c = abc_setslot(c, t->slot_id);
1737 *code = code_append(*code, c);
1740 t->kind= TRAIT_CONST;
1746 /* ------------ constants -------------------------------------- */
1748 MAYBESTATICCONSTANT: {$$=0;}
1749 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1751 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1752 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1753 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1754 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1755 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1756 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1757 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1758 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1759 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1761 /* ------------ classes and interfaces (body, functions) ------- */
1763 // non-vararg version
1765 memset(&$$,0,sizeof($$));
1767 MAYBE_PARAM_LIST: PARAM_LIST {
1772 MAYBE_PARAM_LIST: "..." PARAM {
1773 memset(&$$,0,sizeof($$));
1775 list_append($$.list, $2);
1777 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1780 list_append($$.list, $4);
1784 PARAM_LIST: PARAM_LIST ',' PARAM {
1786 list_append($$.list, $3);
1789 memset(&$$,0,sizeof($$));
1790 list_append($$.list, $1);
1793 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1794 $$ = malloc(sizeof(param_t));
1799 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1800 $$ = malloc(sizeof(param_t));
1802 $$->type = TYPE_ANY;
1805 GETSET : "get" {$$=$1;}
1809 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1810 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1813 if(state->method->late_binding) {
1814 c = abc_getlocal_0(c);
1815 c = abc_pushscope(c);
1817 if(state->method->is_constructor && !state->method->has_super) {
1818 // call default constructor
1819 c = abc_getlocal_0(c);
1820 c = abc_constructsuper(c, 0);
1822 c = wrap_function(c, state->method->initcode, $11);
1823 endfunction(0,$1,$3,$4,&$6,$8,c);
1827 /* ------------- package + class ids --------------- */
1829 CLASS: T_IDENTIFIER {
1831 /* try current package */
1832 $$ = find_class($1);
1833 if(!$$) syntaxerror("Could not find class %s\n", $1);
1836 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1837 $$ = registry_findclass($1, $3);
1838 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1842 QNAME: PACKAGEANDCLASS
1845 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1846 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1848 TYPE : QNAME {$$=$1;}
1849 | '*' {$$=registry_getanytype();}
1850 | "void" {$$=registry_getanytype();}
1852 | "String" {$$=registry_getstringclass();}
1853 | "int" {$$=registry_getintclass();}
1854 | "uint" {$$=registry_getuintclass();}
1855 | "Boolean" {$$=registry_getbooleanclass();}
1856 | "Number" {$$=registry_getnumberclass();}
1859 MAYBETYPE: ':' TYPE {$$=$2;}
1862 /* ----------function calls, delete, constructor calls ------ */
1864 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
1865 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1867 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1868 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1869 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
1872 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1874 $$.cc = code_append($1.cc, $3.c);
1877 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1882 $$.c = abc_getglobalscope($$.c);
1883 $$.c = abc_getslot($$.c, $2->slot);
1885 $$.c = abc_findpropstrict2($$.c, &m);
1888 $$.c = code_append($$.c, $3.cc);
1891 $$.c = abc_construct($$.c, $3.len);
1893 $$.c = abc_constructprop2($$.c, &m, $3.len);
1897 /* TODO: use abc_call (for calling local variables),
1898 abc_callstatic (for calling own methods)
1901 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1904 if($$.c->opcode == OPCODE_COERCE_A) {
1905 $$.c = code_cutlast($$.c);
1907 code_t*paramcode = $3.cc;
1910 if($$.c->opcode == OPCODE_GETPROPERTY) {
1911 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1912 $$.c = code_cutlast($$.c);
1913 $$.c = code_append($$.c, paramcode);
1914 $$.c = abc_callproperty2($$.c, name, $3.len);
1915 multiname_destroy(name);
1916 } else if($$.c->opcode == OPCODE_GETSLOT) {
1917 int slot = (int)(ptroff_t)$$.c->data[0];
1918 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1919 if(t->kind!=TRAIT_METHOD) {
1920 //ok: flash allows to assign closures to members.
1922 multiname_t*name = t->name;
1923 $$.c = code_cutlast($$.c);
1924 $$.c = code_append($$.c, paramcode);
1925 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1926 $$.c = abc_callproperty2($$.c, name, $3.len);
1927 } else if($$.c->opcode == OPCODE_GETSUPER) {
1928 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1929 $$.c = code_cutlast($$.c);
1930 $$.c = code_append($$.c, paramcode);
1931 $$.c = abc_callsuper2($$.c, name, $3.len);
1932 multiname_destroy(name);
1934 $$.c = abc_getlocal_0($$.c);
1935 $$.c = code_append($$.c, paramcode);
1936 $$.c = abc_call($$.c, $3.len);
1941 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1942 $$.t = $1.t->function->return_type;
1944 $$.c = abc_coerce_a($$.c);
1949 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1950 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1951 if(!state->method) syntaxerror("super() not allowed outside of a function");
1952 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1955 $$.c = abc_getlocal_0($$.c);
1957 $$.c = code_append($$.c, $3.cc);
1959 this is dependent on the control path, check this somewhere else
1960 if(state->method->has_super)
1961 syntaxerror("constructor may call super() only once");
1963 state->method->has_super = 1;
1964 $$.c = abc_constructsuper($$.c, $3.len);
1965 $$.c = abc_pushundefined($$.c);
1969 DELETE: "delete" E {
1971 if($$.c->opcode == OPCODE_COERCE_A) {
1972 $$.c = code_cutlast($$.c);
1974 multiname_t*name = 0;
1975 if($$.c->opcode == OPCODE_GETPROPERTY) {
1976 $$.c->opcode = OPCODE_DELETEPROPERTY;
1977 } else if($$.c->opcode == OPCODE_GETSLOT) {
1978 int slot = (int)(ptroff_t)$$.c->data[0];
1979 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1980 $$.c = code_cutlast($$.c);
1981 $$.c = abc_deleteproperty2($$.c, name);
1983 $$.c = abc_getlocal_0($$.c);
1984 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1985 $$.c = abc_deleteproperty2($$.c, &m);
1987 $$.t = TYPE_BOOLEAN;
1990 RETURN: "return" %prec prec_none {
1991 $$ = abc_returnvoid(0);
1993 RETURN: "return" EXPRESSION {
1995 $$ = abc_returnvalue($$);
1998 // ----------------------- expression types -------------------------------------
2000 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2001 EXPRESSION : E %prec below_minus {$$ = $1;}
2002 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2004 $$.c = cut_last_push($$.c);
2005 $$.c = code_append($$.c,$3.c);
2008 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2009 $$=cut_last_push($1.c);
2012 // ----------------------- expression evaluation -------------------------------------
2015 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2017 E : DELETE {$$ = $1;}
2018 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
2022 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2023 //MULTINAME(m, registry_getintclass());
2024 //$$.c = abc_coerce2($$.c, &m); // FIXME
2027 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2030 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2033 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2036 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2039 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2042 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2045 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2046 $$.t = TYPE_BOOLEAN;
2048 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2049 $$.t = TYPE_BOOLEAN;
2051 CONSTANT : "null" {$$.c = abc_pushnull(0);
2056 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2057 $$.t = TYPE_BOOLEAN;
2059 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2060 $$.t = TYPE_BOOLEAN;
2062 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2063 $$.t = TYPE_BOOLEAN;
2065 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2066 $$.t = TYPE_BOOLEAN;
2068 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2069 $$.t = TYPE_BOOLEAN;
2071 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2072 $$.t = TYPE_BOOLEAN;
2074 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2075 $$.t = TYPE_BOOLEAN;
2077 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2078 $$.t = TYPE_BOOLEAN;
2081 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2083 $$.c = converttype($$.c, $1.t, $$.t);
2084 $$.c = abc_dup($$.c);
2085 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2086 $$.c = cut_last_push($$.c);
2087 $$.c = code_append($$.c,$3.c);
2088 $$.c = converttype($$.c, $3.t, $$.t);
2089 code_t*label = $$.c = abc_label($$.c);
2090 jmp->branch = label;
2093 $$.t = join_types($1.t, $3.t, 'A');
2094 /*printf("%08x:\n",$1.t);
2095 code_dump($1.c, 0, 0, "", stdout);
2096 printf("%08x:\n",$3.t);
2097 code_dump($3.c, 0, 0, "", stdout);
2098 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2100 $$.c = converttype($$.c, $1.t, $$.t);
2101 $$.c = abc_dup($$.c);
2102 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2103 $$.c = cut_last_push($$.c);
2104 $$.c = code_append($$.c,$3.c);
2105 $$.c = converttype($$.c, $3.t, $$.t);
2106 code_t*label = $$.c = abc_label($$.c);
2107 jmp->branch = label;
2110 E : '!' E {$$.c=$2.c;
2111 $$.c = abc_not($$.c);
2112 $$.t = TYPE_BOOLEAN;
2115 E : '~' E {$$.c=$2.c;
2116 $$.c = abc_bitnot($$.c);
2120 E : E '&' E {$$.c = code_append($1.c,$3.c);
2121 $$.c = abc_bitand($$.c);
2125 E : E '^' E {$$.c = code_append($1.c,$3.c);
2126 $$.c = abc_bitxor($$.c);
2130 E : E '|' E {$$.c = code_append($1.c,$3.c);
2131 $$.c = abc_bitor($$.c);
2135 E : E '-' E {$$.c = code_append($1.c,$3.c);
2136 if(BOTH_INT($1,$3)) {
2137 $$.c = abc_subtract_i($$.c);
2140 $$.c = abc_subtract($$.c);
2144 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2145 $$.c = abc_rshift($$.c);
2148 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2149 $$.c = abc_urshift($$.c);
2152 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2153 $$.c = abc_lshift($$.c);
2157 E : E '/' E {$$.c = code_append($1.c,$3.c);
2158 $$.c = abc_divide($$.c);
2161 E : E '+' E {$$.c = code_append($1.c,$3.c);
2162 $$.c = abc_add($$.c);
2165 E : E '%' E {$$.c = code_append($1.c,$3.c);
2166 $$.c = abc_modulo($$.c);
2169 E : E '*' E {$$.c = code_append($1.c,$3.c);
2170 if(BOTH_INT($1,$3)) {
2171 $$.c = abc_multiply_i($$.c);
2174 $$.c = abc_multiply($$.c);
2179 E : E "in" E {$$.c = code_append($1.c,$3.c);
2180 $$.c = abc_in($$.c);
2181 $$.t = TYPE_BOOLEAN;
2184 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2185 if(use_astype && TYPE_IS_CLASS($3.t)) {
2186 MULTINAME(m,$3.t->cls);
2187 $$.c = abc_astype2($1.c, &m);
2190 $$.c = code_append($1.c, $3.c);
2191 $$.c = abc_astypelate($$.c);
2196 E : E "instanceof" E
2197 {$$.c = code_append($1.c, $3.c);
2198 $$.c = abc_instanceof($$.c);
2199 $$.t = TYPE_BOOLEAN;
2202 E : E "is" E {$$.c = code_append($1.c, $3.c);
2203 $$.c = abc_istypelate($$.c);
2204 $$.t = TYPE_BOOLEAN;
2207 E : "typeof" '(' E ')' {
2209 $$.c = abc_typeof($$.c);
2214 $$.c = cut_last_push($2.c);
2215 $$.c = abc_pushundefined($$.c);
2219 E : "void" { $$.c = abc_pushundefined(0);
2223 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2228 $$.c=abc_negate_i($$.c);
2231 $$.c=abc_negate($$.c);
2238 $$.c = code_append($$.c, $3.c);
2240 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2241 $$.c = abc_getproperty2($$.c, &m);
2242 $$.t = 0; // array elements have unknown type
2245 E : '[' MAYBE_EXPRESSION_LIST ']' {
2247 $$.c = code_append($$.c, $2.cc);
2248 $$.c = abc_newarray($$.c, $2.len);
2249 $$.t = registry_getarrayclass();
2252 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2253 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2255 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2257 $$.cc = code_append($$.cc, $1.c);
2258 $$.cc = code_append($$.cc, $3.c);
2261 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2264 $$.cc = code_append($$.cc, $3.c);
2265 $$.cc = code_append($$.cc, $5.c);
2270 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2272 $$.c = code_append($$.c, $2.cc);
2273 $$.c = abc_newobject($$.c, $2.len/2);
2274 $$.t = registry_getobjectclass();
2279 if(BOTH_INT($1,$3)) {
2280 c=abc_multiply_i(c);
2284 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2285 $$.c = toreadwrite($1.c, c, 0, 0);
2290 code_t*c = abc_modulo($3.c);
2291 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2292 $$.c = toreadwrite($1.c, c, 0, 0);
2296 code_t*c = abc_lshift($3.c);
2297 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2298 $$.c = toreadwrite($1.c, c, 0, 0);
2302 code_t*c = abc_rshift($3.c);
2303 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2304 $$.c = toreadwrite($1.c, c, 0, 0);
2308 code_t*c = abc_urshift($3.c);
2309 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2310 $$.c = toreadwrite($1.c, c, 0, 0);
2314 code_t*c = abc_divide($3.c);
2315 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2316 $$.c = toreadwrite($1.c, c, 0, 0);
2321 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2326 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2328 $$.c = toreadwrite($1.c, c, 0, 0);
2331 E : E "-=" E { code_t*c = $3.c;
2332 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2333 c=abc_subtract_i(c);
2337 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2339 $$.c = toreadwrite($1.c, c, 0, 0);
2342 E : E '=' E { code_t*c = 0;
2343 c = code_append(c, $3.c);
2344 c = converttype(c, $3.t, $1.t);
2345 $$.c = toreadwrite($1.c, c, 1, 0);
2349 E : E '?' E ':' E %prec below_assignment {
2351 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2352 $$.c = code_append($$.c, $3.c);
2353 code_t*j2 = $$.c = abc_jump($$.c, 0);
2354 $$.c = j1->branch = abc_label($$.c);
2355 $$.c = code_append($$.c, $5.c);
2356 $$.c = j2->branch = abc_label($$.c);
2357 $$.t = join_types($3.t,$5.t,'?');
2360 // TODO: use inclocal where appropriate
2361 E : E "++" { code_t*c = 0;
2362 classinfo_t*type = $1.t;
2363 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2364 c=abc_increment_i(c);
2370 c=converttype(c, type, $1.t);
2371 $$.c = toreadwrite($1.c, c, 0, 1);
2374 E : E "--" { code_t*c = 0;
2375 classinfo_t*type = $1.t;
2376 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2377 c=abc_decrement_i(c);
2383 c=converttype(c, type, $1.t);
2384 $$.c = toreadwrite($1.c, c, 0, 1);
2388 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2389 classinfo_t*type = $2.t;
2390 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2391 c=abc_increment_i(c);
2397 c=converttype(c, type, $2.t);
2398 $$.c = toreadwrite($2.c, c, 0, 0);
2402 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2403 classinfo_t*type = $2.t;
2404 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2405 c=abc_decrement_i(c);
2411 c=converttype(c, type, $2.t);
2412 $$.c = toreadwrite($2.c, c, 0, 0);
2416 E : "super" '.' T_IDENTIFIER
2417 { if(!state->cls->info)
2418 syntaxerror("super keyword not allowed outside a class");
2419 classinfo_t*t = state->cls->info->superclass;
2420 if(!t) t = TYPE_OBJECT;
2422 memberinfo_t*f = registry_findmember(t, $3, 1);
2423 namespace_t ns = {flags2access(f->flags), ""};
2424 MEMBER_MULTINAME(m, f, $3);
2426 $$.c = abc_getlocal_0($$.c);
2427 $$.c = abc_getsuper2($$.c, &m);
2428 $$.t = memberinfo_gettype(f);
2431 E : E '.' T_IDENTIFIER
2433 classinfo_t*t = $1.t;
2435 if(TYPE_IS_CLASS(t) && t->cls) {
2440 memberinfo_t*f = registry_findmember(t, $3, 1);
2442 if(f && !is_static != !(f->flags&FLAG_STATIC))
2444 if(f && f->slot && !noslot) {
2445 $$.c = abc_getslot($$.c, f->slot);
2447 MEMBER_MULTINAME(m, f, $3);
2448 $$.c = abc_getproperty2($$.c, &m);
2450 /* determine type */
2451 $$.t = memberinfo_gettype(f);
2453 $$.c = abc_coerce_a($$.c);
2455 /* when resolving a property on an unknown type, we do know the
2456 name of the property (and don't seem to need the package), but
2457 we need to make avm2 try out all access modes */
2458 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2459 $$.c = abc_getproperty2($$.c, &m);
2460 $$.c = abc_coerce_a($$.c);
2461 $$.t = registry_getanytype();
2465 VAR_READ : T_IDENTIFIER {
2472 /* look at variables */
2473 if((v = find_variable($1))) {
2474 // $1 is a local variable
2475 $$.c = abc_getlocal($$.c, v->index);
2478 /* look at current class' members */
2479 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2480 // $1 is a function in this class
2481 int var_is_static = (f->flags&FLAG_STATIC);
2482 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2483 if(var_is_static != i_am_static) {
2484 /* there doesn't seem to be any "static" way to access
2485 static properties of a class */
2486 state->method->late_binding = 1;
2488 namespace_t ns = {flags2access(f->flags), ""};
2489 multiname_t m = {QNAME, &ns, 0, $1};
2490 $$.c = abc_findpropstrict2($$.c, &m);
2491 $$.c = abc_getproperty2($$.c, &m);
2494 $$.c = abc_getlocal_0($$.c);
2495 $$.c = abc_getslot($$.c, f->slot);
2497 namespace_t ns = {flags2access(f->flags), ""};
2498 multiname_t m = {QNAME, &ns, 0, $1};
2499 $$.c = abc_getlocal_0($$.c);
2500 $$.c = abc_getproperty2($$.c, &m);
2503 if(f->kind == MEMBER_METHOD) {
2504 $$.t = TYPE_FUNCTION(f);
2509 /* look at actual classes, in the current package and imported */
2510 } else if((a = find_class($1))) {
2511 if(a->flags & FLAG_METHOD) {
2513 $$.c = abc_findpropstrict2($$.c, &m);
2514 $$.c = abc_getproperty2($$.c, &m);
2515 $$.t = TYPE_FUNCTION(a->function);
2518 $$.c = abc_getglobalscope($$.c);
2519 $$.c = abc_getslot($$.c, a->slot);
2522 $$.c = abc_getlex2($$.c, &m);
2524 $$.t = TYPE_CLASS(a);
2527 /* unknown object, let the avm2 resolve it */
2529 if(strcmp($1,"trace"))
2530 warning("Couldn't resolve '%s', doing late binding", $1);
2531 state->method->late_binding = 1;
2533 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2536 $$.c = abc_findpropstrict2($$.c, &m);
2537 $$.c = abc_getproperty2($$.c, &m);
2542 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2543 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2544 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2546 // ----------------- namespaces -------------------------------------------------
2548 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2549 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2550 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2552 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}