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
160 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
161 %type <token> PACKAGE_DECLARATION
162 %type <token> FUNCTION_DECLARATION
163 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
164 %type <token> CLASS_DECLARATION
165 %type <token> NAMESPACE_DECLARATION
166 %type <token> 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 init_globals()
365 global = rfx_calloc(sizeof(global_t));
368 static void new_state()
371 state_t*oldstate = state;
373 memcpy(s, state, sizeof(state_t)); //shallow copy
375 s->imports = dict_new();
379 state->has_own_imports = 0;
380 state->vars = dict_new();
381 state->old = oldstate;
383 static void state_has_imports()
385 state->wildcard_imports = list_clone(state->wildcard_imports);
386 state->imports = dict_clone(state->imports);
387 state->has_own_imports = 1;
390 static void state_destroy(state_t*state)
392 if(state->has_own_imports) {
393 list_free(state->wildcard_imports);
394 dict_destroy(state->imports);state->imports=0;
396 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
397 dict_destroy(state->imports);state->imports=0;
401 for(t=0;t<state->vars->hashsize;t++) {
402 dictentry_t*e =state->vars->slots[t];
404 free(e->data);e->data=0;
408 dict_destroy(state->vars);state->vars=0;
414 static void old_state()
416 if(!state || !state->old)
417 syntaxerror("invalid nesting");
418 state_t*leaving = state;
420 /*if(state->method->initcode) {
421 printf("residual initcode\n");
422 code_dump(state->method->initcode, 0, 0, "", stdout);
424 state_destroy(leaving);
426 void initialize_state()
431 global->file = abc_file_new();
432 global->file->flags &= ~ABCFILE_LAZY;
434 global->init = abc_initscript(global->file, 0);
435 code_t*c = global->init->method->body->code;
437 c = abc_getlocal_0(c);
438 c = abc_pushscope(c);
440 /* findpropstrict doesn't just return a scope object- it
441 also makes it "active" somehow. Push local_0 on the
442 scope stack and read it back with findpropstrict, it'll
443 contain properties like "trace". Trying to find the same
444 property on a "vanilla" local_0 yields only a "undefined" */
445 //c = abc_findpropstrict(c, "[package]::trace");
447 /*c = abc_getlocal_0(c);
448 c = abc_findpropstrict(c, "[package]::trace");
450 c = abc_setlocal_1(c);
452 c = abc_pushbyte(c, 0);
453 c = abc_setlocal_2(c);
455 code_t*xx = c = abc_label(c);
456 c = abc_findpropstrict(c, "[package]::trace");
457 c = abc_pushstring(c, "prop:");
458 c = abc_hasnext2(c, 1, 2);
460 c = abc_setlocal_3(c);
461 c = abc_callpropvoid(c, "[package]::trace", 2);
462 c = abc_getlocal_3(c);
464 c = abc_iftrue(c,xx);*/
466 c = abc_findpropstrict(c, "[package]::trace");
467 c = abc_pushstring(c, "[entering global init function]");
468 c = abc_callpropvoid(c, "[package]::trace", 1);
470 global->init->method->body->code = c;
472 void* finalize_state()
474 if(state->level!=1) {
475 syntaxerror("unexpected end of file");
477 abc_method_body_t*m = global->init->method->body;
480 __ findpropstrict(m, "[package]::trace");
481 __ pushstring(m, "[leaving global init function]");
482 __ callpropvoid(m, "[package]::trace", 1);
485 state_destroy(state);
491 static void startpackage(char*name)
494 syntaxerror("Packages can not be nested.");
497 /*printf("entering package \"%s\"\n", name);*/
498 state->package = strdup(name);
500 static void endpackage()
502 /*printf("leaving package \"%s\"\n", state->package);*/
504 //used e.g. in classinfo_register:
505 //free(state->package);state->package=0;
511 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
514 syntaxerror("inner classes now allowed");
517 state->cls = rfx_calloc(sizeof(classstate_t));
520 classinfo_list_t*mlist=0;
521 /*printf("entering class %s\n", name);
522 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
524 printf(" extends: %s.%s\n", extends->package, extends->name);
525 printf(" implements (%d): ", list_length(implements));
526 for(mlist=implements;mlist;mlist=mlist->next) {
527 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
532 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
533 syntaxerror("invalid modifier(s)");
535 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
536 syntaxerror("public and internal not supported at the same time.");
538 /* create the class name, together with the proper attributes */
542 if(!(flags&FLAG_PUBLIC) && !state->package) {
543 access = ACCESS_PRIVATE; package = current_filename;
544 } else if(!(flags&FLAG_PUBLIC) && state->package) {
545 access = ACCESS_PACKAGEINTERNAL; package = state->package;
546 } else if(state->package) {
547 access = ACCESS_PACKAGE; package = state->package;
549 syntaxerror("public classes only allowed inside a package");
552 if(registry_findclass(package, classname)) {
553 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
557 /* build info struct */
558 int num_interfaces = (list_length(implements));
559 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
560 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
562 classinfo_list_t*l = implements;
563 for(l=implements;l;l=l->next) {
564 state->cls->info->interfaces[pos++] = l->classinfo;
567 multiname_t*extends2 = sig2mname(extends);
569 MULTINAME(classname2,state->cls->info);
572 state->cls_init = abc_getlocal_0(state->cls_init);
573 state->cls_init = abc_constructsuper(state->cls_init, 0);
576 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
577 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
578 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
580 state->cls->info->flags |= CLASS_INTERFACE;
581 abc_class_interface(state->cls->abc);
584 abc_class_protectedNS(state->cls->abc, classname);
586 for(mlist=implements;mlist;mlist=mlist->next) {
587 MULTINAME(m, mlist->classinfo);
588 abc_class_add_interface(state->cls->abc, &m);
591 /* now write the construction code for this class */
592 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
594 abc_method_body_t*m = global->init->method->body;
595 __ getglobalscope(m);
596 classinfo_t*s = extends;
601 //TODO: take a look at the current scope stack, maybe
602 // we can re-use something
607 multiname_t*s2 = sig2mname(s);
609 multiname_destroy(s2);
611 __ pushscope(m); count++;
612 m->code = m->code->prev->prev; // invert
614 /* continue appending after last op end */
615 while(m->code && m->code->next) m->code = m->code->next;
617 /* TODO: if this is one of *our* classes, we can also
618 do a getglobalscope/getslot <nr> (which references
619 the init function's slots) */
621 __ getlex2(m, extends2);
623 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
624 stack is not the superclass */
625 __ pushscope(m);count++;
628 /* notice: we get a verify error #1107 if the top element on the scope
629 stack is not the global object */
631 __ pushscope(m);count++;
633 __ newclass(m,state->cls->abc);
637 __ setslot(m, slotindex);
639 /* flash.display.MovieClip handling */
640 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
641 if(state->package && state->package[0]) {
642 globalclass = concat3(state->package, ".", classname);
644 globalclass = strdup(classname);
647 multiname_destroy(extends2);
650 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
652 c = code_append(c, initcode);
653 c = code_append(c, body);
654 /* append return if necessary */
655 if(!c || c->opcode != OPCODE_RETURNVOID &&
656 c->opcode != OPCODE_RETURNVALUE) {
657 c = abc_returnvoid(c);
662 static void endclass()
664 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
666 c = abc_getlocal_0(c);
667 c = abc_constructsuper(c, 0);
668 state->cls->init = code_append(state->cls->init, c);
671 if(state->cls->init) {
672 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
673 m->body->code = wrap_function(0, state->cls->init, m->body->code);
675 if(state->cls->static_init) {
676 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
677 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
679 // handy for scope testing
683 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
686 free(state->cls);state->cls=0;
690 typedef struct _variable {
695 static variable_t* find_variable(char*name)
701 v = dict_lookup(s->vars, name);
709 static variable_t* find_variable_safe(char*name)
711 variable_t* v = find_variable(name);
713 syntaxerror("undefined variable: %s", name);
716 static char variable_exists(char*name)
718 return dict_lookup(state->vars, name)!=0;
720 code_t*defaultvalue(code_t*c, classinfo_t*type);
721 static int new_variable(char*name, classinfo_t*type, char init)
724 v->index = global->variable_count;
726 dict_put(state->vars, name, v);
728 if(init && state->method && type) {
729 /* if this is a typed variable:
730 push default value for type on stack at the very beginning of the
731 method, so that it always has that type regardless of the control
733 state->method->initcode = defaultvalue(state->method->initcode, type);
734 state->method->initcode = abc_setlocal(state->method->initcode, v->index);
736 return global->variable_count++;
738 #define TEMPVARNAME "__as3_temp__"
739 static int gettempvar()
741 variable_t*v = find_variable(TEMPVARNAME);
744 return new_variable(TEMPVARNAME, 0, 0);
747 code_t* killvars(code_t*c)
750 for(t=0;t<state->vars->hashsize;t++) {
751 dictentry_t*e =state->vars->slots[t];
753 variable_t*v = (variable_t*)e->data;
754 //do this always, otherwise register types don't match
755 //in the verifier when doing nested loops
756 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
757 c = abc_kill(c, v->index);
764 void check_code_for_break(code_t*c)
767 if(c->opcode == OPCODE___BREAK__) {
768 char*name = string_cstr(c->data[0]);
769 syntaxerror("Unresolved \"break %s\"", name);
771 if(c->opcode == OPCODE___CONTINUE__) {
772 char*name = string_cstr(c->data[0]);
773 syntaxerror("Unresolved \"continue %s\"", name);
780 static void check_constant_against_type(classinfo_t*t, constant_t*c)
782 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
783 if(TYPE_IS_NUMBER(t)) {
784 xassert(c->type == CONSTANT_FLOAT
785 || c->type == CONSTANT_INT
786 || c->type == CONSTANT_UINT);
787 } else if(TYPE_IS_UINT(t)) {
788 xassert(c->type == CONSTANT_UINT ||
789 (c->type == CONSTANT_INT && c->i>0));
790 } else if(TYPE_IS_INT(t)) {
791 xassert(c->type == CONSTANT_INT);
792 } else if(TYPE_IS_BOOLEAN(t)) {
793 xassert(c->type == CONSTANT_TRUE
794 || c->type == CONSTANT_FALSE);
798 static int flags2access(int flags)
801 if(flags&FLAG_PUBLIC) {
802 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
803 access = ACCESS_PACKAGE;
804 } else if(flags&FLAG_PRIVATE) {
805 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
806 access = ACCESS_PRIVATE;
807 } else if(flags&FLAG_PROTECTED) {
808 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
809 access = ACCESS_PROTECTED;
811 access = ACCESS_PACKAGEINTERNAL;
816 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
818 memberinfo_t*minfo = 0;
821 minfo = rfx_calloc(sizeof(memberinfo_t));
822 classinfo_t*c = classinfo_register(flags2access(flags), state->package, name, 0);
823 c->flags |= FLAG_METHOD;
825 minfo->kind = MEMBER_METHOD;
827 minfo->flags = FLAG_STATIC;
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;
972 syntaxerror("interface methods can't have a method body");
974 free(state->method);state->method=0;
980 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
985 void breakjumpsto(code_t*c, char*name, code_t*jump)
988 if(c->opcode == OPCODE___BREAK__) {
989 string_t*name2 = c->data[0];
990 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
991 c->opcode = OPCODE_JUMP;
998 void continuejumpsto(code_t*c, char*name, code_t*jump)
1001 if(c->opcode == OPCODE___CONTINUE__) {
1002 string_t*name2 = c->data[0];
1003 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1004 c->opcode = OPCODE_JUMP;
1012 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1014 if(!type1 || !type2)
1015 return registry_getanytype();
1016 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1017 return registry_getanytype();
1020 return registry_getanytype();
1022 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1027 return abc_coerce_a(c);
1031 // cast an "any" type to a specific type. subject to
1032 // runtime exceptions
1033 return abc_coerce2(c, &m);
1036 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1037 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1038 // allow conversion between number types
1039 return abc_coerce2(c, &m);
1041 //printf("%s.%s\n", from.package, from.name);
1042 //printf("%s.%s\n", to.package, to.name);
1044 classinfo_t*supertype = from;
1046 if(supertype == to) {
1047 // target type is one of from's superclasses
1048 return abc_coerce2(c, &m);
1051 while(supertype->interfaces[t]) {
1052 if(supertype->interfaces[t]==to) {
1053 // target type is one of from's interfaces
1054 return abc_coerce2(c, &m);
1058 supertype = supertype->superclass;
1060 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1062 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1064 syntaxerror("can't convert type %s to %s", from->name, to->name);
1067 code_t*defaultvalue(code_t*c, classinfo_t*type)
1069 if(TYPE_IS_INT(type)) {
1070 c = abc_pushbyte(c, 0);
1071 } else if(TYPE_IS_UINT(type)) {
1072 c = abc_pushuint(c, 0);
1073 } else if(TYPE_IS_FLOAT(type)) {
1075 } else if(TYPE_IS_BOOLEAN(type)) {
1076 c = abc_pushfalse(c);
1078 c = abc_pushnull(c);
1083 char is_pushundefined(code_t*c)
1085 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1088 void parserassert(int b)
1090 if(!b) syntaxerror("internal error: assertion failed");
1093 static classinfo_t* find_class(char*name)
1097 c = registry_findclass(state->package, name);
1099 /* try explicit imports */
1100 dictentry_t* e = dict_get_slot(state->imports, name);
1104 if(!strcmp(e->key, name)) {
1105 c = (classinfo_t*)e->data;
1110 /* try package.* imports */
1111 import_list_t*l = state->wildcard_imports;
1115 //printf("does package %s contain a class %s?\n", l->import->package, name);
1116 c = registry_findclass(l->import->package, name);
1120 /* try global package */
1122 c = registry_findclass("", name);
1127 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1131 [prefix code] [read instruction]
1135 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1138 if(in && in->opcode == OPCODE_COERCE_A) {
1139 in = code_cutlast(in);
1142 syntaxerror("internal error");
1144 /* chop off read instruction */
1148 prefix = r->prev;r->prev = 0;
1154 char use_temp_var = readbefore;
1156 /* generate the write instruction, and maybe append a dup to the prefix code */
1157 code_t* write = abc_nop(0);
1158 if(r->opcode == OPCODE_GETPROPERTY) {
1159 write->opcode = OPCODE_SETPROPERTY;
1160 multiname_t*m = (multiname_t*)r->data[0];
1161 write->data[0] = multiname_clone(m);
1162 if(m->type == QNAME || m->type == MULTINAME) {
1164 prefix = abc_dup(prefix); // we need the object, too
1167 } else if(m->type == MULTINAMEL) {
1169 /* dupping two values on the stack requires 5 operations and one register-
1170 couldn't adobe just have given us a dup2? */
1171 int temp = gettempvar();
1172 prefix = abc_setlocal(prefix, temp);
1173 prefix = abc_dup(prefix);
1174 prefix = abc_getlocal(prefix, temp);
1175 prefix = abc_swap(prefix);
1176 prefix = abc_getlocal(prefix, temp);
1178 prefix = abc_kill(prefix, temp);
1182 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1184 } else if(r->opcode == OPCODE_GETSLOT) {
1185 write->opcode = OPCODE_SETSLOT;
1186 write->data[0] = r->data[0];
1188 prefix = abc_dup(prefix); // we need the object, too
1191 } else if(r->opcode == OPCODE_GETLOCAL) {
1192 write->opcode = OPCODE_SETLOCAL;
1193 write->data[0] = r->data[0];
1194 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1195 write->opcode = OPCODE_SETLOCAL_0;
1196 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1197 write->opcode = OPCODE_SETLOCAL_1;
1198 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1199 write->opcode = OPCODE_SETLOCAL_2;
1200 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1201 write->opcode = OPCODE_SETLOCAL_3;
1203 code_dump(r, 0, 0, "", stdout);
1204 syntaxerror("illegal lvalue: can't assign a value to this expression");
1211 /* with getproperty/getslot, we have to be extra careful not
1212 to execute the read code twice, as it might have side-effects
1213 (e.g. if the property is in fact a setter/getter combination)
1215 So read the value, modify it, and write it again,
1216 using prefix only once and making sure (by using a temporary
1217 register) that the return value is what we just wrote */
1218 temp = gettempvar();
1219 c = code_append(c, prefix);
1220 c = code_append(c, r);
1223 c = abc_setlocal(c, temp);
1225 c = code_append(c, middlepart);
1228 c = abc_setlocal(c, temp);
1230 c = code_append(c, write);
1231 c = abc_getlocal(c, temp);
1232 c = abc_kill(c, temp);
1234 /* if we're allowed to execute the read code twice *and*
1235 the middlepart doesn't modify the code, things are easier.
1237 code_t* r2 = code_dup(r);
1238 //c = code_append(c, prefix);
1239 parserassert(!prefix);
1240 c = code_append(c, r);
1241 c = code_append(c, middlepart);
1242 c = code_append(c, write);
1243 c = code_append(c, r2);
1246 /* even smaller version: overwrite the value without reading
1250 c = code_append(c, prefix);
1253 c = code_append(c, middlepart);
1254 c = code_append(c, write);
1255 c = code_append(c, r);
1257 temp = gettempvar();
1259 c = code_append(c, prefix);
1261 c = code_append(c, middlepart);
1263 c = abc_setlocal(c, temp);
1264 c = code_append(c, write);
1265 c = abc_getlocal(c, temp);
1266 c = abc_kill(c, temp);
1273 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1274 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1281 /* ------------ code blocks / statements ---------------- */
1283 PROGRAM: MAYBECODE {
1284 /* todo: do something with this code if we're outside a function */
1286 warning("ignored code");
1289 MAYBECODE: CODE {$$=$1;}
1290 MAYBECODE: {$$=code_new();}
1292 CODE: CODE CODEPIECE {
1293 $$=code_append($1,$2);
1299 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1300 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1301 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1302 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1303 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1304 CODEPIECE: ';' {$$=code_new();}
1305 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1306 CODEPIECE: VOIDEXPRESSION {$$=$1}
1307 CODEPIECE: FOR {$$=$1}
1308 CODEPIECE: FOR_IN {$$=$1}
1309 CODEPIECE: WHILE {$$=$1}
1310 CODEPIECE: DO_WHILE {$$=$1}
1311 CODEPIECE: SWITCH {$$=$1}
1312 CODEPIECE: BREAK {$$=$1}
1313 CODEPIECE: CONTINUE {$$=$1}
1314 CODEPIECE: RETURN {$$=$1}
1315 CODEPIECE: IF {$$=$1}
1316 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1317 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1319 CODEBLOCK : '{' CODE '}' {$$=$2;}
1320 CODEBLOCK : '{' '}' {$$=0;}
1321 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1322 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1324 /* ------------ variables --------------------------- */
1326 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1327 | {$$.c=abc_pushundefined(0);
1331 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1332 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1334 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1335 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1337 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1339 if(variable_exists($1))
1340 syntaxerror("Variable %s already defined", $1);
1342 if(!is_subtype_of($3.t, $2)) {
1343 syntaxerror("Can't convert %s to %s", $3.t->name,
1347 int index = new_variable($1, $2, 1);
1350 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1352 $$ = converttype($$, $3.t, $2);
1353 $$ = abc_setlocal($$, index);
1355 $$ = defaultvalue(0, $2);
1356 $$ = abc_setlocal($$, index);
1359 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1361 $$ = abc_coerce_a($$);
1362 $$ = abc_setlocal($$, index);
1368 /* that's the default for a local register, anyway
1370 state->method->initcode = abc_pushundefined(state->method->initcode);
1371 state->method->initcode = abc_setlocal(state->method->initcode, index);
1373 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1376 /* ------------ control flow ------------------------- */
1378 MAYBEELSE: %prec below_else {$$ = code_new();}
1379 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1380 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1382 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1384 $$ = code_append($$, $4.c);
1385 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1387 $$ = code_append($$, $6);
1389 myjmp = $$ = abc_jump($$, 0);
1391 myif->branch = $$ = abc_nop($$);
1393 $$ = code_append($$, $7);
1394 myjmp->branch = $$ = abc_nop($$);
1397 $$ = killvars($$);old_state();
1400 FOR_INIT : {$$=code_new();}
1401 FOR_INIT : VARIABLE_DECLARATION
1402 FOR_INIT : VOIDEXPRESSION
1403 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1404 $$=$2;new_variable($2,$3,1);
1406 FOR_IN_INIT : T_IDENTIFIER {
1410 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1411 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1413 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1414 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1416 $$ = code_append($$, $2);
1417 code_t*loopstart = $$ = abc_label($$);
1418 $$ = code_append($$, $4.c);
1419 code_t*myif = $$ = abc_iffalse($$, 0);
1420 $$ = code_append($$, $8);
1421 code_t*cont = $$ = abc_nop($$);
1422 $$ = code_append($$, $6);
1423 $$ = abc_jump($$, loopstart);
1424 code_t*out = $$ = abc_nop($$);
1425 breakjumpsto($$, $1.name, out);
1426 continuejumpsto($$, $1.name, cont);
1429 $$ = killvars($$);old_state();
1432 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1433 variable_t*var = find_variable($2);
1434 char*tmp1name = concat2($2, "__tmp1__");
1435 int it = new_variable(tmp1name, TYPE_INT, 0);
1436 char*tmp2name = concat2($2, "__array__");
1437 int array = new_variable(tmp1name, 0, 0);
1440 $$ = code_append($$, $4.c);
1441 $$ = abc_coerce_a($$);
1442 $$ = abc_setlocal($$, array);
1443 $$ = abc_pushbyte($$, 0);
1444 $$ = abc_setlocal($$, it);
1446 code_t*loopstart = $$ = abc_label($$);
1448 $$ = abc_hasnext2($$, array, it);
1449 code_t*myif = $$ = abc_iffalse($$, 0);
1450 $$ = abc_getlocal($$, array);
1451 $$ = abc_getlocal($$, it);
1453 $$ = abc_nextname($$);
1455 $$ = abc_nextvalue($$);
1456 $$ = converttype($$, 0, var->type);
1457 $$ = abc_setlocal($$, var->index);
1459 $$ = code_append($$, $6);
1460 $$ = abc_jump($$, loopstart);
1462 code_t*out = $$ = abc_nop($$);
1463 breakjumpsto($$, $1.name, out);
1464 continuejumpsto($$, $1.name, loopstart);
1475 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1478 code_t*myjmp = $$ = abc_jump($$, 0);
1479 code_t*loopstart = $$ = abc_label($$);
1480 $$ = code_append($$, $6);
1481 code_t*cont = $$ = abc_nop($$);
1482 myjmp->branch = cont;
1483 $$ = code_append($$, $4.c);
1484 $$ = abc_iftrue($$, loopstart);
1485 code_t*out = $$ = abc_nop($$);
1486 breakjumpsto($$, $1, out);
1487 continuejumpsto($$, $1, cont);
1493 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1495 code_t*loopstart = $$ = abc_label($$);
1496 $$ = code_append($$, $3);
1497 code_t*cont = $$ = abc_nop($$);
1498 $$ = code_append($$, $6.c);
1499 $$ = abc_iftrue($$, loopstart);
1500 code_t*out = $$ = abc_nop($$);
1501 breakjumpsto($$, $1, out);
1502 continuejumpsto($$, $1, cont);
1507 BREAK : "break" %prec prec_none {
1508 $$ = abc___break__(0, "");
1510 BREAK : "break" T_IDENTIFIER {
1511 $$ = abc___break__(0, $2);
1513 CONTINUE : "continue" %prec prec_none {
1514 $$ = abc___continue__(0, "");
1516 CONTINUE : "continue" T_IDENTIFIER {
1517 $$ = abc___continue__(0, $2);
1520 MAYBE_CASE_LIST : {$$=0;}
1521 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1522 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1523 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1524 CASE_LIST: CASE {$$=$1}
1525 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1527 CASE: "case" E ':' MAYBECODE {
1529 $$ = code_append($$, $2.c);
1530 code_t*j = $$ = abc_ifne($$, 0);
1531 $$ = code_append($$, $4);
1532 if($$->opcode != OPCODE___BREAK__) {
1533 $$ = abc___fallthrough__($$, "");
1535 code_t*e = $$ = abc_nop($$);
1538 DEFAULT: "default" ':' MAYBECODE {
1541 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1543 $$ = code_append($$, $7);
1544 code_t*out = $$ = abc_pop($$);
1545 breakjumpsto($$, $1, out);
1547 code_t*c = $$,*lastblock=0;
1549 if(c->opcode == OPCODE_IFNE) {
1550 if(!c->next) syntaxerror("internal error in fallthrough handling");
1552 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1554 c->opcode = OPCODE_JUMP;
1555 c->branch = lastblock;
1557 /* fall through end of switch */
1558 c->opcode = OPCODE_NOP;
1566 /* ------------ packages and imports ---------------- */
1568 X_IDENTIFIER: T_IDENTIFIER
1569 | "package" {$$="package";}
1571 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1572 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1574 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBECODE '}' {endpackage()}
1575 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1577 IMPORT : "import" QNAME {
1580 syntaxerror("Couldn't import class\n");
1581 state_has_imports();
1582 dict_put(state->imports, c->name, c);
1585 IMPORT : "import" PACKAGE '.' '*' {
1588 state_has_imports();
1589 list_append(state->wildcard_imports, i);
1593 /* ------------ classes and interfaces (header) -------------- */
1595 MAYBE_MODIFIERS : {$$=0;}
1596 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1597 MODIFIER_LIST : MODIFIER {$$=$1;}
1598 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1600 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1601 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1602 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1603 | KW_STATIC {$$=FLAG_STATIC;}
1604 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1605 | KW_FINAL {$$=FLAG_FINAL;}
1606 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1607 | KW_NATIVE {$$=FLAG_NATIVE;}
1608 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1610 EXTENDS : {$$=registry_getobjectclass();}
1611 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1613 EXTENDS_LIST : {$$=list_new();}
1614 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1616 IMPLEMENTS_LIST : {$$=list_new();}
1617 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1619 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1620 EXTENDS IMPLEMENTS_LIST
1621 '{' {startclass($1,$3,$4,$5, 0);}
1622 MAYBE_DECLARATION_LIST
1625 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1627 '{' {startclass($1,$3,0,$4,1);}
1628 MAYBE_IDECLARATION_LIST
1631 /* ------------ classes and interfaces (body) -------------- */
1633 MAYBE_DECLARATION_LIST :
1634 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1635 DECLARATION_LIST : DECLARATION
1636 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1638 DECLARATION : SLOT_DECLARATION
1639 DECLARATION : FUNCTION_DECLARATION
1641 MAYBE_IDECLARATION_LIST :
1642 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1643 IDECLARATION_LIST : IDECLARATION
1644 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1646 IDECLARATION : "var" T_IDENTIFIER {
1647 syntaxerror("variable declarations not allowed in interfaces");
1649 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1651 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1652 syntaxerror("invalid method modifiers: interface methods always need to be public");
1654 startfunction(0,$1,$3,$4,&$6,$8);
1655 endfunction(0,$1,$3,$4,&$6,$8, 0);
1658 /* ------------ classes and interfaces (body, slots ) ------- */
1660 VARCONST: "var" | "const"
1662 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1664 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1666 info->flags = flags;
1669 namespace_t mname_ns = {flags2access(flags), ""};
1670 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1672 if(!(flags&FLAG_STATIC)) {
1675 t=abc_class_slot(state->cls->abc, &mname, &m);
1677 t=abc_class_slot(state->cls->abc, &mname, 0);
1679 info->slot = t->slot_id;
1683 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1685 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1687 info->slot = t->slot_id;
1689 if($5.c && !is_pushundefined($5.c)) {
1691 c = abc_getlocal_0(c);
1692 c = code_append(c, $5.c);
1693 c = converttype(c, $5.t, $4);
1694 c = abc_setslot(c, t->slot_id);
1695 if(!(flags&FLAG_STATIC))
1696 state->cls->init = code_append(state->cls->init, c);
1698 state->cls->static_init = code_append(state->cls->static_init, c);
1701 t->kind= TRAIT_CONST;
1705 /* ------------ constants -------------------------------------- */
1707 MAYBESTATICCONSTANT: {$$=0;}
1708 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1710 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1711 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1712 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1713 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1714 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1715 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1716 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1717 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1718 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1720 /* ------------ classes and interfaces (body, functions) ------- */
1722 // non-vararg version
1724 memset(&$$,0,sizeof($$));
1726 MAYBE_PARAM_LIST: PARAM_LIST {
1731 MAYBE_PARAM_LIST: "..." PARAM {
1732 memset(&$$,0,sizeof($$));
1734 list_append($$.list, $2);
1736 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1739 list_append($$.list, $4);
1743 PARAM_LIST: PARAM_LIST ',' PARAM {
1745 list_append($$.list, $3);
1748 memset(&$$,0,sizeof($$));
1749 list_append($$.list, $1);
1752 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1753 $$ = malloc(sizeof(param_t));
1758 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1759 $$ = malloc(sizeof(param_t));
1761 $$->type = TYPE_ANY;
1764 GETSET : "get" {$$=$1;}
1768 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1769 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1772 if(state->method->late_binding) {
1773 c = abc_getlocal_0(c);
1774 c = abc_pushscope(c);
1776 if(state->method->is_constructor && !state->method->has_super) {
1777 // call default constructor
1778 c = abc_getlocal_0(c);
1779 c = abc_constructsuper(c, 0);
1781 c = wrap_function(c, state->method->initcode, $11);
1782 endfunction(0,$1,$3,$4,&$6,$8,c);
1785 /* ------------- package + class ids --------------- */
1787 CLASS: T_IDENTIFIER {
1789 /* try current package */
1790 $$ = find_class($1);
1791 if(!$$) syntaxerror("Could not find class %s\n", $1);
1794 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1795 $$ = registry_findclass($1, $3);
1796 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1800 QNAME: PACKAGEANDCLASS
1803 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1804 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1806 TYPE : QNAME {$$=$1;}
1807 | '*' {$$=registry_getanytype();}
1808 | "void" {$$=registry_getanytype();}
1810 | "String" {$$=registry_getstringclass();}
1811 | "int" {$$=registry_getintclass();}
1812 | "uint" {$$=registry_getuintclass();}
1813 | "Boolean" {$$=registry_getbooleanclass();}
1814 | "Number" {$$=registry_getnumberclass();}
1817 MAYBETYPE: ':' TYPE {$$=$2;}
1820 /* ----------function calls, delete, constructor calls ------ */
1822 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
1823 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1825 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1826 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1827 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
1830 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1832 $$.cc = code_append($1.cc, $3.c);
1835 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1840 $$.c = abc_getglobalscope($$.c);
1841 $$.c = abc_getslot($$.c, $2->slot);
1843 $$.c = abc_findpropstrict2($$.c, &m);
1846 $$.c = code_append($$.c, $3.cc);
1849 $$.c = abc_construct($$.c, $3.len);
1851 $$.c = abc_constructprop2($$.c, &m, $3.len);
1855 /* TODO: use abc_call (for calling local variables),
1856 abc_callstatic (for calling own methods)
1859 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1862 if($$.c->opcode == OPCODE_COERCE_A) {
1863 $$.c = code_cutlast($$.c);
1865 code_t*paramcode = $3.cc;
1868 if($$.c->opcode == OPCODE_GETPROPERTY) {
1869 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1870 $$.c = code_cutlast($$.c);
1871 $$.c = code_append($$.c, paramcode);
1872 $$.c = abc_callproperty2($$.c, name, $3.len);
1873 multiname_destroy(name);
1874 } else if($$.c->opcode == OPCODE_GETSLOT) {
1875 int slot = (int)(ptroff_t)$$.c->data[0];
1876 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1877 if(t->kind!=TRAIT_METHOD) {
1878 //ok: flash allows to assign closures to members.
1880 multiname_t*name = t->name;
1881 $$.c = code_cutlast($$.c);
1882 $$.c = code_append($$.c, paramcode);
1883 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1884 $$.c = abc_callproperty2($$.c, name, $3.len);
1885 } else if($$.c->opcode == OPCODE_GETSUPER) {
1886 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1887 $$.c = code_cutlast($$.c);
1888 $$.c = code_append($$.c, paramcode);
1889 $$.c = abc_callsuper2($$.c, name, $3.len);
1890 multiname_destroy(name);
1892 $$.c = abc_getlocal_0($$.c);
1893 $$.c = code_append($$.c, paramcode);
1894 $$.c = abc_call($$.c, $3.len);
1899 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1900 $$.t = $1.t->function->return_type;
1902 $$.c = abc_coerce_a($$.c);
1907 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1908 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1909 if(!state->method) syntaxerror("super() not allowed outside of a function");
1910 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1913 $$.c = abc_getlocal_0($$.c);
1915 $$.c = code_append($$.c, $3.cc);
1917 this is dependent on the control path, check this somewhere else
1918 if(state->method->has_super)
1919 syntaxerror("constructor may call super() only once");
1921 state->method->has_super = 1;
1922 $$.c = abc_constructsuper($$.c, $3.len);
1923 $$.c = abc_pushundefined($$.c);
1927 DELETE: "delete" E {
1929 if($$.c->opcode == OPCODE_COERCE_A) {
1930 $$.c = code_cutlast($$.c);
1932 multiname_t*name = 0;
1933 if($$.c->opcode == OPCODE_GETPROPERTY) {
1934 $$.c->opcode = OPCODE_DELETEPROPERTY;
1935 } else if($$.c->opcode == OPCODE_GETSLOT) {
1936 int slot = (int)(ptroff_t)$$.c->data[0];
1937 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1938 $$.c = code_cutlast($$.c);
1939 $$.c = abc_deleteproperty2($$.c, name);
1941 $$.c = abc_getlocal_0($$.c);
1942 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1943 $$.c = abc_deleteproperty2($$.c, &m);
1945 $$.t = TYPE_BOOLEAN;
1948 RETURN: "return" %prec prec_none {
1949 $$ = abc_returnvoid(0);
1951 RETURN: "return" EXPRESSION {
1953 $$ = abc_returnvalue($$);
1956 // ----------------------- expression types -------------------------------------
1958 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1959 EXPRESSION : E %prec below_minus {$$ = $1;}
1960 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1962 $$.c = cut_last_push($$.c);
1963 $$.c = code_append($$.c,$3.c);
1966 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1967 $$=cut_last_push($1.c);
1970 // ----------------------- expression evaluation -------------------------------------
1973 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1975 E : DELETE {$$ = $1;}
1976 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1980 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1981 //MULTINAME(m, registry_getintclass());
1982 //$$.c = abc_coerce2($$.c, &m); // FIXME
1985 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1988 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1991 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1994 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1997 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2000 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2003 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2004 $$.t = TYPE_BOOLEAN;
2006 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2007 $$.t = TYPE_BOOLEAN;
2009 CONSTANT : "null" {$$.c = abc_pushnull(0);
2014 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2015 $$.t = TYPE_BOOLEAN;
2017 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2018 $$.t = TYPE_BOOLEAN;
2020 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2021 $$.t = TYPE_BOOLEAN;
2023 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2024 $$.t = TYPE_BOOLEAN;
2026 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2027 $$.t = TYPE_BOOLEAN;
2029 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2030 $$.t = TYPE_BOOLEAN;
2032 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2033 $$.t = TYPE_BOOLEAN;
2035 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2036 $$.t = TYPE_BOOLEAN;
2039 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2041 $$.c = converttype($$.c, $1.t, $$.t);
2042 $$.c = abc_dup($$.c);
2043 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2044 $$.c = cut_last_push($$.c);
2045 $$.c = code_append($$.c,$3.c);
2046 $$.c = converttype($$.c, $3.t, $$.t);
2047 code_t*label = $$.c = abc_label($$.c);
2048 jmp->branch = label;
2051 $$.t = join_types($1.t, $3.t, 'A');
2052 /*printf("%08x:\n",$1.t);
2053 code_dump($1.c, 0, 0, "", stdout);
2054 printf("%08x:\n",$3.t);
2055 code_dump($3.c, 0, 0, "", stdout);
2056 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2058 $$.c = converttype($$.c, $1.t, $$.t);
2059 $$.c = abc_dup($$.c);
2060 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2061 $$.c = cut_last_push($$.c);
2062 $$.c = code_append($$.c,$3.c);
2063 $$.c = converttype($$.c, $3.t, $$.t);
2064 code_t*label = $$.c = abc_label($$.c);
2065 jmp->branch = label;
2068 E : '!' E {$$.c=$2.c;
2069 $$.c = abc_not($$.c);
2070 $$.t = TYPE_BOOLEAN;
2073 E : '~' E {$$.c=$2.c;
2074 $$.c = abc_bitnot($$.c);
2078 E : E '&' E {$$.c = code_append($1.c,$3.c);
2079 $$.c = abc_bitand($$.c);
2083 E : E '^' E {$$.c = code_append($1.c,$3.c);
2084 $$.c = abc_bitxor($$.c);
2088 E : E '|' E {$$.c = code_append($1.c,$3.c);
2089 $$.c = abc_bitor($$.c);
2093 E : E '-' E {$$.c = code_append($1.c,$3.c);
2094 if(BOTH_INT($1,$3)) {
2095 $$.c = abc_subtract_i($$.c);
2098 $$.c = abc_subtract($$.c);
2102 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2103 $$.c = abc_rshift($$.c);
2106 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2107 $$.c = abc_urshift($$.c);
2110 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2111 $$.c = abc_lshift($$.c);
2115 E : E '/' E {$$.c = code_append($1.c,$3.c);
2116 $$.c = abc_divide($$.c);
2119 E : E '+' E {$$.c = code_append($1.c,$3.c);
2120 $$.c = abc_add($$.c);
2123 E : E '%' E {$$.c = code_append($1.c,$3.c);
2124 $$.c = abc_modulo($$.c);
2127 E : E '*' E {$$.c = code_append($1.c,$3.c);
2128 if(BOTH_INT($1,$3)) {
2129 $$.c = abc_multiply_i($$.c);
2132 $$.c = abc_multiply($$.c);
2137 E : E "in" E {$$.c = code_append($1.c,$3.c);
2138 $$.c = abc_in($$.c);
2139 $$.t = TYPE_BOOLEAN;
2142 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2143 if(use_astype && TYPE_IS_CLASS($3.t)) {
2144 MULTINAME(m,$3.t->cls);
2145 $$.c = abc_astype2($1.c, &m);
2148 $$.c = code_append($1.c, $3.c);
2149 $$.c = abc_astypelate($$.c);
2154 E : E "instanceof" E
2155 {$$.c = code_append($1.c, $3.c);
2156 $$.c = abc_instanceof($$.c);
2157 $$.t = TYPE_BOOLEAN;
2160 E : E "is" E {$$.c = code_append($1.c, $3.c);
2161 $$.c = abc_istypelate($$.c);
2162 $$.t = TYPE_BOOLEAN;
2165 E : "typeof" '(' E ')' {
2167 $$.c = abc_typeof($$.c);
2172 $$.c = cut_last_push($2.c);
2173 $$.c = abc_pushundefined($$.c);
2177 E : "void" { $$.c = abc_pushundefined(0);
2181 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2186 $$.c=abc_negate_i($$.c);
2189 $$.c=abc_negate($$.c);
2196 $$.c = code_append($$.c, $3.c);
2198 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2199 $$.c = abc_getproperty2($$.c, &m);
2200 $$.t = 0; // array elements have unknown type
2203 E : '[' MAYBE_EXPRESSION_LIST ']' {
2205 $$.c = code_append($$.c, $2.cc);
2206 $$.c = abc_newarray($$.c, $2.len);
2207 $$.t = registry_getarrayclass();
2210 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2211 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2213 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2215 $$.cc = code_append($$.cc, $1.c);
2216 $$.cc = code_append($$.cc, $3.c);
2219 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2222 $$.cc = code_append($$.cc, $3.c);
2223 $$.cc = code_append($$.cc, $5.c);
2228 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2230 $$.c = code_append($$.c, $2.cc);
2231 $$.c = abc_newobject($$.c, $2.len/2);
2232 $$.t = registry_getobjectclass();
2237 if(BOTH_INT($1,$3)) {
2238 c=abc_multiply_i(c);
2242 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2243 $$.c = toreadwrite($1.c, c, 0, 0);
2248 code_t*c = abc_modulo($3.c);
2249 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2250 $$.c = toreadwrite($1.c, c, 0, 0);
2254 code_t*c = abc_lshift($3.c);
2255 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2256 $$.c = toreadwrite($1.c, c, 0, 0);
2260 code_t*c = abc_rshift($3.c);
2261 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2262 $$.c = toreadwrite($1.c, c, 0, 0);
2266 code_t*c = abc_urshift($3.c);
2267 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2268 $$.c = toreadwrite($1.c, c, 0, 0);
2272 code_t*c = abc_divide($3.c);
2273 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2274 $$.c = toreadwrite($1.c, c, 0, 0);
2279 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2284 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2286 $$.c = toreadwrite($1.c, c, 0, 0);
2289 E : E "-=" E { code_t*c = $3.c;
2290 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2291 c=abc_subtract_i(c);
2295 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2297 $$.c = toreadwrite($1.c, c, 0, 0);
2300 E : E '=' E { code_t*c = 0;
2301 c = code_append(c, $3.c);
2302 c = converttype(c, $3.t, $1.t);
2303 $$.c = toreadwrite($1.c, c, 1, 0);
2307 E : E '?' E ':' E %prec below_assignment {
2309 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2310 $$.c = code_append($$.c, $3.c);
2311 code_t*j2 = $$.c = abc_jump($$.c, 0);
2312 $$.c = j1->branch = abc_label($$.c);
2313 $$.c = code_append($$.c, $5.c);
2314 $$.c = j2->branch = abc_label($$.c);
2315 $$.t = join_types($3.t,$5.t,'?');
2318 // TODO: use inclocal where appropriate
2319 E : E "++" { code_t*c = 0;
2320 classinfo_t*type = $1.t;
2321 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2322 c=abc_increment_i(c);
2328 c=converttype(c, type, $1.t);
2329 $$.c = toreadwrite($1.c, c, 0, 1);
2332 E : E "--" { code_t*c = 0;
2333 classinfo_t*type = $1.t;
2334 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2335 c=abc_decrement_i(c);
2341 c=converttype(c, type, $1.t);
2342 $$.c = toreadwrite($1.c, c, 0, 1);
2346 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2347 classinfo_t*type = $2.t;
2348 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2349 c=abc_increment_i(c);
2355 c=converttype(c, type, $2.t);
2356 $$.c = toreadwrite($2.c, c, 0, 0);
2360 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2361 classinfo_t*type = $2.t;
2362 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2363 c=abc_decrement_i(c);
2369 c=converttype(c, type, $2.t);
2370 $$.c = toreadwrite($2.c, c, 0, 0);
2374 E : "super" '.' T_IDENTIFIER
2375 { if(!state->cls->info)
2376 syntaxerror("super keyword not allowed outside a class");
2377 classinfo_t*t = state->cls->info->superclass;
2378 if(!t) t = TYPE_OBJECT;
2380 memberinfo_t*f = registry_findmember(t, $3, 1);
2381 namespace_t ns = {flags2access(f->flags), ""};
2382 MEMBER_MULTINAME(m, f, $3);
2384 $$.c = abc_getlocal_0($$.c);
2385 $$.c = abc_getsuper2($$.c, &m);
2386 $$.t = memberinfo_gettype(f);
2389 E : E '.' T_IDENTIFIER
2391 classinfo_t*t = $1.t;
2393 if(TYPE_IS_CLASS(t) && t->cls) {
2398 memberinfo_t*f = registry_findmember(t, $3, 1);
2400 if(f && !is_static != !(f->flags&FLAG_STATIC))
2402 if(f && f->slot && !noslot) {
2403 $$.c = abc_getslot($$.c, f->slot);
2405 MEMBER_MULTINAME(m, f, $3);
2406 $$.c = abc_getproperty2($$.c, &m);
2408 /* determine type */
2409 $$.t = memberinfo_gettype(f);
2411 $$.c = abc_coerce_a($$.c);
2413 /* when resolving a property on an unknown type, we do know the
2414 name of the property (and don't seem to need the package), but
2415 we need to make avm2 try out all access modes */
2416 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2417 $$.c = abc_getproperty2($$.c, &m);
2418 $$.c = abc_coerce_a($$.c);
2419 $$.t = registry_getanytype();
2423 VAR_READ : T_IDENTIFIER {
2430 /* look at variables */
2431 if((v = find_variable($1))) {
2432 // $1 is a local variable
2433 $$.c = abc_getlocal($$.c, v->index);
2436 /* look at current class' members */
2437 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2438 // $1 is a function in this class
2439 int var_is_static = (f->flags&FLAG_STATIC);
2440 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2441 if(var_is_static != i_am_static) {
2442 /* there doesn't seem to be any "static" way to access
2443 static properties of a class */
2444 state->method->late_binding = 1;
2446 namespace_t ns = {flags2access(f->flags), ""};
2447 multiname_t m = {QNAME, &ns, 0, $1};
2448 $$.c = abc_findpropstrict2($$.c, &m);
2449 $$.c = abc_getproperty2($$.c, &m);
2452 $$.c = abc_getlocal_0($$.c);
2453 $$.c = abc_getslot($$.c, f->slot);
2455 namespace_t ns = {flags2access(f->flags), ""};
2456 multiname_t m = {QNAME, &ns, 0, $1};
2457 $$.c = abc_getlocal_0($$.c);
2458 $$.c = abc_getproperty2($$.c, &m);
2461 if(f->kind == MEMBER_METHOD) {
2462 $$.t = TYPE_FUNCTION(f);
2467 /* look at actual classes, in the current package and imported */
2468 } else if((a = find_class($1))) {
2469 if(a->flags & FLAG_METHOD) {
2471 $$.c = abc_findpropstrict2($$.c, &m);
2472 $$.c = abc_getproperty2($$.c, &m);
2473 $$.t = TYPE_FUNCTION(a->function);
2476 $$.c = abc_getglobalscope($$.c);
2477 $$.c = abc_getslot($$.c, a->slot);
2480 $$.c = abc_getlex2($$.c, &m);
2482 $$.t = TYPE_CLASS(a);
2485 /* unknown object, let the avm2 resolve it */
2487 if(strcmp($1,"trace"))
2488 warning("Couldn't resolve '%s', doing late binding", $1);
2489 state->method->late_binding = 1;
2491 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2494 $$.c = abc_findpropstrict2($$.c, &m);
2495 $$.c = abc_getproperty2($$.c, &m);
2500 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2501 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2502 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2504 // ----------------- namespaces -------------------------------------------------
2506 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2507 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2508 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2510 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER