3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
30 #include "tokenizer.h"
42 enum yytokentype token;
45 classinfo_t*classinfo;
46 classinfo_list_t*classinfo_list;
49 unsigned int number_uint;
53 //typedcode_list_t*value_list;
54 codeandnumber_t value_list;
60 for_start_t for_start;
61 abc_exception_t *exception;
62 abc_exception_list_t *exception_list;
67 %token<id> T_IDENTIFIER
69 %token<regexp> T_REGEXP
71 %token<number_int> T_INT
72 %token<number_uint> T_UINT
73 %token<number_uint> T_BYTE
74 %token<number_uint> T_SHORT
75 %token<number_float> T_FLOAT
77 %token<id> T_FOR "for"
78 %token<id> T_WHILE "while"
80 %token<id> T_SWITCH "switch"
82 %token<token> KW_IMPLEMENTS "implements"
83 %token<token> KW_NAMESPACE "namespace"
84 %token<token> KW_PACKAGE "package"
85 %token<token> KW_PROTECTED "protected"
86 %token<token> KW_PUBLIC "public"
87 %token<token> KW_PRIVATE "private"
88 %token<token> KW_USE "use"
89 %token<token> KW_INTERNAL "internal"
90 %token<token> KW_NEW "new"
91 %token<token> KW_NATIVE "native"
92 %token<token> KW_FUNCTION "function"
93 %token<token> KW_UNDEFINED "undefined"
94 %token<token> KW_CONTINUE "continue"
95 %token<token> KW_CLASS "class"
96 %token<token> KW_CONST "const"
97 %token<token> KW_CATCH "catch"
98 %token<token> KW_CASE "case"
99 %token<token> KW_SET "set"
100 %token<token> KW_VOID "void"
101 %token<token> KW_THROW "throw"
102 %token<token> KW_STATIC "static"
103 %token<token> KW_WITH "with"
104 %token<token> KW_INSTANCEOF "instanceof"
105 %token<token> KW_IMPORT "import"
106 %token<token> KW_RETURN "return"
107 %token<token> KW_TYPEOF "typeof"
108 %token<token> KW_INTERFACE "interface"
109 %token<token> KW_NULL "null"
110 %token<token> KW_VAR "var"
111 %token<token> KW_DYNAMIC "dynamic"
112 %token<token> KW_OVERRIDE "override"
113 %token<token> KW_FINAL "final"
114 %token<token> KW_EACH "each"
115 %token<token> KW_GET "get"
116 %token<token> KW_TRY "try"
117 %token<token> KW_SUPER "super"
118 %token<token> KW_EXTENDS "extends"
119 %token<token> KW_FALSE "false"
120 %token<token> KW_TRUE "true"
121 %token<token> KW_BOOLEAN "Boolean"
122 %token<token> KW_UINT "uint"
123 %token<token> KW_INT "int"
124 %token<token> KW_NUMBER "Number"
125 %token<token> KW_STRING "String"
126 %token<token> KW_DEFAULT "default"
127 %token<token> KW_DELETE "delete"
128 %token<token> KW_IF "if"
129 %token<token> KW_ELSE "else"
130 %token<token> KW_BREAK "break"
131 %token<token> KW_IS "is"
132 %token<token> KW_IN "in"
133 %token<token> KW_AS "as"
135 %token<token> T_EQEQ "=="
136 %token<token> T_EQEQEQ "==="
137 %token<token> T_NE "!="
138 %token<token> T_NEE "!=="
139 %token<token> T_LE "<="
140 %token<token> T_GE ">="
141 %token<token> T_ORBY "|="
142 %token<token> T_DIVBY "/="
143 %token<token> T_MODBY "%="
144 %token<token> T_MULBY "*="
145 %token<token> T_PLUSBY "+="
146 %token<token> T_MINUSBY "-="
147 %token<token> T_SHRBY ">>="
148 %token<token> T_SHLBY "<<="
149 %token<token> T_USHRBY ">>>="
150 %token<token> T_OROR "||"
151 %token<token> T_ANDAND "&&"
152 %token<token> T_COLONCOLON "::"
153 %token<token> T_MINUSMINUS "--"
154 %token<token> T_PLUSPLUS "++"
155 %token<token> T_DOTDOT ".."
156 %token<token> T_DOTDOTDOT "..."
157 %token<token> T_SHL "<<"
158 %token<token> T_USHR ">>>"
159 %token<token> T_SHR ">>"
161 %type <for_start> FOR_START
162 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
163 %type <token> VARCONST
165 %type <code> CODEPIECE CODE_STATEMENT
166 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
167 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
168 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
169 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
170 %type <exception> CATCH
171 %type <exception_list> CATCH_LIST
172 %type <code> CLASS_DECLARATION
173 %type <code> NAMESPACE_DECLARATION
174 %type <code> INTERFACE_DECLARATION
175 %type <code> VOIDEXPRESSION
176 %type <value> EXPRESSION NONCOMMAEXPRESSION
177 %type <value> MAYBEEXPRESSION
178 %type <value> E DELETE
179 %type <value> CONSTANT
180 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
181 %type <token> USE_NAMESPACE
182 %type <code> FOR_INIT
184 %type <classinfo> MAYBETYPE
187 %type <params> PARAM_LIST
188 %type <params> MAYBE_PARAM_LIST
189 %type <flags> MAYBE_MODIFIERS
190 %type <flags> MODIFIER_LIST
191 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
192 %type <classinfo_list> IMPLEMENTS_LIST
193 %type <classinfo> EXTENDS
194 %type <classinfo_list> EXTENDS_LIST
195 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
196 %type <classinfo_list> QNAME_LIST
197 %type <classinfo> TYPE
198 //%type <token> VARIABLE
199 %type <value> VAR_READ
201 //%type <token> T_IDENTIFIER
202 %type <token> MODIFIER
203 %type <value> FUNCTIONCALL
204 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
206 // precedence: from low to high
210 %left below_semicolon
213 %nonassoc below_assignment // for ?:, contrary to spec
214 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
221 %nonassoc "==" "!=" "===" "!=="
222 %nonassoc "is" "as" "in"
223 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
224 %left "<<" ">>" ">>>"
228 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
230 %nonassoc below_curly
231 %left '[' ']' '{' "new" '.' ".." "::"
232 %nonassoc T_IDENTIFIER
233 %left above_identifier
238 // needed for "return" precedence:
239 %nonassoc T_STRING T_REGEXP
240 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
241 %nonassoc "false" "true" "null" "undefined" "super"
247 static int yyerror(char*s)
249 syntaxerror("%s", s);
252 static char* concat2(const char* t1, const char* t2)
256 char*text = malloc(l1+l2+1);
257 memcpy(text , t1, l1);
258 memcpy(text+l1, t2, l2);
262 static char* concat3(const char* t1, const char* t2, const char* t3)
267 char*text = malloc(l1+l2+l3+1);
268 memcpy(text , t1, l1);
269 memcpy(text+l1, t2, l2);
270 memcpy(text+l1+l2, t3, l3);
275 typedef struct _import {
279 DECLARE_LIST(import);
281 typedef struct _classstate {
287 char has_constructor;
290 typedef struct _methodstate {
297 abc_exception_list_t*exceptions;
300 typedef struct _state {
305 import_list_t*wildcard_imports;
307 char has_own_imports;
310 methodstate_t*method;
317 typedef struct _global {
324 static global_t*global = 0;
325 static state_t* state = 0;
329 #define MULTINAME(m,x) \
332 registry_fill_multiname(&m, &m##_ns, x);
334 #define MEMBER_MULTINAME(m,f,n) \
338 m##_ns = flags2namespace(f->flags, ""); \
341 m.namespace_set = 0; \
344 m.type = MULTINAME; \
346 m.namespace_set = &nopackage_namespace_set; \
350 /* warning: list length of namespace set is undefined */
351 #define MULTINAME_LATE(m, access, package) \
352 namespace_t m##_ns = {access, package}; \
353 namespace_set_t m##_nsset; \
354 namespace_list_t m##_l;m##_l.next = 0; \
355 m##_nsset.namespaces = &m##_l; \
356 m##_nsset = m##_nsset; \
357 m##_l.namespace = &m##_ns; \
358 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
360 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
361 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
362 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
363 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
364 static namespace_list_t nl4 = {&ns4,0};
365 static namespace_list_t nl3 = {&ns3,&nl4};
366 static namespace_list_t nl2 = {&ns2,&nl3};
367 static namespace_list_t nl1 = {&ns1,&nl2};
368 static namespace_set_t nopackage_namespace_set = {&nl1};
370 static void new_state()
373 state_t*oldstate = state;
375 memcpy(s, state, sizeof(state_t)); //shallow copy
377 s->imports = dict_new();
381 state->has_own_imports = 0;
382 state->vars = dict_new();
383 state->old = oldstate;
385 static void state_has_imports()
387 state->wildcard_imports = list_clone(state->wildcard_imports);
388 state->imports = dict_clone(state->imports);
389 state->has_own_imports = 1;
392 static void state_destroy(state_t*state)
394 if(state->has_own_imports) {
395 list_free(state->wildcard_imports);
396 dict_destroy(state->imports);state->imports=0;
398 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
399 dict_destroy(state->imports);state->imports=0;
403 for(t=0;t<state->vars->hashsize;t++) {
404 dictentry_t*e =state->vars->slots[t];
406 free(e->data);e->data=0;
410 dict_destroy(state->vars);state->vars=0;
416 static void old_state()
418 if(!state || !state->old)
419 syntaxerror("invalid nesting");
420 state_t*leaving = state;
423 state_destroy(leaving);
425 void initialize_state()
427 global = rfx_calloc(sizeof(global_t));
430 state->package = current_filename;
432 global->file = abc_file_new();
433 global->file->flags &= ~ABCFILE_LAZY;
434 global->variable_count = 1;
436 global->init = abc_initscript(global->file, 0);
437 code_t*c = global->init->method->body->code;
439 c = abc_getlocal_0(c);
440 c = abc_pushscope(c);
442 /* findpropstrict doesn't just return a scope object- it
443 also makes it "active" somehow. Push local_0 on the
444 scope stack and read it back with findpropstrict, it'll
445 contain properties like "trace". Trying to find the same
446 property on a "vanilla" local_0 yields only a "undefined" */
447 //c = abc_findpropstrict(c, "[package]::trace");
449 /*c = abc_getlocal_0(c);
450 c = abc_findpropstrict(c, "[package]::trace");
452 c = abc_setlocal_1(c);
454 c = abc_pushbyte(c, 0);
455 c = abc_setlocal_2(c);
457 code_t*xx = c = abc_label(c);
458 c = abc_findpropstrict(c, "[package]::trace");
459 c = abc_pushstring(c, "prop:");
460 c = abc_hasnext2(c, 1, 2);
462 c = abc_setlocal_3(c);
463 c = abc_callpropvoid(c, "[package]::trace", 2);
464 c = abc_getlocal_3(c);
466 c = abc_iftrue(c,xx);*/
468 c = abc_findpropstrict(c, "[package]::trace");
469 c = abc_pushstring(c, "[entering global init function]");
470 c = abc_callpropvoid(c, "[package]::trace", 1);
472 global->init->method->body->code = c;
474 void* finalize_state()
476 if(state->level!=1) {
477 syntaxerror("unexpected end of file");
479 abc_method_body_t*m = global->init->method->body;
482 __ findpropstrict(m, "[package]::trace");
483 __ pushstring(m, "[leaving global init function]");
484 __ callpropvoid(m, "[package]::trace", 1);
487 state_destroy(state);state=0;
493 typedef struct _variable {
499 static variable_t* find_variable(char*name)
505 v = dict_lookup(s->vars, name);
513 static variable_t* find_variable_safe(char*name)
515 variable_t* v = find_variable(name);
517 syntaxerror("undefined variable: %s", name);
520 static char variable_exists(char*name)
522 return dict_lookup(state->vars, name)!=0;
524 code_t*defaultvalue(code_t*c, classinfo_t*type);
525 static int new_variable(char*name, classinfo_t*type, char init)
528 v->index = global->variable_count;
532 dict_put(state->vars, name, v);
534 return global->variable_count++;
536 #define TEMPVARNAME "__as3_temp__"
537 static int gettempvar()
539 variable_t*v = find_variable(TEMPVARNAME);
542 return new_variable(TEMPVARNAME, 0, 0);
545 code_t* var_block(code_t*body)
551 for(t=0;t<state->vars->hashsize;t++) {
552 dictentry_t*e = state->vars->slots[t];
554 variable_t*v = (variable_t*)e->data;
555 if(v->type && v->init) {
556 c = defaultvalue(c, v->type);
557 c = abc_setlocal(c, v->index);
558 k = abc_kill(k, v->index);
568 if(x->opcode== OPCODE___BREAK__ ||
569 x->opcode== OPCODE___CONTINUE__) {
570 /* link kill code before break/continue */
571 code_t*e = code_dup(k);
572 code_t*s = code_start(e);
584 c = code_append(c, body);
585 c = code_append(c, k);
589 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
591 c = code_append(c, header);
592 c = code_append(c, var_block(body));
593 /* append return if necessary */
594 if(!c || c->opcode != OPCODE_RETURNVOID &&
595 c->opcode != OPCODE_RETURNVALUE) {
596 c = abc_returnvoid(c);
602 static void startpackage(char*name)
605 /*printf("entering package \"%s\"\n", name);*/
606 state->package = strdup(name);
607 global->variable_count = 1;
609 static void endpackage()
611 /*printf("leaving package \"%s\"\n", state->package);*/
613 //used e.g. in classinfo_register:
614 //free(state->package);state->package=0;
620 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
623 syntaxerror("inner classes now allowed");
626 global->variable_count = 1;
627 state->cls = rfx_calloc(sizeof(classstate_t));
630 classinfo_list_t*mlist=0;
631 /*printf("entering class %s\n", name);
632 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
634 printf(" extends: %s.%s\n", extends->package, extends->name);
635 printf(" implements (%d): ", list_length(implements));
636 for(mlist=implements;mlist;mlist=mlist->next) {
637 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
642 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
643 syntaxerror("invalid modifier(s)");
645 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
646 syntaxerror("public and internal not supported at the same time.");
648 /* create the class name, together with the proper attributes */
652 if(!(flags&FLAG_PUBLIC) && !state->package) {
653 access = ACCESS_PRIVATE; package = current_filename;
654 } else if(!(flags&FLAG_PUBLIC) && state->package) {
655 access = ACCESS_PACKAGEINTERNAL; package = state->package;
656 } else if(state->package) {
657 access = ACCESS_PACKAGE; package = state->package;
659 syntaxerror("public classes only allowed inside a package");
662 if(registry_findclass(package, classname)) {
663 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
667 /* build info struct */
668 int num_interfaces = (list_length(implements));
669 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
670 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
672 classinfo_list_t*l = implements;
673 for(l=implements;l;l=l->next) {
674 state->cls->info->interfaces[pos++] = l->classinfo;
677 multiname_t*extends2 = sig2mname(extends);
679 MULTINAME(classname2,state->cls->info);
682 state->cls_init = abc_getlocal_0(state->cls_init);
683 state->cls_init = abc_constructsuper(state->cls_init, 0);
686 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
687 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
688 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
690 state->cls->info->flags |= CLASS_INTERFACE;
691 abc_class_interface(state->cls->abc);
694 abc_class_protectedNS(state->cls->abc, classname);
696 for(mlist=implements;mlist;mlist=mlist->next) {
697 MULTINAME(m, mlist->classinfo);
698 abc_class_add_interface(state->cls->abc, &m);
701 /* now write the construction code for this class */
702 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
704 abc_method_body_t*m = global->init->method->body;
705 __ getglobalscope(m);
706 classinfo_t*s = extends;
711 //TODO: take a look at the current scope stack, maybe
712 // we can re-use something
717 multiname_t*s2 = sig2mname(s);
719 multiname_destroy(s2);
721 __ pushscope(m); count++;
722 m->code = m->code->prev->prev; // invert
724 /* continue appending after last op end */
725 while(m->code && m->code->next) m->code = m->code->next;
727 /* TODO: if this is one of *our* classes, we can also
728 do a getglobalscope/getslot <nr> (which references
729 the init function's slots) */
731 __ getlex2(m, extends2);
733 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
734 stack is not the superclass */
735 __ pushscope(m);count++;
738 /* notice: we get a verify error #1107 if the top element on the scope
739 stack is not the global object */
741 __ pushscope(m);count++;
743 __ newclass(m,state->cls->abc);
747 __ setslot(m, slotindex);
749 /* flash.display.MovieClip handling */
750 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
751 if(state->package && state->package[0]) {
752 globalclass = concat3(state->package, ".", classname);
754 globalclass = strdup(classname);
757 multiname_destroy(extends2);
760 static void endclass()
762 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
764 c = abc_getlocal_0(c);
765 c = abc_constructsuper(c, 0);
766 state->cls->init = code_append(state->cls->init, c);
769 if(state->cls->init) {
770 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
771 m->body->code = wrap_function(0, state->cls->init, m->body->code);
773 if(state->cls->static_init) {
774 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
775 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
777 // handy for scope testing
781 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
784 free(state->cls);state->cls=0;
788 void check_code_for_break(code_t*c)
791 if(c->opcode == OPCODE___BREAK__) {
792 char*name = string_cstr(c->data[0]);
793 syntaxerror("Unresolved \"break %s\"", name);
795 if(c->opcode == OPCODE___CONTINUE__) {
796 char*name = string_cstr(c->data[0]);
797 syntaxerror("Unresolved \"continue %s\"", name);
804 static void check_constant_against_type(classinfo_t*t, constant_t*c)
806 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
807 if(TYPE_IS_NUMBER(t)) {
808 xassert(c->type == CONSTANT_FLOAT
809 || c->type == CONSTANT_INT
810 || c->type == CONSTANT_UINT);
811 } else if(TYPE_IS_UINT(t)) {
812 xassert(c->type == CONSTANT_UINT ||
813 (c->type == CONSTANT_INT && c->i>0));
814 } else if(TYPE_IS_INT(t)) {
815 xassert(c->type == CONSTANT_INT);
816 } else if(TYPE_IS_BOOLEAN(t)) {
817 xassert(c->type == CONSTANT_TRUE
818 || c->type == CONSTANT_FALSE);
823 static int flags2access(int flags)
826 if(flags&FLAG_PUBLIC) {
827 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
828 syntaxerror("invalid combination of access levels");
829 access = ACCESS_PACKAGE;
830 } else if(flags&FLAG_PRIVATE) {
831 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
832 syntaxerror("invalid combination of access levels");
833 access = ACCESS_PRIVATE;
834 } else if(flags&FLAG_PROTECTED) {
835 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
836 syntaxerror("invalid combination of access levels");
837 access = ACCESS_PROTECTED;
839 access = ACCESS_PACKAGEINTERNAL;
845 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
847 memberinfo_t*minfo = 0;
850 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
851 minfo->return_type = return_type;
852 } else if(getset != KW_GET && getset != KW_SET) {
854 if((minfo = registry_findmember(state->cls->info, name, 0))) {
855 if(minfo->parent == state->cls->info) {
856 syntaxerror("class already contains a member/method called '%s'", name);
857 } else if(!minfo->parent) {
858 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
860 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
861 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
864 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
865 minfo->return_type = return_type;
866 // getslot on a member slot only returns "undefined", so no need
867 // to actually store these
868 //state->minfo->slot = state->method->abc->method->trait->slot_id;
870 //class getter/setter
871 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
875 else if(params->list)
876 type = params->list->param->type;
877 // not sure wether to look into superclasses here, too
878 if((minfo=registry_findmember(state->cls->info, name, 0))) {
879 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
880 syntaxerror("class already contains a member or method called '%s'", name);
882 syntaxerror("getter/setter for '%s' already defined", name);
883 /* make a setter or getter into a getset */
888 if(type && minfo->type != type)
889 syntaxerror("different type in getter and setter");
891 minfo = memberinfo_register(state->cls->info, name, gs);
894 /* can't assign a slot as getter and setter might have different slots */
895 //minfo->slot = slot;
897 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
898 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
899 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
900 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
901 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
902 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
906 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
907 params_t*params, classinfo_t*return_type)
910 syntaxerror("not able to start another method scope");
913 global->variable_count = 0;
914 state->method = rfx_calloc(sizeof(methodstate_t));
915 state->method->has_super = 0;
918 state->method->is_constructor = !strcmp(state->cls->info->name,name);
919 state->cls->has_constructor |= state->method->is_constructor;
921 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
923 state->method->is_global = 1;
924 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
926 new_variable("globalscope", 0, 0);
929 /* state->vars is initialized by state_new */
932 for(p=params->list;p;p=p->next) {
933 new_variable(p->param->name, p->param->type, 0);
935 if(state->method->is_constructor)
936 name = "__as3_constructor__";
937 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
940 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
941 params_t*params, classinfo_t*return_type, code_t*body)
945 multiname_t*type2 = sig2mname(return_type);
947 if(state->method->is_constructor) {
948 f = abc_class_getconstructor(state->cls->abc, type2);
949 } else if(!state->method->is_global) {
950 namespace_t mname_ns = flags2namespace(flags, "");
951 multiname_t mname = {QNAME, &mname_ns, 0, name};
953 if(flags&FLAG_STATIC)
954 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
956 f = abc_class_method(state->cls->abc, type2, &mname);
957 slot = f->trait->slot_id;
959 namespace_t mname_ns = flags2namespace(flags, state->package);
960 multiname_t mname = {QNAME, &mname_ns, 0, name};
962 f = abc_method_new(global->file, type2, 1);
963 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
964 //abc_code_t*c = global->init->method->body->code;
966 //flash doesn't seem to allow us to access function slots
967 //state->method->info->slot = slot;
969 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
970 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
971 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
972 if(params->varargs) f->flags |= METHOD_NEED_REST;
976 for(p=params->list;p;p=p->next) {
977 if(params->varargs && !p->next) {
978 break; //varargs: omit last parameter in function signature
980 multiname_t*m = sig2mname(p->param->type);
981 list_append(f->parameters, m);
982 if(p->param->value) {
983 check_constant_against_type(p->param->type, p->param->value);
984 opt=1;list_append(f->optional_parameters, p->param->value);
986 syntaxerror("non-optional parameter not allowed after optional parameters");
989 check_code_for_break(body);
992 f->body->code = body;
993 f->body->exceptions = state->method->exceptions;
996 syntaxerror("interface methods can't have a method body");
999 free(state->method);state->method=0;
1005 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1010 void breakjumpsto(code_t*c, char*name, code_t*jump)
1013 if(c->opcode == OPCODE___BREAK__) {
1014 string_t*name2 = c->data[0];
1015 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1016 c->opcode = OPCODE_JUMP;
1023 void continuejumpsto(code_t*c, char*name, code_t*jump)
1026 if(c->opcode == OPCODE___CONTINUE__) {
1027 string_t*name2 = c->data[0];
1028 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1029 c->opcode = OPCODE_JUMP;
1037 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1038 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1039 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1041 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1043 if(!type1 || !type2)
1044 return registry_getanytype();
1045 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1046 return registry_getanytype();
1049 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1058 return registry_getanytype();
1060 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1065 return abc_coerce_a(c);
1069 // cast an "any" type to a specific type. subject to
1070 // runtime exceptions
1071 return abc_coerce2(c, &m);
1074 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1075 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1076 // allow conversion between number types
1077 return abc_coerce2(c, &m);
1079 //printf("%s.%s\n", from.package, from.name);
1080 //printf("%s.%s\n", to.package, to.name);
1082 classinfo_t*supertype = from;
1084 if(supertype == to) {
1085 // target type is one of from's superclasses
1086 return abc_coerce2(c, &m);
1089 while(supertype->interfaces[t]) {
1090 if(supertype->interfaces[t]==to) {
1091 // target type is one of from's interfaces
1092 return abc_coerce2(c, &m);
1096 supertype = supertype->superclass;
1098 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1100 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1102 syntaxerror("can't convert type %s to %s", from->name, to->name);
1105 code_t*defaultvalue(code_t*c, classinfo_t*type)
1107 if(TYPE_IS_INT(type)) {
1108 c = abc_pushbyte(c, 0);
1109 } else if(TYPE_IS_UINT(type)) {
1110 c = abc_pushuint(c, 0);
1111 } else if(TYPE_IS_FLOAT(type)) {
1113 } else if(TYPE_IS_BOOLEAN(type)) {
1114 c = abc_pushfalse(c);
1116 //c = abc_pushundefined(c);
1118 c = abc_pushnull(c);
1120 c = abc_coerce2(c, &m);
1125 char is_pushundefined(code_t*c)
1127 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1130 void parserassert(int b)
1132 if(!b) syntaxerror("internal error: assertion failed");
1135 static classinfo_t* find_class(char*name)
1139 c = registry_findclass(state->package, name);
1142 /* try explicit imports */
1143 dictentry_t* e = dict_get_slot(state->imports, name);
1146 if(!strcmp(e->key, name)) {
1147 c = (classinfo_t*)e->data;
1153 /* try package.* imports */
1154 import_list_t*l = state->wildcard_imports;
1156 //printf("does package %s contain a class %s?\n", l->import->package, name);
1157 c = registry_findclass(l->import->package, name);
1162 /* try global package */
1163 c = registry_findclass("", name);
1166 /* try local "filename" package */
1167 c = registry_findclass(current_filename, name);
1173 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1177 [prefix code] [read instruction]
1181 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1184 if(in && in->opcode == OPCODE_COERCE_A) {
1185 in = code_cutlast(in);
1188 syntaxerror("internal error");
1190 /* chop off read instruction */
1194 prefix = r->prev;r->prev = 0;
1200 char use_temp_var = readbefore;
1202 /* generate the write instruction, and maybe append a dup to the prefix code */
1203 code_t* write = abc_nop(0);
1204 if(r->opcode == OPCODE_GETPROPERTY) {
1205 write->opcode = OPCODE_SETPROPERTY;
1206 multiname_t*m = (multiname_t*)r->data[0];
1207 write->data[0] = multiname_clone(m);
1208 if(m->type == QNAME || m->type == MULTINAME) {
1210 prefix = abc_dup(prefix); // we need the object, too
1213 } else if(m->type == MULTINAMEL) {
1215 /* dupping two values on the stack requires 5 operations and one register-
1216 couldn't adobe just have given us a dup2? */
1217 int temp = gettempvar();
1218 prefix = abc_setlocal(prefix, temp);
1219 prefix = abc_dup(prefix);
1220 prefix = abc_getlocal(prefix, temp);
1221 prefix = abc_swap(prefix);
1222 prefix = abc_getlocal(prefix, temp);
1224 prefix = abc_kill(prefix, temp);
1228 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1230 } else if(r->opcode == OPCODE_GETSLOT) {
1231 write->opcode = OPCODE_SETSLOT;
1232 write->data[0] = r->data[0];
1234 prefix = abc_dup(prefix); // we need the object, too
1237 } else if(r->opcode == OPCODE_GETLOCAL) {
1238 write->opcode = OPCODE_SETLOCAL;
1239 write->data[0] = r->data[0];
1240 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1241 write->opcode = OPCODE_SETLOCAL_0;
1242 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1243 write->opcode = OPCODE_SETLOCAL_1;
1244 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1245 write->opcode = OPCODE_SETLOCAL_2;
1246 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1247 write->opcode = OPCODE_SETLOCAL_3;
1249 code_dump(r, 0, 0, "", stdout);
1250 syntaxerror("illegal lvalue: can't assign a value to this expression");
1257 /* with getproperty/getslot, we have to be extra careful not
1258 to execute the read code twice, as it might have side-effects
1259 (e.g. if the property is in fact a setter/getter combination)
1261 So read the value, modify it, and write it again,
1262 using prefix only once and making sure (by using a temporary
1263 register) that the return value is what we just wrote */
1264 temp = gettempvar();
1265 c = code_append(c, prefix);
1266 c = code_append(c, r);
1269 c = abc_setlocal(c, temp);
1271 c = code_append(c, middlepart);
1274 c = abc_setlocal(c, temp);
1276 c = code_append(c, write);
1277 c = abc_getlocal(c, temp);
1278 c = abc_kill(c, temp);
1280 /* if we're allowed to execute the read code twice *and*
1281 the middlepart doesn't modify the code, things are easier.
1283 code_t* r2 = code_dup(r);
1284 //c = code_append(c, prefix);
1285 parserassert(!prefix);
1286 c = code_append(c, r);
1287 c = code_append(c, middlepart);
1288 c = code_append(c, write);
1289 c = code_append(c, r2);
1292 /* even smaller version: overwrite the value without reading
1296 c = code_append(c, prefix);
1299 c = code_append(c, middlepart);
1300 c = code_append(c, write);
1301 c = code_append(c, r);
1303 temp = gettempvar();
1305 c = code_append(c, prefix);
1307 c = code_append(c, middlepart);
1309 c = abc_setlocal(c, temp);
1310 c = code_append(c, write);
1311 c = abc_getlocal(c, temp);
1312 c = abc_kill(c, temp);
1325 /* ------------ code blocks / statements ---------------- */
1327 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1329 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1330 PROGRAM_CODE_LIST: PROGRAM_CODE
1331 | PROGRAM_CODE_LIST PROGRAM_CODE
1333 PROGRAM_CODE: PACKAGE_DECLARATION
1334 | INTERFACE_DECLARATION
1336 | FUNCTION_DECLARATION
1341 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1342 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1343 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1345 INPACKAGE_CODE: INTERFACE_DECLARATION
1347 | FUNCTION_DECLARATION
1352 MAYBECODE: CODE {$$=$1;}
1353 MAYBECODE: {$$=code_new();}
1355 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1356 CODE: CODEPIECE {$$=$1;}
1358 // code which also may appear outside a method
1359 CODE_STATEMENT: IMPORT
1360 CODE_STATEMENT: VOIDEXPRESSION
1362 CODE_STATEMENT: FOR_IN
1363 CODE_STATEMENT: WHILE
1364 CODE_STATEMENT: DO_WHILE
1365 CODE_STATEMENT: SWITCH
1367 CODE_STATEMENT: WITH
1370 // code which may appear anywhere
1371 CODEPIECE: ';' {$$=0;}
1372 CODEPIECE: VARIABLE_DECLARATION
1373 CODEPIECE: CODE_STATEMENT
1379 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1380 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1382 CODEBLOCK : '{' CODE '}' {$$=$2;}
1383 CODEBLOCK : '{' '}' {$$=0;}
1384 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1385 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1387 /* ------------ package init code ------------------- */
1389 PACKAGE_INITCODE: CODE_STATEMENT {
1390 if($1) warning("code ignored");
1393 /* ------------ variables --------------------------- */
1395 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1396 | {$$.c=abc_pushundefined(0);
1400 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1401 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1403 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1404 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1406 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1408 if(variable_exists($1))
1409 syntaxerror("Variable %s already defined", $1);
1411 if(!is_subtype_of($3.t, $2)) {
1412 syntaxerror("Can't convert %s to %s", $3.t->name,
1416 int index = new_variable($1, $2, 1);
1419 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1421 $$ = converttype($$, $3.t, $2);
1422 $$ = abc_setlocal($$, index);
1424 $$ = defaultvalue(0, $2);
1425 $$ = abc_setlocal($$, index);
1428 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1430 $$ = abc_coerce_a($$);
1431 $$ = abc_setlocal($$, index);
1437 /* that's the default for a local register, anyway
1439 state->method->initcode = abc_pushundefined(state->method->initcode);
1440 state->method->initcode = abc_setlocal(state->method->initcode, index);
1442 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1445 /* ------------ control flow ------------------------- */
1447 MAYBEELSE: %prec below_else {$$ = code_new();}
1448 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1449 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1451 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1454 $$ = code_append($$, $4.c);
1455 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1457 $$ = code_append($$, $6);
1459 myjmp = $$ = abc_jump($$, 0);
1461 myif->branch = $$ = abc_nop($$);
1463 $$ = code_append($$, $7);
1464 myjmp->branch = $$ = abc_nop($$);
1470 FOR_INIT : {$$=code_new();}
1471 FOR_INIT : VARIABLE_DECLARATION
1472 FOR_INIT : VOIDEXPRESSION
1473 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1474 $$=$2;new_variable($2,$3,1);
1476 FOR_IN_INIT : T_IDENTIFIER {
1480 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1481 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1483 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1484 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1486 $$ = code_append($$, $2);
1487 code_t*loopstart = $$ = abc_label($$);
1488 $$ = code_append($$, $4.c);
1489 code_t*myif = $$ = abc_iffalse($$, 0);
1490 $$ = code_append($$, $8);
1491 code_t*cont = $$ = abc_nop($$);
1492 $$ = code_append($$, $6);
1493 $$ = abc_jump($$, loopstart);
1494 code_t*out = $$ = abc_nop($$);
1495 breakjumpsto($$, $1.name, out);
1496 continuejumpsto($$, $1.name, cont);
1503 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1504 variable_t*var = find_variable($2);
1505 char*tmp1name = concat2($2, "__tmp1__");
1506 int it = new_variable(tmp1name, TYPE_INT, 0);
1507 char*tmp2name = concat2($2, "__array__");
1508 int array = new_variable(tmp1name, 0, 0);
1511 $$ = code_append($$, $4.c);
1512 $$ = abc_coerce_a($$);
1513 $$ = abc_setlocal($$, array);
1514 $$ = abc_pushbyte($$, 0);
1515 $$ = abc_setlocal($$, it);
1517 code_t*loopstart = $$ = abc_label($$);
1519 $$ = abc_hasnext2($$, array, it);
1520 code_t*myif = $$ = abc_iffalse($$, 0);
1521 $$ = abc_getlocal($$, array);
1522 $$ = abc_getlocal($$, it);
1524 $$ = abc_nextname($$);
1526 $$ = abc_nextvalue($$);
1527 $$ = converttype($$, 0, var->type);
1528 $$ = abc_setlocal($$, var->index);
1530 $$ = code_append($$, $6);
1531 $$ = abc_jump($$, loopstart);
1533 code_t*out = $$ = abc_nop($$);
1534 breakjumpsto($$, $1.name, out);
1535 continuejumpsto($$, $1.name, loopstart);
1546 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1550 code_t*myjmp = $$ = abc_jump($$, 0);
1551 code_t*loopstart = $$ = abc_label($$);
1552 $$ = code_append($$, $6);
1553 code_t*cont = $$ = abc_nop($$);
1554 myjmp->branch = cont;
1555 $$ = code_append($$, $4.c);
1556 $$ = abc_iftrue($$, loopstart);
1557 code_t*out = $$ = abc_nop($$);
1558 breakjumpsto($$, $1, out);
1559 continuejumpsto($$, $1, cont);
1565 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1567 code_t*loopstart = $$ = abc_label($$);
1568 $$ = code_append($$, $3);
1569 code_t*cont = $$ = abc_nop($$);
1570 $$ = code_append($$, $6.c);
1571 $$ = abc_iftrue($$, loopstart);
1572 code_t*out = $$ = abc_nop($$);
1573 breakjumpsto($$, $1, out);
1574 continuejumpsto($$, $1, cont);
1580 BREAK : "break" %prec prec_none {
1581 $$ = abc___break__(0, "");
1583 BREAK : "break" T_IDENTIFIER {
1584 $$ = abc___break__(0, $2);
1586 CONTINUE : "continue" %prec prec_none {
1587 $$ = abc___continue__(0, "");
1589 CONTINUE : "continue" T_IDENTIFIER {
1590 $$ = abc___continue__(0, $2);
1593 MAYBE_CASE_LIST : {$$=0;}
1594 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1595 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1596 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1597 CASE_LIST: CASE {$$=$1}
1598 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1600 CASE: "case" E ':' MAYBECODE {
1602 $$ = code_append($$, $2.c);
1603 code_t*j = $$ = abc_ifne($$, 0);
1604 $$ = code_append($$, $4);
1605 if($$->opcode != OPCODE___BREAK__) {
1606 $$ = abc___fallthrough__($$, "");
1608 code_t*e = $$ = abc_nop($$);
1611 DEFAULT: "default" ':' MAYBECODE {
1614 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1616 $$ = code_append($$, $7);
1617 code_t*out = $$ = abc_pop($$);
1618 breakjumpsto($$, $1, out);
1620 code_t*c = $$,*lastblock=0;
1622 if(c->opcode == OPCODE_IFNE) {
1623 if(!c->next) syntaxerror("internal error in fallthrough handling");
1625 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1627 c->opcode = OPCODE_JUMP;
1628 c->branch = lastblock;
1630 /* fall through end of switch */
1631 c->opcode = OPCODE_NOP;
1641 /* ------------ try / catch /finally ---------------- */
1643 FINALLY: "finally" '{' CODE '}'
1644 MAYBE_FINALLY: | FINALLY
1646 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1648 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1649 multiname_t name = {QNAME, &name_ns, 0, $3};
1651 NEW(abc_exception_t, e)
1652 e->exc_type = sig2mname($4);
1653 e->var_name = multiname_clone(&name);
1657 int i = find_variable_safe($3)->index;
1658 e->target = c = abc_setlocal(0, i);
1659 c = code_append(c, $8);
1667 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1668 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1670 TRY : "try" '{' {new_state();} CODE '}' CATCH_LIST MAYBE_FINALLY {
1671 code_t*start = code_start($4);
1674 code_t*out = abc_nop(0);
1675 code_t*jmp = $$ = abc_jump($$, out);
1677 abc_exception_list_t*l = $6;
1679 abc_exception_t*e = l->abc_exception;
1682 $$ = code_append($$, e->target);
1683 $$ = abc_jump($$, out);
1686 $$ = code_append($$, out);
1689 list_concat(state->method->exceptions, $6);
1695 /* ------------ throw ------------------------------- */
1697 THROW : "throw" EXPRESSION {
1701 THROW : "throw" %prec prec_none {
1702 if(!state->exception_name)
1703 syntaxerror("re-throw only possible within a catch block");
1704 variable_t*v = find_variable(state->exception_name);
1706 $$=abc_getlocal($$, v->index);
1710 /* ------------ with -------------------------------- */
1712 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1714 $$ = abc_pushscope($$);
1715 $$ = code_append($$, $5);
1716 $$ = abc_popscope($$);
1719 /* ------------ packages and imports ---------------- */
1721 X_IDENTIFIER: T_IDENTIFIER
1722 | "package" {$$="package";}
1724 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1725 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1727 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1728 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1730 IMPORT : "import" QNAME {
1733 syntaxerror("Couldn't import class\n");
1734 state_has_imports();
1735 dict_put(state->imports, c->name, c);
1738 IMPORT : "import" PACKAGE '.' '*' {
1741 state_has_imports();
1742 list_append(state->wildcard_imports, i);
1746 /* ------------ classes and interfaces (header) -------------- */
1748 MAYBE_MODIFIERS : {$$=0;}
1749 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1750 MODIFIER_LIST : MODIFIER {$$=$1;}
1751 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1753 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1754 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1755 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1756 | KW_STATIC {$$=FLAG_STATIC;}
1757 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1758 | KW_FINAL {$$=FLAG_FINAL;}
1759 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1760 | KW_NATIVE {$$=FLAG_NATIVE;}
1761 | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1763 EXTENDS : {$$=registry_getobjectclass();}
1764 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1766 EXTENDS_LIST : {$$=list_new();}
1767 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1769 IMPLEMENTS_LIST : {$$=list_new();}
1770 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1772 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1773 EXTENDS IMPLEMENTS_LIST
1774 '{' {startclass($1,$3,$4,$5, 0);}
1776 '}' {endclass();$$=0;}
1778 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1780 '{' {startclass($1,$3,0,$4,1);}
1781 MAYBE_INTERFACE_BODY
1782 '}' {endclass();$$=0;}
1784 /* ------------ classes and interfaces (body) -------------- */
1787 MAYBE_CLASS_BODY : CLASS_BODY
1788 CLASS_BODY : CLASS_BODY_ITEM
1789 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1790 CLASS_BODY_ITEM : ';'
1791 CLASS_BODY_ITEM : SLOT_DECLARATION
1792 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1794 CLASS_BODY_ITEM : CODE_STATEMENT {
1795 code_t*c = state->cls->static_init;
1796 c = code_append(c, $1);
1797 state->cls->static_init = c;
1800 MAYBE_INTERFACE_BODY :
1801 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1802 INTERFACE_BODY : IDECLARATION
1803 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1805 IDECLARATION : "var" T_IDENTIFIER {
1806 syntaxerror("variable declarations not allowed in interfaces");
1808 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1810 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
1811 syntaxerror("invalid method modifiers: interface methods always need to be public");
1813 startfunction(0,$1,$3,$4,&$6,$8);
1814 endfunction(0,$1,$3,$4,&$6,$8, 0);
1817 /* ------------ classes and interfaces (body, slots ) ------- */
1819 VARCONST: "var" | "const"
1821 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1823 memberinfo_t* info = state->cls?
1824 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1825 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1828 info->flags = flags;
1831 namespace_t mname_ns = {flags2access(flags), ""};
1832 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1834 trait_list_t**traits;
1838 traits = &global->init->traits;
1839 code = &global->init->method->body->code;
1840 } else if(flags&FLAG_STATIC) {
1842 traits = &state->cls->abc->static_traits;
1843 code = &state->cls->static_init;
1845 // instance variable
1846 traits = &state->cls->abc->traits;
1847 code = &state->cls->init;
1853 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1855 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1857 info->slot = t->slot_id;
1859 /* initalization code (if needed) */
1861 if($5.c && !is_pushundefined($5.c)) {
1862 c = abc_getlocal_0(c);
1863 c = code_append(c, $5.c);
1864 c = converttype(c, $5.t, $4);
1865 c = abc_setslot(c, t->slot_id);
1868 *code = code_append(*code, c);
1871 t->kind= TRAIT_CONST;
1877 /* ------------ constants -------------------------------------- */
1879 MAYBESTATICCONSTANT: {$$=0;}
1880 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1882 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1883 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1884 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1885 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1886 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1887 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1888 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1889 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1890 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1892 /* ------------ classes and interfaces (body, functions) ------- */
1894 // non-vararg version
1896 memset(&$$,0,sizeof($$));
1898 MAYBE_PARAM_LIST: PARAM_LIST {
1903 MAYBE_PARAM_LIST: "..." PARAM {
1904 memset(&$$,0,sizeof($$));
1906 list_append($$.list, $2);
1908 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1911 list_append($$.list, $4);
1915 PARAM_LIST: PARAM_LIST ',' PARAM {
1917 list_append($$.list, $3);
1920 memset(&$$,0,sizeof($$));
1921 list_append($$.list, $1);
1924 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1925 $$ = malloc(sizeof(param_t));
1930 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1931 $$ = malloc(sizeof(param_t));
1933 $$->type = TYPE_ANY;
1936 GETSET : "get" {$$=$1;}
1940 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1941 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1944 if(state->method->late_binding) {
1945 c = abc_getlocal_0(c);
1946 c = abc_pushscope(c);
1948 if(state->method->is_constructor && !state->method->has_super) {
1949 // call default constructor
1950 c = abc_getlocal_0(c);
1951 c = abc_constructsuper(c, 0);
1953 c = wrap_function(c, 0, $11);
1954 endfunction(0,$1,$3,$4,&$6,$8,c);
1958 /* ------------- package + class ids --------------- */
1960 CLASS: T_IDENTIFIER {
1962 /* try current package */
1963 $$ = find_class($1);
1964 if(!$$) syntaxerror("Could not find class %s\n", $1);
1967 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1968 $$ = registry_findclass($1, $3);
1969 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1973 QNAME: PACKAGEANDCLASS
1976 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1977 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1979 TYPE : QNAME {$$=$1;}
1980 | '*' {$$=registry_getanytype();}
1981 | "void" {$$=registry_getanytype();}
1983 | "String" {$$=registry_getstringclass();}
1984 | "int" {$$=registry_getintclass();}
1985 | "uint" {$$=registry_getuintclass();}
1986 | "Boolean" {$$=registry_getbooleanclass();}
1987 | "Number" {$$=registry_getnumberclass();}
1990 MAYBETYPE: ':' TYPE {$$=$2;}
1993 /* ----------function calls, delete, constructor calls ------ */
1995 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
1996 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1998 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1999 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2000 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2003 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2005 $$.cc = code_append($1.cc, $3.c);
2008 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2013 $$.c = abc_getglobalscope($$.c);
2014 $$.c = abc_getslot($$.c, $2->slot);
2016 $$.c = abc_findpropstrict2($$.c, &m);
2019 $$.c = code_append($$.c, $3.cc);
2022 $$.c = abc_construct($$.c, $3.len);
2024 $$.c = abc_constructprop2($$.c, &m, $3.len);
2028 /* TODO: use abc_call (for calling local variables),
2029 abc_callstatic (for calling own methods)
2032 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2035 if($$.c->opcode == OPCODE_COERCE_A) {
2036 $$.c = code_cutlast($$.c);
2038 code_t*paramcode = $3.cc;
2041 if($$.c->opcode == OPCODE_GETPROPERTY) {
2042 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2043 $$.c = code_cutlast($$.c);
2044 $$.c = code_append($$.c, paramcode);
2045 $$.c = abc_callproperty2($$.c, name, $3.len);
2046 multiname_destroy(name);
2047 } else if($$.c->opcode == OPCODE_GETSLOT) {
2048 int slot = (int)(ptroff_t)$$.c->data[0];
2049 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2050 if(t->kind!=TRAIT_METHOD) {
2051 //ok: flash allows to assign closures to members.
2053 multiname_t*name = t->name;
2054 $$.c = code_cutlast($$.c);
2055 $$.c = code_append($$.c, paramcode);
2056 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2057 $$.c = abc_callproperty2($$.c, name, $3.len);
2058 } else if($$.c->opcode == OPCODE_GETSUPER) {
2059 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2060 $$.c = code_cutlast($$.c);
2061 $$.c = code_append($$.c, paramcode);
2062 $$.c = abc_callsuper2($$.c, name, $3.len);
2063 multiname_destroy(name);
2065 $$.c = abc_getlocal_0($$.c);
2066 $$.c = code_append($$.c, paramcode);
2067 $$.c = abc_call($$.c, $3.len);
2072 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2073 $$.t = $1.t->function->return_type;
2075 $$.c = abc_coerce_a($$.c);
2080 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2081 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2082 if(!state->method) syntaxerror("super() not allowed outside of a function");
2083 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2086 $$.c = abc_getlocal_0($$.c);
2088 $$.c = code_append($$.c, $3.cc);
2090 this is dependent on the control path, check this somewhere else
2091 if(state->method->has_super)
2092 syntaxerror("constructor may call super() only once");
2094 state->method->has_super = 1;
2095 $$.c = abc_constructsuper($$.c, $3.len);
2096 $$.c = abc_pushundefined($$.c);
2100 DELETE: "delete" E {
2102 if($$.c->opcode == OPCODE_COERCE_A) {
2103 $$.c = code_cutlast($$.c);
2105 multiname_t*name = 0;
2106 if($$.c->opcode == OPCODE_GETPROPERTY) {
2107 $$.c->opcode = OPCODE_DELETEPROPERTY;
2108 } else if($$.c->opcode == OPCODE_GETSLOT) {
2109 int slot = (int)(ptroff_t)$$.c->data[0];
2110 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2111 $$.c = code_cutlast($$.c);
2112 $$.c = abc_deleteproperty2($$.c, name);
2114 $$.c = abc_getlocal_0($$.c);
2115 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2116 $$.c = abc_deleteproperty2($$.c, &m);
2118 $$.t = TYPE_BOOLEAN;
2121 RETURN: "return" %prec prec_none {
2122 $$ = abc_returnvoid(0);
2124 RETURN: "return" EXPRESSION {
2126 $$ = abc_returnvalue($$);
2129 // ----------------------- expression types -------------------------------------
2131 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2132 EXPRESSION : E %prec below_minus {$$ = $1;}
2133 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2135 $$.c = cut_last_push($$.c);
2136 $$.c = code_append($$.c,$3.c);
2139 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2140 $$=cut_last_push($1.c);
2143 // ----------------------- expression evaluation -------------------------------------
2145 //V : CONSTANT {$$ = 0;}
2147 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2148 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2149 //V : NEW {$$ = $1.c;}
2151 //V : DELETE {$$ = $1.c;}
2152 E : DELETE {$$ = $1;}
2156 namespace_t ns = {ACCESS_PACKAGE, ""};
2157 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2159 $$.c = abc_getlex2($$.c, &m);
2160 $$.c = abc_pushstring($$.c, $1.pattern);
2161 $$.c = abc_construct($$.c, 1);
2163 $$.c = abc_getlex2($$.c, &m);
2164 $$.c = abc_pushstring($$.c, $1.pattern);
2165 $$.c = abc_pushstring($$.c, $1.options);
2166 $$.c = abc_construct($$.c, 2);
2171 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2172 //MULTINAME(m, registry_getintclass());
2173 //$$.c = abc_coerce2($$.c, &m); // FIXME
2176 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2179 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2182 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2185 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2188 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2191 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2194 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2195 $$.t = TYPE_BOOLEAN;
2197 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2198 $$.t = TYPE_BOOLEAN;
2200 CONSTANT : "null" {$$.c = abc_pushnull(0);
2205 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2206 $$.t = TYPE_BOOLEAN;
2208 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2209 $$.t = TYPE_BOOLEAN;
2211 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2212 $$.t = TYPE_BOOLEAN;
2214 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2215 $$.t = TYPE_BOOLEAN;
2217 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2218 $$.t = TYPE_BOOLEAN;
2220 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2221 $$.t = TYPE_BOOLEAN;
2223 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2224 $$.t = TYPE_BOOLEAN;
2226 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2227 $$.t = TYPE_BOOLEAN;
2230 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2232 $$.c = converttype($$.c, $1.t, $$.t);
2233 $$.c = abc_dup($$.c);
2234 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2235 $$.c = cut_last_push($$.c);
2236 $$.c = code_append($$.c,$3.c);
2237 $$.c = converttype($$.c, $3.t, $$.t);
2238 code_t*label = $$.c = abc_label($$.c);
2239 jmp->branch = label;
2242 $$.t = join_types($1.t, $3.t, 'A');
2243 /*printf("%08x:\n",$1.t);
2244 code_dump($1.c, 0, 0, "", stdout);
2245 printf("%08x:\n",$3.t);
2246 code_dump($3.c, 0, 0, "", stdout);
2247 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2249 $$.c = converttype($$.c, $1.t, $$.t);
2250 $$.c = abc_dup($$.c);
2251 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2252 $$.c = cut_last_push($$.c);
2253 $$.c = code_append($$.c,$3.c);
2254 $$.c = converttype($$.c, $3.t, $$.t);
2255 code_t*label = $$.c = abc_label($$.c);
2256 jmp->branch = label;
2259 E : '!' E {$$.c=$2.c;
2260 $$.c = abc_not($$.c);
2261 $$.t = TYPE_BOOLEAN;
2264 E : '~' E {$$.c=$2.c;
2265 $$.c = abc_bitnot($$.c);
2269 E : E '&' E {$$.c = code_append($1.c,$3.c);
2270 $$.c = abc_bitand($$.c);
2274 E : E '^' E {$$.c = code_append($1.c,$3.c);
2275 $$.c = abc_bitxor($$.c);
2279 E : E '|' E {$$.c = code_append($1.c,$3.c);
2280 $$.c = abc_bitor($$.c);
2284 E : E '-' E {$$.c = code_append($1.c,$3.c);
2285 if(BOTH_INT($1.t,$3.t)) {
2286 $$.c = abc_subtract_i($$.c);
2289 $$.c = abc_subtract($$.c);
2293 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2294 $$.c = abc_rshift($$.c);
2297 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2298 $$.c = abc_urshift($$.c);
2301 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2302 $$.c = abc_lshift($$.c);
2306 E : E '/' E {$$.c = code_append($1.c,$3.c);
2307 $$.c = abc_divide($$.c);
2310 E : E '%' E {$$.c = code_append($1.c,$3.c);
2311 $$.c = abc_modulo($$.c);
2314 E : E '+' E {$$.c = code_append($1.c,$3.c);
2315 if(BOTH_INT($1.t, $3.t)) {
2316 $$.c = abc_add_i($$.c);
2319 $$.c = abc_add($$.c);
2320 $$.t = join_types($1.t,$3.t,'+');
2323 E : E '*' E {$$.c = code_append($1.c,$3.c);
2324 if(BOTH_INT($1.t,$3.t)) {
2325 $$.c = abc_multiply_i($$.c);
2328 $$.c = abc_multiply($$.c);
2333 E : E "in" E {$$.c = code_append($1.c,$3.c);
2334 $$.c = abc_in($$.c);
2335 $$.t = TYPE_BOOLEAN;
2338 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2339 if(use_astype && TYPE_IS_CLASS($3.t)) {
2340 MULTINAME(m,$3.t->cls);
2341 $$.c = abc_astype2($1.c, &m);
2344 $$.c = code_append($1.c, $3.c);
2345 $$.c = abc_astypelate($$.c);
2350 E : E "instanceof" E
2351 {$$.c = code_append($1.c, $3.c);
2352 $$.c = abc_instanceof($$.c);
2353 $$.t = TYPE_BOOLEAN;
2356 E : E "is" E {$$.c = code_append($1.c, $3.c);
2357 $$.c = abc_istypelate($$.c);
2358 $$.t = TYPE_BOOLEAN;
2361 E : "typeof" '(' E ')' {
2363 $$.c = abc_typeof($$.c);
2368 $$.c = cut_last_push($2.c);
2369 $$.c = abc_pushundefined($$.c);
2373 E : "void" { $$.c = abc_pushundefined(0);
2377 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2382 $$.c=abc_negate_i($$.c);
2385 $$.c=abc_negate($$.c);
2392 $$.c = code_append($$.c, $3.c);
2394 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2395 $$.c = abc_getproperty2($$.c, &m);
2396 $$.t = 0; // array elements have unknown type
2399 E : '[' MAYBE_EXPRESSION_LIST ']' {
2401 $$.c = code_append($$.c, $2.cc);
2402 $$.c = abc_newarray($$.c, $2.len);
2403 $$.t = registry_getarrayclass();
2406 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2407 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2409 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2411 $$.cc = code_append($$.cc, $1.c);
2412 $$.cc = code_append($$.cc, $3.c);
2415 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2418 $$.cc = code_append($$.cc, $3.c);
2419 $$.cc = code_append($$.cc, $5.c);
2424 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2426 $$.c = code_append($$.c, $2.cc);
2427 $$.c = abc_newobject($$.c, $2.len/2);
2428 $$.t = registry_getobjectclass();
2433 if(BOTH_INT($1.t,$3.t)) {
2434 c=abc_multiply_i(c);
2438 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2439 $$.c = toreadwrite($1.c, c, 0, 0);
2444 code_t*c = abc_modulo($3.c);
2445 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2446 $$.c = toreadwrite($1.c, c, 0, 0);
2450 code_t*c = abc_lshift($3.c);
2451 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2452 $$.c = toreadwrite($1.c, c, 0, 0);
2456 code_t*c = abc_rshift($3.c);
2457 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2458 $$.c = toreadwrite($1.c, c, 0, 0);
2462 code_t*c = abc_urshift($3.c);
2463 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2464 $$.c = toreadwrite($1.c, c, 0, 0);
2468 code_t*c = abc_divide($3.c);
2469 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2470 $$.c = toreadwrite($1.c, c, 0, 0);
2474 code_t*c = abc_bitor($3.c);
2475 c=converttype(c, TYPE_INT, $1.t);
2476 $$.c = toreadwrite($1.c, c, 0, 0);
2481 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2486 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2488 $$.c = toreadwrite($1.c, c, 0, 0);
2491 E : E "-=" E { code_t*c = $3.c;
2492 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2493 c=abc_subtract_i(c);
2497 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2499 $$.c = toreadwrite($1.c, c, 0, 0);
2502 E : E '=' E { code_t*c = 0;
2503 c = code_append(c, $3.c);
2504 c = converttype(c, $3.t, $1.t);
2505 $$.c = toreadwrite($1.c, c, 1, 0);
2509 E : E '?' E ':' E %prec below_assignment {
2511 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2512 $$.c = code_append($$.c, $3.c);
2513 code_t*j2 = $$.c = abc_jump($$.c, 0);
2514 $$.c = j1->branch = abc_label($$.c);
2515 $$.c = code_append($$.c, $5.c);
2516 $$.c = j2->branch = abc_label($$.c);
2517 $$.t = join_types($3.t,$5.t,'?');
2520 // TODO: use inclocal where appropriate
2521 E : E "++" { code_t*c = 0;
2522 classinfo_t*type = $1.t;
2523 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2524 c=abc_increment_i(c);
2530 c=converttype(c, type, $1.t);
2531 $$.c = toreadwrite($1.c, c, 0, 1);
2534 E : E "--" { code_t*c = 0;
2535 classinfo_t*type = $1.t;
2536 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2537 c=abc_decrement_i(c);
2543 c=converttype(c, type, $1.t);
2544 $$.c = toreadwrite($1.c, c, 0, 1);
2548 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2549 classinfo_t*type = $2.t;
2550 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2551 c=abc_increment_i(c);
2557 c=converttype(c, type, $2.t);
2558 $$.c = toreadwrite($2.c, c, 0, 0);
2562 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2563 classinfo_t*type = $2.t;
2564 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2565 c=abc_decrement_i(c);
2571 c=converttype(c, type, $2.t);
2572 $$.c = toreadwrite($2.c, c, 0, 0);
2576 E : "super" '.' T_IDENTIFIER
2577 { if(!state->cls->info)
2578 syntaxerror("super keyword not allowed outside a class");
2579 classinfo_t*t = state->cls->info->superclass;
2580 if(!t) t = TYPE_OBJECT;
2582 memberinfo_t*f = registry_findmember(t, $3, 1);
2583 namespace_t ns = flags2namespace(f->flags, "");
2584 MEMBER_MULTINAME(m, f, $3);
2586 $$.c = abc_getlocal_0($$.c);
2587 $$.c = abc_getsuper2($$.c, &m);
2588 $$.t = memberinfo_gettype(f);
2591 E : E '.' T_IDENTIFIER
2593 classinfo_t*t = $1.t;
2595 if(TYPE_IS_CLASS(t) && t->cls) {
2600 memberinfo_t*f = registry_findmember(t, $3, 1);
2602 if(f && !is_static != !(f->flags&FLAG_STATIC))
2604 if(f && f->slot && !noslot) {
2605 $$.c = abc_getslot($$.c, f->slot);
2607 MEMBER_MULTINAME(m, f, $3);
2608 $$.c = abc_getproperty2($$.c, &m);
2610 /* determine type */
2611 $$.t = memberinfo_gettype(f);
2613 $$.c = abc_coerce_a($$.c);
2615 /* when resolving a property on an unknown type, we do know the
2616 name of the property (and don't seem to need the package), but
2617 we need to make avm2 try out all access modes */
2618 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2619 $$.c = abc_getproperty2($$.c, &m);
2620 $$.c = abc_coerce_a($$.c);
2621 $$.t = registry_getanytype();
2625 VAR_READ : T_IDENTIFIER {
2632 /* look at variables */
2633 if((v = find_variable($1))) {
2634 // $1 is a local variable
2635 $$.c = abc_getlocal($$.c, v->index);
2638 /* look at current class' members */
2639 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2640 // $1 is a function in this class
2641 int var_is_static = (f->flags&FLAG_STATIC);
2642 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2643 if(var_is_static != i_am_static) {
2644 /* there doesn't seem to be any "static" way to access
2645 static properties of a class */
2646 state->method->late_binding = 1;
2648 namespace_t ns = {flags2access(f->flags), ""};
2649 multiname_t m = {QNAME, &ns, 0, $1};
2650 $$.c = abc_findpropstrict2($$.c, &m);
2651 $$.c = abc_getproperty2($$.c, &m);
2654 $$.c = abc_getlocal_0($$.c);
2655 $$.c = abc_getslot($$.c, f->slot);
2657 namespace_t ns = {flags2access(f->flags), ""};
2658 multiname_t m = {QNAME, &ns, 0, $1};
2659 $$.c = abc_getlocal_0($$.c);
2660 $$.c = abc_getproperty2($$.c, &m);
2663 if(f->kind == MEMBER_METHOD) {
2664 $$.t = TYPE_FUNCTION(f);
2669 /* look at actual classes, in the current package and imported */
2670 } else if((a = find_class($1))) {
2671 if(a->flags & FLAG_METHOD) {
2673 $$.c = abc_findpropstrict2($$.c, &m);
2674 $$.c = abc_getproperty2($$.c, &m);
2675 $$.t = TYPE_FUNCTION(a->function);
2678 $$.c = abc_getglobalscope($$.c);
2679 $$.c = abc_getslot($$.c, a->slot);
2682 $$.c = abc_getlex2($$.c, &m);
2684 $$.t = TYPE_CLASS(a);
2687 /* unknown object, let the avm2 resolve it */
2689 if(strcmp($1,"trace"))
2690 warning("Couldn't resolve '%s', doing late binding", $1);
2691 state->method->late_binding = 1;
2693 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2696 $$.c = abc_findpropstrict2($$.c, &m);
2697 $$.c = abc_getproperty2($$.c, &m);
2702 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2703 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2704 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2706 // ----------------- namespaces -------------------------------------------------
2708 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2709 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2710 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2712 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}