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));
628 state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
631 classinfo_list_t*mlist=0;
633 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
634 syntaxerror("invalid modifier(s)");
636 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
637 syntaxerror("public and internal not supported at the same time.");
639 /* create the class name, together with the proper attributes */
643 if(!(flags&FLAG_PUBLIC) && !state->package) {
644 access = ACCESS_PRIVATE; package = current_filename;
645 } else if(!(flags&FLAG_PUBLIC) && state->package) {
646 access = ACCESS_PACKAGEINTERNAL; package = state->package;
647 } else if(state->package) {
648 access = ACCESS_PACKAGE; package = state->package;
650 syntaxerror("public classes only allowed inside a package");
653 if(registry_findclass(package, classname)) {
654 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
658 /* build info struct */
659 int num_interfaces = (list_length(implements));
660 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
661 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
663 classinfo_list_t*l = implements;
664 for(l=implements;l;l=l->next) {
665 state->cls->info->interfaces[pos++] = l->classinfo;
668 multiname_t*extends2 = sig2mname(extends);
670 MULTINAME(classname2,state->cls->info);
673 state->cls_init = abc_getlocal_0(state->cls_init);
674 state->cls_init = abc_constructsuper(state->cls_init, 0);
677 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
678 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
679 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
681 state->cls->info->flags |= CLASS_INTERFACE;
682 abc_class_interface(state->cls->abc);
685 abc_class_protectedNS(state->cls->abc, classname);
687 for(mlist=implements;mlist;mlist=mlist->next) {
688 MULTINAME(m, mlist->classinfo);
689 abc_class_add_interface(state->cls->abc, &m);
692 /* now write the construction code for this class */
693 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
695 abc_method_body_t*m = global->init->method->body;
696 __ getglobalscope(m);
697 classinfo_t*s = extends;
702 //TODO: take a look at the current scope stack, maybe
703 // we can re-use something
708 multiname_t*s2 = sig2mname(s);
710 multiname_destroy(s2);
712 __ pushscope(m); count++;
713 m->code = m->code->prev->prev; // invert
715 /* continue appending after last op end */
716 while(m->code && m->code->next) m->code = m->code->next;
718 /* TODO: if this is one of *our* classes, we can also
719 do a getglobalscope/getslot <nr> (which references
720 the init function's slots) */
722 __ getlex2(m, extends2);
724 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
725 stack is not the superclass */
726 __ pushscope(m);count++;
729 /* notice: we get a verify error #1107 if the top element on the scope
730 stack is not the global object */
732 __ pushscope(m);count++;
734 __ newclass(m,state->cls->abc);
738 __ setslot(m, slotindex);
740 /* flash.display.MovieClip handling */
741 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
742 if(state->package && state->package[0]) {
743 globalclass = concat3(state->package, ".", classname);
745 globalclass = strdup(classname);
748 multiname_destroy(extends2);
751 static void endclass()
753 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
755 c = abc_getlocal_0(c);
756 c = abc_constructsuper(c, 0);
757 state->cls->init = code_append(state->cls->init, c);
759 if(!state->method->late_binding) {
760 // class initialization code uses late binding
762 c = abc_getlocal_0(c);
763 c = abc_pushscope(c);
764 state->cls->static_init = code_append(c, state->cls->static_init);
767 if(state->cls->init) {
768 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
769 m->body->code = wrap_function(0, state->cls->init, m->body->code);
771 if(state->cls->static_init) {
772 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
773 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
776 free(state->cls);state->cls=0;
777 free(state->method);state->method=0;
781 void check_code_for_break(code_t*c)
784 if(c->opcode == OPCODE___BREAK__) {
785 char*name = string_cstr(c->data[0]);
786 syntaxerror("Unresolved \"break %s\"", name);
788 if(c->opcode == OPCODE___CONTINUE__) {
789 char*name = string_cstr(c->data[0]);
790 syntaxerror("Unresolved \"continue %s\"", name);
797 static void check_constant_against_type(classinfo_t*t, constant_t*c)
799 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
800 if(TYPE_IS_NUMBER(t)) {
801 xassert(c->type == CONSTANT_FLOAT
802 || c->type == CONSTANT_INT
803 || c->type == CONSTANT_UINT);
804 } else if(TYPE_IS_UINT(t)) {
805 xassert(c->type == CONSTANT_UINT ||
806 (c->type == CONSTANT_INT && c->i>0));
807 } else if(TYPE_IS_INT(t)) {
808 xassert(c->type == CONSTANT_INT);
809 } else if(TYPE_IS_BOOLEAN(t)) {
810 xassert(c->type == CONSTANT_TRUE
811 || c->type == CONSTANT_FALSE);
816 static int flags2access(int flags)
819 if(flags&FLAG_PUBLIC) {
820 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
821 syntaxerror("invalid combination of access levels");
822 access = ACCESS_PACKAGE;
823 } else if(flags&FLAG_PRIVATE) {
824 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
825 syntaxerror("invalid combination of access levels");
826 access = ACCESS_PRIVATE;
827 } else if(flags&FLAG_PROTECTED) {
828 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
829 syntaxerror("invalid combination of access levels");
830 access = ACCESS_PROTECTED;
832 access = ACCESS_PACKAGEINTERNAL;
838 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
840 memberinfo_t*minfo = 0;
843 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
844 minfo->return_type = return_type;
845 } else if(getset != KW_GET && getset != KW_SET) {
847 if((minfo = registry_findmember(state->cls->info, name, 0))) {
848 if(minfo->parent == state->cls->info) {
849 syntaxerror("class already contains a member/method called '%s'", name);
850 } else if(!minfo->parent) {
851 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
853 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
854 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
857 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
858 minfo->return_type = return_type;
859 // getslot on a member slot only returns "undefined", so no need
860 // to actually store these
861 //state->minfo->slot = state->method->abc->method->trait->slot_id;
863 //class getter/setter
864 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
868 else if(params->list)
869 type = params->list->param->type;
870 // not sure wether to look into superclasses here, too
871 if((minfo=registry_findmember(state->cls->info, name, 0))) {
872 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
873 syntaxerror("class already contains a member or method called '%s'", name);
875 syntaxerror("getter/setter for '%s' already defined", name);
876 /* make a setter or getter into a getset */
881 if(type && minfo->type != type)
882 syntaxerror("different type in getter and setter");
884 minfo = memberinfo_register(state->cls->info, name, gs);
887 /* can't assign a slot as getter and setter might have different slots */
888 //minfo->slot = slot;
890 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
891 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
892 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
893 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
894 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
895 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
899 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
900 params_t*params, classinfo_t*return_type)
902 if(state->method && state->method->info) {
903 syntaxerror("not able to start another method scope");
906 global->variable_count = 0;
907 state->method = rfx_calloc(sizeof(methodstate_t));
908 state->method->has_super = 0;
911 state->method->is_constructor = !strcmp(state->cls->info->name,name);
912 state->cls->has_constructor |= state->method->is_constructor;
914 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
916 state->method->is_global = 1;
917 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
919 new_variable("globalscope", 0, 0);
922 /* state->vars is initialized by state_new */
925 for(p=params->list;p;p=p->next) {
926 new_variable(p->param->name, p->param->type, 0);
928 if(state->method->is_constructor)
929 name = "__as3_constructor__";
930 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
933 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
934 params_t*params, classinfo_t*return_type, code_t*body)
938 multiname_t*type2 = sig2mname(return_type);
940 if(state->method->is_constructor) {
941 f = abc_class_getconstructor(state->cls->abc, type2);
942 } else if(!state->method->is_global) {
943 namespace_t mname_ns = flags2namespace(flags, "");
944 multiname_t mname = {QNAME, &mname_ns, 0, name};
946 if(flags&FLAG_STATIC)
947 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
949 f = abc_class_method(state->cls->abc, type2, &mname);
950 slot = f->trait->slot_id;
952 namespace_t mname_ns = flags2namespace(flags, state->package);
953 multiname_t mname = {QNAME, &mname_ns, 0, name};
955 f = abc_method_new(global->file, type2, 1);
956 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
957 //abc_code_t*c = global->init->method->body->code;
959 //flash doesn't seem to allow us to access function slots
960 //state->method->info->slot = slot;
962 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
963 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
964 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
965 if(params->varargs) f->flags |= METHOD_NEED_REST;
969 for(p=params->list;p;p=p->next) {
970 if(params->varargs && !p->next) {
971 break; //varargs: omit last parameter in function signature
973 multiname_t*m = sig2mname(p->param->type);
974 list_append(f->parameters, m);
975 if(p->param->value) {
976 check_constant_against_type(p->param->type, p->param->value);
977 opt=1;list_append(f->optional_parameters, p->param->value);
979 syntaxerror("non-optional parameter not allowed after optional parameters");
982 check_code_for_break(body);
985 f->body->code = body;
986 f->body->exceptions = state->method->exceptions;
989 syntaxerror("interface methods can't have a method body");
992 free(state->method);state->method=0;
998 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1003 void breakjumpsto(code_t*c, char*name, code_t*jump)
1006 if(c->opcode == OPCODE___BREAK__) {
1007 string_t*name2 = c->data[0];
1008 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1009 c->opcode = OPCODE_JUMP;
1016 void continuejumpsto(code_t*c, char*name, code_t*jump)
1019 if(c->opcode == OPCODE___CONTINUE__) {
1020 string_t*name2 = c->data[0];
1021 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1022 c->opcode = OPCODE_JUMP;
1030 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1031 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1032 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1034 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1036 if(!type1 || !type2)
1037 return registry_getanytype();
1038 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1039 return registry_getanytype();
1042 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1051 return registry_getanytype();
1053 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1058 return abc_coerce_a(c);
1062 // cast an "any" type to a specific type. subject to
1063 // runtime exceptions
1064 return abc_coerce2(c, &m);
1067 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1068 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1069 // allow conversion between number types
1070 return abc_coerce2(c, &m);
1072 //printf("%s.%s\n", from.package, from.name);
1073 //printf("%s.%s\n", to.package, to.name);
1075 classinfo_t*supertype = from;
1077 if(supertype == to) {
1078 // target type is one of from's superclasses
1079 return abc_coerce2(c, &m);
1082 while(supertype->interfaces[t]) {
1083 if(supertype->interfaces[t]==to) {
1084 // target type is one of from's interfaces
1085 return abc_coerce2(c, &m);
1089 supertype = supertype->superclass;
1091 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1093 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1095 syntaxerror("can't convert type %s to %s", from->name, to->name);
1098 code_t*defaultvalue(code_t*c, classinfo_t*type)
1100 if(TYPE_IS_INT(type)) {
1101 c = abc_pushbyte(c, 0);
1102 } else if(TYPE_IS_UINT(type)) {
1103 c = abc_pushuint(c, 0);
1104 } else if(TYPE_IS_FLOAT(type)) {
1106 } else if(TYPE_IS_BOOLEAN(type)) {
1107 c = abc_pushfalse(c);
1109 //c = abc_pushundefined(c);
1111 c = abc_pushnull(c);
1113 c = abc_coerce2(c, &m);
1118 char is_pushundefined(code_t*c)
1120 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1123 void parserassert(int b)
1125 if(!b) syntaxerror("internal error: assertion failed");
1128 static classinfo_t* find_class(char*name)
1132 c = registry_findclass(state->package, name);
1135 /* try explicit imports */
1136 dictentry_t* e = dict_get_slot(state->imports, name);
1139 if(!strcmp(e->key, name)) {
1140 c = (classinfo_t*)e->data;
1146 /* try package.* imports */
1147 import_list_t*l = state->wildcard_imports;
1149 //printf("does package %s contain a class %s?\n", l->import->package, name);
1150 c = registry_findclass(l->import->package, name);
1155 /* try global package */
1156 c = registry_findclass("", name);
1159 /* try local "filename" package */
1160 c = registry_findclass(current_filename, name);
1166 static char is_getlocal(code_t*c)
1168 if(!c || c->prev || c->next)
1170 return(c->opcode == OPCODE_GETLOCAL
1171 || c->opcode == OPCODE_GETLOCAL_0
1172 || c->opcode == OPCODE_GETLOCAL_1
1173 || c->opcode == OPCODE_GETLOCAL_2
1174 || c->opcode == OPCODE_GETLOCAL_3);
1176 static int getlocalnr(code_t*c)
1178 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1179 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1180 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1181 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1182 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1183 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1186 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1190 [prefix code] [read instruction]
1194 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1197 if(in && in->opcode == OPCODE_COERCE_A) {
1198 in = code_cutlast(in);
1201 syntaxerror("internal error");
1203 /* chop off read instruction */
1207 prefix = r->prev;r->prev = 0;
1213 char use_temp_var = readbefore;
1215 /* generate the write instruction, and maybe append a dup to the prefix code */
1216 code_t* write = abc_nop(0);
1217 if(r->opcode == OPCODE_GETPROPERTY) {
1218 write->opcode = OPCODE_SETPROPERTY;
1219 multiname_t*m = (multiname_t*)r->data[0];
1220 write->data[0] = multiname_clone(m);
1221 if(m->type == QNAME || m->type == MULTINAME) {
1223 prefix = abc_dup(prefix); // we need the object, too
1226 } else if(m->type == MULTINAMEL) {
1228 /* dupping two values on the stack requires 5 operations and one register-
1229 couldn't adobe just have given us a dup2? */
1230 int temp = gettempvar();
1231 prefix = abc_setlocal(prefix, temp);
1232 prefix = abc_dup(prefix);
1233 prefix = abc_getlocal(prefix, temp);
1234 prefix = abc_swap(prefix);
1235 prefix = abc_getlocal(prefix, temp);
1237 prefix = abc_kill(prefix, temp);
1241 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1243 } else if(r->opcode == OPCODE_GETSLOT) {
1244 write->opcode = OPCODE_SETSLOT;
1245 write->data[0] = r->data[0];
1247 prefix = abc_dup(prefix); // we need the object, too
1250 } else if(r->opcode == OPCODE_GETLOCAL) {
1251 write->opcode = OPCODE_SETLOCAL;
1252 write->data[0] = r->data[0];
1253 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1254 write->opcode = OPCODE_SETLOCAL_0;
1255 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1256 write->opcode = OPCODE_SETLOCAL_1;
1257 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1258 write->opcode = OPCODE_SETLOCAL_2;
1259 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1260 write->opcode = OPCODE_SETLOCAL_3;
1262 code_dump(r, 0, 0, "", stdout);
1263 syntaxerror("illegal lvalue: can't assign a value to this expression");
1270 /* with getproperty/getslot, we have to be extra careful not
1271 to execute the read code twice, as it might have side-effects
1272 (e.g. if the property is in fact a setter/getter combination)
1274 So read the value, modify it, and write it again,
1275 using prefix only once and making sure (by using a temporary
1276 register) that the return value is what we just wrote */
1277 temp = gettempvar();
1278 c = code_append(c, prefix);
1279 c = code_append(c, r);
1282 c = abc_setlocal(c, temp);
1284 c = code_append(c, middlepart);
1287 c = abc_setlocal(c, temp);
1289 c = code_append(c, write);
1290 c = abc_getlocal(c, temp);
1291 c = abc_kill(c, temp);
1293 /* if we're allowed to execute the read code twice *and*
1294 the middlepart doesn't modify the code, things are easier.
1296 code_t* r2 = code_dup(r);
1297 //c = code_append(c, prefix);
1298 parserassert(!prefix);
1299 c = code_append(c, r);
1300 c = code_append(c, middlepart);
1301 c = code_append(c, write);
1302 c = code_append(c, r2);
1305 /* even smaller version: overwrite the value without reading
1309 c = code_append(c, prefix);
1312 c = code_append(c, middlepart);
1313 c = code_append(c, write);
1314 c = code_append(c, r);
1316 temp = gettempvar();
1318 c = code_append(c, prefix);
1320 c = code_append(c, middlepart);
1322 c = abc_setlocal(c, temp);
1323 c = code_append(c, write);
1324 c = abc_getlocal(c, temp);
1325 c = abc_kill(c, temp);
1338 /* ------------ code blocks / statements ---------------- */
1340 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1342 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1343 PROGRAM_CODE_LIST: PROGRAM_CODE
1344 | PROGRAM_CODE_LIST PROGRAM_CODE
1346 PROGRAM_CODE: PACKAGE_DECLARATION
1347 | INTERFACE_DECLARATION
1349 | FUNCTION_DECLARATION
1354 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1355 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1356 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1358 INPACKAGE_CODE: INTERFACE_DECLARATION
1360 | FUNCTION_DECLARATION
1365 MAYBECODE: CODE {$$=$1;}
1366 MAYBECODE: {$$=code_new();}
1368 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1369 CODE: CODEPIECE {$$=$1;}
1371 // code which also may appear outside a method
1372 CODE_STATEMENT: IMPORT
1373 CODE_STATEMENT: VOIDEXPRESSION
1375 CODE_STATEMENT: FOR_IN
1376 CODE_STATEMENT: WHILE
1377 CODE_STATEMENT: DO_WHILE
1378 CODE_STATEMENT: SWITCH
1380 CODE_STATEMENT: WITH
1383 // code which may appear anywhere
1384 CODEPIECE: ';' {$$=0;}
1385 CODEPIECE: VARIABLE_DECLARATION
1386 CODEPIECE: CODE_STATEMENT
1392 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1393 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1395 CODEBLOCK : '{' CODE '}' {$$=$2;}
1396 CODEBLOCK : '{' '}' {$$=0;}
1397 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1398 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1400 /* ------------ package init code ------------------- */
1402 PACKAGE_INITCODE: CODE_STATEMENT {
1403 if($1) warning("code ignored");
1406 /* ------------ variables --------------------------- */
1408 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1409 | {$$.c=abc_pushundefined(0);
1413 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1414 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1416 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1417 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1419 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1421 if(variable_exists($1))
1422 syntaxerror("Variable %s already defined", $1);
1424 if(!is_subtype_of($3.t, $2)) {
1425 syntaxerror("Can't convert %s to %s", $3.t->name,
1429 int index = new_variable($1, $2, 1);
1432 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1434 $$ = converttype($$, $3.t, $2);
1435 $$ = abc_setlocal($$, index);
1437 $$ = defaultvalue(0, $2);
1438 $$ = abc_setlocal($$, index);
1441 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1443 $$ = abc_coerce_a($$);
1444 $$ = abc_setlocal($$, index);
1450 /* that's the default for a local register, anyway
1452 state->method->initcode = abc_pushundefined(state->method->initcode);
1453 state->method->initcode = abc_setlocal(state->method->initcode, index);
1455 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1458 /* ------------ control flow ------------------------- */
1460 MAYBEELSE: %prec below_else {$$ = code_new();}
1461 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1462 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1464 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1467 $$ = code_append($$, $4.c);
1468 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1470 $$ = code_append($$, $6);
1472 myjmp = $$ = abc_jump($$, 0);
1474 myif->branch = $$ = abc_nop($$);
1476 $$ = code_append($$, $7);
1477 myjmp->branch = $$ = abc_nop($$);
1483 FOR_INIT : {$$=code_new();}
1484 FOR_INIT : VARIABLE_DECLARATION
1485 FOR_INIT : VOIDEXPRESSION
1486 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1487 $$=$2;new_variable($2,$3,1);
1489 FOR_IN_INIT : T_IDENTIFIER {
1493 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1494 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1496 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1497 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1499 $$ = code_append($$, $2);
1500 code_t*loopstart = $$ = abc_label($$);
1501 $$ = code_append($$, $4.c);
1502 code_t*myif = $$ = abc_iffalse($$, 0);
1503 $$ = code_append($$, $8);
1504 code_t*cont = $$ = abc_nop($$);
1505 $$ = code_append($$, $6);
1506 $$ = abc_jump($$, loopstart);
1507 code_t*out = $$ = abc_nop($$);
1508 breakjumpsto($$, $1.name, out);
1509 continuejumpsto($$, $1.name, cont);
1516 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1517 variable_t*var = find_variable($2);
1518 char*tmp1name = concat2($2, "__tmp1__");
1519 int it = new_variable(tmp1name, TYPE_INT, 0);
1520 char*tmp2name = concat2($2, "__array__");
1521 int array = new_variable(tmp1name, 0, 0);
1524 $$ = code_append($$, $4.c);
1525 $$ = abc_coerce_a($$);
1526 $$ = abc_setlocal($$, array);
1527 $$ = abc_pushbyte($$, 0);
1528 $$ = abc_setlocal($$, it);
1530 code_t*loopstart = $$ = abc_label($$);
1532 $$ = abc_hasnext2($$, array, it);
1533 code_t*myif = $$ = abc_iffalse($$, 0);
1534 $$ = abc_getlocal($$, array);
1535 $$ = abc_getlocal($$, it);
1537 $$ = abc_nextname($$);
1539 $$ = abc_nextvalue($$);
1540 $$ = converttype($$, 0, var->type);
1541 $$ = abc_setlocal($$, var->index);
1543 $$ = code_append($$, $6);
1544 $$ = abc_jump($$, loopstart);
1546 code_t*out = $$ = abc_nop($$);
1547 breakjumpsto($$, $1.name, out);
1548 continuejumpsto($$, $1.name, loopstart);
1559 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1563 code_t*myjmp = $$ = abc_jump($$, 0);
1564 code_t*loopstart = $$ = abc_label($$);
1565 $$ = code_append($$, $6);
1566 code_t*cont = $$ = abc_nop($$);
1567 myjmp->branch = cont;
1568 $$ = code_append($$, $4.c);
1569 $$ = abc_iftrue($$, loopstart);
1570 code_t*out = $$ = abc_nop($$);
1571 breakjumpsto($$, $1, out);
1572 continuejumpsto($$, $1, cont);
1578 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1580 code_t*loopstart = $$ = abc_label($$);
1581 $$ = code_append($$, $3);
1582 code_t*cont = $$ = abc_nop($$);
1583 $$ = code_append($$, $6.c);
1584 $$ = abc_iftrue($$, loopstart);
1585 code_t*out = $$ = abc_nop($$);
1586 breakjumpsto($$, $1, out);
1587 continuejumpsto($$, $1, cont);
1593 BREAK : "break" %prec prec_none {
1594 $$ = abc___break__(0, "");
1596 BREAK : "break" T_IDENTIFIER {
1597 $$ = abc___break__(0, $2);
1599 CONTINUE : "continue" %prec prec_none {
1600 $$ = abc___continue__(0, "");
1602 CONTINUE : "continue" T_IDENTIFIER {
1603 $$ = abc___continue__(0, $2);
1606 MAYBE_CASE_LIST : {$$=0;}
1607 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1608 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1609 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1610 CASE_LIST: CASE {$$=$1}
1611 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1613 CASE: "case" E ':' MAYBECODE {
1615 $$ = code_append($$, $2.c);
1616 code_t*j = $$ = abc_ifne($$, 0);
1617 $$ = code_append($$, $4);
1618 if($$->opcode != OPCODE___BREAK__) {
1619 $$ = abc___fallthrough__($$, "");
1621 code_t*e = $$ = abc_nop($$);
1624 DEFAULT: "default" ':' MAYBECODE {
1627 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1629 $$ = code_append($$, $7);
1630 code_t*out = $$ = abc_pop($$);
1631 breakjumpsto($$, $1, out);
1633 code_t*c = $$,*lastblock=0;
1635 if(c->opcode == OPCODE_IFNE) {
1636 if(!c->next) syntaxerror("internal error in fallthrough handling");
1638 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1640 c->opcode = OPCODE_JUMP;
1641 c->branch = lastblock;
1643 /* fall through end of switch */
1644 c->opcode = OPCODE_NOP;
1654 /* ------------ try / catch /finally ---------------- */
1656 FINALLY: "finally" '{' CODE '}'
1657 MAYBE_FINALLY: | FINALLY
1659 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1661 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1662 multiname_t name = {QNAME, &name_ns, 0, $3};
1664 NEW(abc_exception_t, e)
1665 e->exc_type = sig2mname($4);
1666 e->var_name = multiname_clone(&name);
1670 int i = find_variable_safe($3)->index;
1671 e->target = c = abc_setlocal(0, i);
1672 c = code_append(c, $8);
1680 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1681 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1683 TRY : "try" '{' {new_state();} CODE '}' CATCH_LIST MAYBE_FINALLY {
1684 code_t*start = code_start($4);
1687 code_t*out = abc_nop(0);
1688 code_t*jmp = $$ = abc_jump($$, out);
1690 abc_exception_list_t*l = $6;
1692 abc_exception_t*e = l->abc_exception;
1695 $$ = code_append($$, e->target);
1696 $$ = abc_jump($$, out);
1699 $$ = code_append($$, out);
1702 list_concat(state->method->exceptions, $6);
1708 /* ------------ throw ------------------------------- */
1710 THROW : "throw" EXPRESSION {
1714 THROW : "throw" %prec prec_none {
1715 if(!state->exception_name)
1716 syntaxerror("re-throw only possible within a catch block");
1717 variable_t*v = find_variable(state->exception_name);
1719 $$=abc_getlocal($$, v->index);
1723 /* ------------ with -------------------------------- */
1725 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1727 $$ = abc_pushscope($$);
1728 $$ = code_append($$, $5);
1729 $$ = abc_popscope($$);
1732 /* ------------ packages and imports ---------------- */
1734 X_IDENTIFIER: T_IDENTIFIER
1735 | "package" {$$="package";}
1737 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1738 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1740 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1741 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1743 IMPORT : "import" QNAME {
1746 syntaxerror("Couldn't import class\n");
1747 state_has_imports();
1748 dict_put(state->imports, c->name, c);
1751 IMPORT : "import" PACKAGE '.' '*' {
1754 state_has_imports();
1755 list_append(state->wildcard_imports, i);
1759 /* ------------ classes and interfaces (header) -------------- */
1761 MAYBE_MODIFIERS : {$$=0;}
1762 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1763 MODIFIER_LIST : MODIFIER {$$=$1;}
1764 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1766 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1767 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1768 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1769 | KW_STATIC {$$=FLAG_STATIC;}
1770 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1771 | KW_FINAL {$$=FLAG_FINAL;}
1772 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1773 | KW_NATIVE {$$=FLAG_NATIVE;}
1774 | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1776 EXTENDS : {$$=registry_getobjectclass();}
1777 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1779 EXTENDS_LIST : {$$=list_new();}
1780 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1782 IMPLEMENTS_LIST : {$$=list_new();}
1783 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1785 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1786 EXTENDS IMPLEMENTS_LIST
1787 '{' {startclass($1,$3,$4,$5, 0);}
1789 '}' {endclass();$$=0;}
1791 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1793 '{' {startclass($1,$3,0,$4,1);}
1794 MAYBE_INTERFACE_BODY
1795 '}' {endclass();$$=0;}
1797 /* ------------ classes and interfaces (body) -------------- */
1800 MAYBE_CLASS_BODY : CLASS_BODY
1801 CLASS_BODY : CLASS_BODY_ITEM
1802 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1803 CLASS_BODY_ITEM : ';'
1804 CLASS_BODY_ITEM : SLOT_DECLARATION
1805 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1807 CLASS_BODY_ITEM : CODE_STATEMENT {
1808 code_t*c = state->cls->static_init;
1809 c = code_append(c, $1);
1810 state->cls->static_init = c;
1813 MAYBE_INTERFACE_BODY :
1814 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1815 INTERFACE_BODY : IDECLARATION
1816 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1818 IDECLARATION : "var" T_IDENTIFIER {
1819 syntaxerror("variable declarations not allowed in interfaces");
1821 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1823 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
1824 syntaxerror("invalid method modifiers: interface methods always need to be public");
1826 startfunction(0,$1,$3,$4,&$6,$8);
1827 endfunction(0,$1,$3,$4,&$6,$8, 0);
1830 /* ------------ classes and interfaces (body, slots ) ------- */
1832 VARCONST: "var" | "const"
1834 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1836 memberinfo_t* info = state->cls?
1837 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1838 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1841 info->flags = flags;
1844 namespace_t mname_ns = {flags2access(flags), ""};
1845 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1847 trait_list_t**traits;
1851 traits = &global->init->traits;
1852 code = &global->init->method->body->code;
1853 } else if(flags&FLAG_STATIC) {
1855 traits = &state->cls->abc->static_traits;
1856 code = &state->cls->static_init;
1858 // instance variable
1859 traits = &state->cls->abc->traits;
1860 code = &state->cls->init;
1866 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1868 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1870 info->slot = t->slot_id;
1872 /* initalization code (if needed) */
1874 if($5.c && !is_pushundefined($5.c)) {
1875 c = abc_getlocal_0(c);
1876 c = code_append(c, $5.c);
1877 c = converttype(c, $5.t, $4);
1878 c = abc_setslot(c, t->slot_id);
1881 *code = code_append(*code, c);
1884 t->kind= TRAIT_CONST;
1890 /* ------------ constants -------------------------------------- */
1892 MAYBESTATICCONSTANT: {$$=0;}
1893 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1895 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1896 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1897 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1898 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1899 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1900 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1901 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1902 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1903 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1905 /* ------------ classes and interfaces (body, functions) ------- */
1907 // non-vararg version
1909 memset(&$$,0,sizeof($$));
1911 MAYBE_PARAM_LIST: PARAM_LIST {
1916 MAYBE_PARAM_LIST: "..." PARAM {
1917 memset(&$$,0,sizeof($$));
1919 list_append($$.list, $2);
1921 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1924 list_append($$.list, $4);
1928 PARAM_LIST: PARAM_LIST ',' PARAM {
1930 list_append($$.list, $3);
1933 memset(&$$,0,sizeof($$));
1934 list_append($$.list, $1);
1937 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1938 $$ = malloc(sizeof(param_t));
1943 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1944 $$ = malloc(sizeof(param_t));
1946 $$->type = TYPE_ANY;
1949 GETSET : "get" {$$=$1;}
1953 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1954 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1957 if(state->method->late_binding) {
1958 c = abc_getlocal_0(c);
1959 c = abc_pushscope(c);
1961 if(state->method->is_constructor && !state->method->has_super) {
1962 // call default constructor
1963 c = abc_getlocal_0(c);
1964 c = abc_constructsuper(c, 0);
1966 c = wrap_function(c, 0, $11);
1967 endfunction(0,$1,$3,$4,&$6,$8,c);
1971 /* ------------- package + class ids --------------- */
1973 CLASS: T_IDENTIFIER {
1975 /* try current package */
1976 $$ = find_class($1);
1977 if(!$$) syntaxerror("Could not find class %s\n", $1);
1980 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1981 $$ = registry_findclass($1, $3);
1982 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1986 QNAME: PACKAGEANDCLASS
1989 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1990 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1992 TYPE : QNAME {$$=$1;}
1993 | '*' {$$=registry_getanytype();}
1994 | "void" {$$=registry_getanytype();}
1996 | "String" {$$=registry_getstringclass();}
1997 | "int" {$$=registry_getintclass();}
1998 | "uint" {$$=registry_getuintclass();}
1999 | "Boolean" {$$=registry_getbooleanclass();}
2000 | "Number" {$$=registry_getnumberclass();}
2003 MAYBETYPE: ':' TYPE {$$=$2;}
2006 /* ----------function calls, delete, constructor calls ------ */
2008 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2009 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
2011 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2012 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2013 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2016 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2018 $$.cc = code_append($1.cc, $3.c);
2021 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2026 $$.c = abc_getglobalscope($$.c);
2027 $$.c = abc_getslot($$.c, $2->slot);
2029 $$.c = abc_findpropstrict2($$.c, &m);
2032 $$.c = code_append($$.c, $3.cc);
2035 $$.c = abc_construct($$.c, $3.len);
2037 $$.c = abc_constructprop2($$.c, &m, $3.len);
2041 /* TODO: use abc_call (for calling local variables),
2042 abc_callstatic (for calling own methods)
2045 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2048 if($$.c->opcode == OPCODE_COERCE_A) {
2049 $$.c = code_cutlast($$.c);
2051 code_t*paramcode = $3.cc;
2054 if($$.c->opcode == OPCODE_GETPROPERTY) {
2055 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2056 $$.c = code_cutlast($$.c);
2057 $$.c = code_append($$.c, paramcode);
2058 $$.c = abc_callproperty2($$.c, name, $3.len);
2059 multiname_destroy(name);
2060 } else if($$.c->opcode == OPCODE_GETSLOT) {
2061 int slot = (int)(ptroff_t)$$.c->data[0];
2062 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2063 if(t->kind!=TRAIT_METHOD) {
2064 //ok: flash allows to assign closures to members.
2066 multiname_t*name = t->name;
2067 $$.c = code_cutlast($$.c);
2068 $$.c = code_append($$.c, paramcode);
2069 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2070 $$.c = abc_callproperty2($$.c, name, $3.len);
2071 } else if($$.c->opcode == OPCODE_GETSUPER) {
2072 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2073 $$.c = code_cutlast($$.c);
2074 $$.c = code_append($$.c, paramcode);
2075 $$.c = abc_callsuper2($$.c, name, $3.len);
2076 multiname_destroy(name);
2078 $$.c = abc_getlocal_0($$.c);
2079 $$.c = code_append($$.c, paramcode);
2080 $$.c = abc_call($$.c, $3.len);
2085 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2086 $$.t = $1.t->function->return_type;
2088 $$.c = abc_coerce_a($$.c);
2093 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2094 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2095 if(!state->method) syntaxerror("super() not allowed outside of a function");
2096 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2099 $$.c = abc_getlocal_0($$.c);
2101 $$.c = code_append($$.c, $3.cc);
2103 this is dependent on the control path, check this somewhere else
2104 if(state->method->has_super)
2105 syntaxerror("constructor may call super() only once");
2107 state->method->has_super = 1;
2108 $$.c = abc_constructsuper($$.c, $3.len);
2109 $$.c = abc_pushundefined($$.c);
2113 DELETE: "delete" E {
2115 if($$.c->opcode == OPCODE_COERCE_A) {
2116 $$.c = code_cutlast($$.c);
2118 multiname_t*name = 0;
2119 if($$.c->opcode == OPCODE_GETPROPERTY) {
2120 $$.c->opcode = OPCODE_DELETEPROPERTY;
2121 } else if($$.c->opcode == OPCODE_GETSLOT) {
2122 int slot = (int)(ptroff_t)$$.c->data[0];
2123 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2124 $$.c = code_cutlast($$.c);
2125 $$.c = abc_deleteproperty2($$.c, name);
2127 $$.c = abc_getlocal_0($$.c);
2128 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2129 $$.c = abc_deleteproperty2($$.c, &m);
2131 $$.t = TYPE_BOOLEAN;
2134 RETURN: "return" %prec prec_none {
2135 $$ = abc_returnvoid(0);
2137 RETURN: "return" EXPRESSION {
2139 $$ = abc_returnvalue($$);
2142 // ----------------------- expression types -------------------------------------
2144 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2145 EXPRESSION : E %prec below_minus {$$ = $1;}
2146 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2148 $$.c = cut_last_push($$.c);
2149 $$.c = code_append($$.c,$3.c);
2152 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2153 $$=cut_last_push($1.c);
2156 // ----------------------- expression evaluation -------------------------------------
2158 //V : CONSTANT {$$ = 0;}
2160 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2161 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2162 //V : NEW {$$ = $1.c;}
2164 //V : DELETE {$$ = $1.c;}
2165 E : DELETE {$$ = $1;}
2169 namespace_t ns = {ACCESS_PACKAGE, ""};
2170 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2172 $$.c = abc_getlex2($$.c, &m);
2173 $$.c = abc_pushstring($$.c, $1.pattern);
2174 $$.c = abc_construct($$.c, 1);
2176 $$.c = abc_getlex2($$.c, &m);
2177 $$.c = abc_pushstring($$.c, $1.pattern);
2178 $$.c = abc_pushstring($$.c, $1.options);
2179 $$.c = abc_construct($$.c, 2);
2184 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2185 //MULTINAME(m, registry_getintclass());
2186 //$$.c = abc_coerce2($$.c, &m); // FIXME
2189 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2192 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2195 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2198 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2201 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2204 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2207 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2208 $$.t = TYPE_BOOLEAN;
2210 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2211 $$.t = TYPE_BOOLEAN;
2213 CONSTANT : "null" {$$.c = abc_pushnull(0);
2218 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2219 $$.t = TYPE_BOOLEAN;
2221 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2222 $$.t = TYPE_BOOLEAN;
2224 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2225 $$.t = TYPE_BOOLEAN;
2227 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2228 $$.t = TYPE_BOOLEAN;
2230 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2231 $$.t = TYPE_BOOLEAN;
2233 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2234 $$.t = TYPE_BOOLEAN;
2236 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2237 $$.t = TYPE_BOOLEAN;
2239 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2240 $$.t = TYPE_BOOLEAN;
2243 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2245 $$.c = converttype($$.c, $1.t, $$.t);
2246 $$.c = abc_dup($$.c);
2247 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2248 $$.c = cut_last_push($$.c);
2249 $$.c = code_append($$.c,$3.c);
2250 $$.c = converttype($$.c, $3.t, $$.t);
2251 code_t*label = $$.c = abc_label($$.c);
2252 jmp->branch = label;
2255 $$.t = join_types($1.t, $3.t, 'A');
2256 /*printf("%08x:\n",$1.t);
2257 code_dump($1.c, 0, 0, "", stdout);
2258 printf("%08x:\n",$3.t);
2259 code_dump($3.c, 0, 0, "", stdout);
2260 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2262 $$.c = converttype($$.c, $1.t, $$.t);
2263 $$.c = abc_dup($$.c);
2264 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2265 $$.c = cut_last_push($$.c);
2266 $$.c = code_append($$.c,$3.c);
2267 $$.c = converttype($$.c, $3.t, $$.t);
2268 code_t*label = $$.c = abc_label($$.c);
2269 jmp->branch = label;
2272 E : '!' E {$$.c=$2.c;
2273 $$.c = abc_not($$.c);
2274 $$.t = TYPE_BOOLEAN;
2277 E : '~' E {$$.c=$2.c;
2278 $$.c = abc_bitnot($$.c);
2282 E : E '&' E {$$.c = code_append($1.c,$3.c);
2283 $$.c = abc_bitand($$.c);
2287 E : E '^' E {$$.c = code_append($1.c,$3.c);
2288 $$.c = abc_bitxor($$.c);
2292 E : E '|' E {$$.c = code_append($1.c,$3.c);
2293 $$.c = abc_bitor($$.c);
2297 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2298 $$.c = abc_rshift($$.c);
2301 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2302 $$.c = abc_urshift($$.c);
2305 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2306 $$.c = abc_lshift($$.c);
2310 E : E '/' E {$$.c = code_append($1.c,$3.c);
2311 $$.c = abc_divide($$.c);
2314 E : E '%' E {$$.c = code_append($1.c,$3.c);
2315 $$.c = abc_modulo($$.c);
2318 E : E '+' E {$$.c = code_append($1.c,$3.c);
2319 if(BOTH_INT($1.t, $3.t)) {
2320 $$.c = abc_add_i($$.c);
2323 $$.c = abc_add($$.c);
2324 $$.t = join_types($1.t,$3.t,'+');
2327 E : E '-' E {$$.c = code_append($1.c,$3.c);
2328 if(BOTH_INT($1.t,$3.t)) {
2329 $$.c = abc_subtract_i($$.c);
2332 $$.c = abc_subtract($$.c);
2336 E : E '*' E {$$.c = code_append($1.c,$3.c);
2337 if(BOTH_INT($1.t,$3.t)) {
2338 $$.c = abc_multiply_i($$.c);
2341 $$.c = abc_multiply($$.c);
2346 E : E "in" E {$$.c = code_append($1.c,$3.c);
2347 $$.c = abc_in($$.c);
2348 $$.t = TYPE_BOOLEAN;
2351 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2352 if(use_astype && TYPE_IS_CLASS($3.t)) {
2353 MULTINAME(m,$3.t->cls);
2354 $$.c = abc_astype2($1.c, &m);
2357 $$.c = code_append($1.c, $3.c);
2358 $$.c = abc_astypelate($$.c);
2363 E : E "instanceof" E
2364 {$$.c = code_append($1.c, $3.c);
2365 $$.c = abc_instanceof($$.c);
2366 $$.t = TYPE_BOOLEAN;
2369 E : E "is" E {$$.c = code_append($1.c, $3.c);
2370 $$.c = abc_istypelate($$.c);
2371 $$.t = TYPE_BOOLEAN;
2374 E : "typeof" '(' E ')' {
2376 $$.c = abc_typeof($$.c);
2381 $$.c = cut_last_push($2.c);
2382 $$.c = abc_pushundefined($$.c);
2386 E : "void" { $$.c = abc_pushundefined(0);
2390 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2395 $$.c=abc_negate_i($$.c);
2398 $$.c=abc_negate($$.c);
2405 $$.c = code_append($$.c, $3.c);
2407 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2408 $$.c = abc_getproperty2($$.c, &m);
2409 $$.t = 0; // array elements have unknown type
2412 E : '[' MAYBE_EXPRESSION_LIST ']' {
2414 $$.c = code_append($$.c, $2.cc);
2415 $$.c = abc_newarray($$.c, $2.len);
2416 $$.t = registry_getarrayclass();
2419 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2420 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2422 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2424 $$.cc = code_append($$.cc, $1.c);
2425 $$.cc = code_append($$.cc, $3.c);
2428 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2431 $$.cc = code_append($$.cc, $3.c);
2432 $$.cc = code_append($$.cc, $5.c);
2437 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2439 $$.c = code_append($$.c, $2.cc);
2440 $$.c = abc_newobject($$.c, $2.len/2);
2441 $$.t = registry_getobjectclass();
2446 if(BOTH_INT($1.t,$3.t)) {
2447 c=abc_multiply_i(c);
2451 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2452 $$.c = toreadwrite($1.c, c, 0, 0);
2457 code_t*c = abc_modulo($3.c);
2458 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2459 $$.c = toreadwrite($1.c, c, 0, 0);
2463 code_t*c = abc_lshift($3.c);
2464 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2465 $$.c = toreadwrite($1.c, c, 0, 0);
2469 code_t*c = abc_rshift($3.c);
2470 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2471 $$.c = toreadwrite($1.c, c, 0, 0);
2475 code_t*c = abc_urshift($3.c);
2476 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2477 $$.c = toreadwrite($1.c, c, 0, 0);
2481 code_t*c = abc_divide($3.c);
2482 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2483 $$.c = toreadwrite($1.c, c, 0, 0);
2487 code_t*c = abc_bitor($3.c);
2488 c=converttype(c, TYPE_INT, $1.t);
2489 $$.c = toreadwrite($1.c, c, 0, 0);
2495 if(TYPE_IS_INT($1.t)) {
2499 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2502 $$.c = toreadwrite($1.c, c, 0, 0);
2505 E : E "-=" E { code_t*c = $3.c;
2506 if(TYPE_IS_INT($1.t)) {
2507 c=abc_subtract_i(c);
2510 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2513 $$.c = toreadwrite($1.c, c, 0, 0);
2516 E : E '=' E { code_t*c = 0;
2517 c = code_append(c, $3.c);
2518 c = converttype(c, $3.t, $1.t);
2519 $$.c = toreadwrite($1.c, c, 1, 0);
2523 E : E '?' E ':' E %prec below_assignment {
2524 $$.t = join_types($3.t,$5.t,'?');
2526 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2527 $$.c = code_append($$.c, $3.c);
2528 $$.c = converttype($$.c, $3.t, $$.t);
2529 code_t*j2 = $$.c = abc_jump($$.c, 0);
2530 $$.c = j1->branch = abc_label($$.c);
2531 $$.c = code_append($$.c, $5.c);
2532 $$.c = converttype($$.c, $3.t, $$.t);
2533 $$.c = j2->branch = abc_label($$.c);
2536 E : E "++" { code_t*c = 0;
2537 classinfo_t*type = $1.t;
2538 if(is_getlocal($1.c) && TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t)) {
2539 int nr = getlocalnr($1.c);
2540 code_free($1.c);$1.c=0;
2541 if(TYPE_IS_INT($1.t)) {
2542 $$.c = abc_getlocal(0, nr);
2543 $$.c = abc_inclocal_i($$.c, nr);
2544 } else if(TYPE_IS_NUMBER($1.t)) {
2545 $$.c = abc_getlocal(0, nr);
2546 $$.c = abc_inclocal($$.c, nr);
2547 } else syntaxerror("internal error");
2549 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2550 c=abc_increment_i(c);
2556 c=converttype(c, type, $1.t);
2557 $$.c = toreadwrite($1.c, c, 0, 1);
2562 // TODO: use inclocal, like with ++
2563 E : E "--" { code_t*c = 0;
2564 classinfo_t*type = $1.t;
2565 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2566 c=abc_decrement_i(c);
2572 c=converttype(c, type, $1.t);
2573 $$.c = toreadwrite($1.c, c, 0, 1);
2577 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2578 classinfo_t*type = $2.t;
2579 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2580 c=abc_increment_i(c);
2586 c=converttype(c, type, $2.t);
2587 $$.c = toreadwrite($2.c, c, 0, 0);
2591 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2592 classinfo_t*type = $2.t;
2593 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2594 c=abc_decrement_i(c);
2600 c=converttype(c, type, $2.t);
2601 $$.c = toreadwrite($2.c, c, 0, 0);
2605 E : "super" '.' T_IDENTIFIER
2606 { if(!state->cls->info)
2607 syntaxerror("super keyword not allowed outside a class");
2608 classinfo_t*t = state->cls->info->superclass;
2609 if(!t) t = TYPE_OBJECT;
2611 memberinfo_t*f = registry_findmember(t, $3, 1);
2612 namespace_t ns = flags2namespace(f->flags, "");
2613 MEMBER_MULTINAME(m, f, $3);
2615 $$.c = abc_getlocal_0($$.c);
2616 $$.c = abc_getsuper2($$.c, &m);
2617 $$.t = memberinfo_gettype(f);
2620 E : E '.' T_IDENTIFIER
2622 classinfo_t*t = $1.t;
2624 if(TYPE_IS_CLASS(t) && t->cls) {
2629 memberinfo_t*f = registry_findmember(t, $3, 1);
2631 if(f && !is_static != !(f->flags&FLAG_STATIC))
2633 if(f && f->slot && !noslot) {
2634 $$.c = abc_getslot($$.c, f->slot);
2636 MEMBER_MULTINAME(m, f, $3);
2637 $$.c = abc_getproperty2($$.c, &m);
2639 /* determine type */
2640 $$.t = memberinfo_gettype(f);
2642 $$.c = abc_coerce_a($$.c);
2644 /* when resolving a property on an unknown type, we do know the
2645 name of the property (and don't seem to need the package), but
2646 we need to make avm2 try out all access modes */
2647 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2648 $$.c = abc_getproperty2($$.c, &m);
2649 $$.c = abc_coerce_a($$.c);
2650 $$.t = registry_getanytype();
2654 VAR_READ : T_IDENTIFIER {
2661 /* look at variables */
2662 if((v = find_variable($1))) {
2663 // $1 is a local variable
2664 $$.c = abc_getlocal($$.c, v->index);
2667 /* look at current class' members */
2668 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2669 // $1 is a function in this class
2670 int var_is_static = (f->flags&FLAG_STATIC);
2671 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2672 if(var_is_static != i_am_static) {
2673 /* there doesn't seem to be any "static" way to access
2674 static properties of a class */
2675 state->method->late_binding = 1;
2677 namespace_t ns = {flags2access(f->flags), ""};
2678 multiname_t m = {QNAME, &ns, 0, $1};
2679 $$.c = abc_findpropstrict2($$.c, &m);
2680 $$.c = abc_getproperty2($$.c, &m);
2683 $$.c = abc_getlocal_0($$.c);
2684 $$.c = abc_getslot($$.c, f->slot);
2686 namespace_t ns = {flags2access(f->flags), ""};
2687 multiname_t m = {QNAME, &ns, 0, $1};
2688 $$.c = abc_getlocal_0($$.c);
2689 $$.c = abc_getproperty2($$.c, &m);
2692 if(f->kind == MEMBER_METHOD) {
2693 $$.t = TYPE_FUNCTION(f);
2698 /* look at actual classes, in the current package and imported */
2699 } else if((a = find_class($1))) {
2700 if(a->flags & FLAG_METHOD) {
2702 $$.c = abc_findpropstrict2($$.c, &m);
2703 $$.c = abc_getproperty2($$.c, &m);
2704 $$.t = TYPE_FUNCTION(a->function);
2707 $$.c = abc_getglobalscope($$.c);
2708 $$.c = abc_getslot($$.c, a->slot);
2711 $$.c = abc_getlex2($$.c, &m);
2713 $$.t = TYPE_CLASS(a);
2716 /* unknown object, let the avm2 resolve it */
2718 if(strcmp($1,"trace"))
2719 warning("Couldn't resolve '%s', doing late binding", $1);
2720 state->method->late_binding = 1;
2722 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2725 $$.c = abc_findpropstrict2($$.c, &m);
2726 $$.c = abc_getproperty2($$.c, &m);
2731 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2732 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2733 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2735 // ----------------- namespaces -------------------------------------------------
2737 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2738 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2739 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2741 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}