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 {
294 /* code that needs to be executed at the start of
295 a method (like initializing local registers) */
300 abc_exception_list_t*exceptions;
303 typedef struct _state {
308 import_list_t*wildcard_imports;
310 char has_own_imports;
313 methodstate_t*method;
320 typedef struct _global {
327 static global_t*global = 0;
328 static state_t* state = 0;
332 #define MULTINAME(m,x) \
335 registry_fill_multiname(&m, &m##_ns, x);
337 #define MEMBER_MULTINAME(m,f,n) \
341 m##_ns = flags2namespace(f->flags, ""); \
344 m.namespace_set = 0; \
347 m.type = MULTINAME; \
349 m.namespace_set = &nopackage_namespace_set; \
353 /* warning: list length of namespace set is undefined */
354 #define MULTINAME_LATE(m, access, package) \
355 namespace_t m##_ns = {access, package}; \
356 namespace_set_t m##_nsset; \
357 namespace_list_t m##_l;m##_l.next = 0; \
358 m##_nsset.namespaces = &m##_l; \
359 m##_nsset = m##_nsset; \
360 m##_l.namespace = &m##_ns; \
361 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
363 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
364 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
365 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
366 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
367 static namespace_list_t nl4 = {&ns4,0};
368 static namespace_list_t nl3 = {&ns3,&nl4};
369 static namespace_list_t nl2 = {&ns2,&nl3};
370 static namespace_list_t nl1 = {&ns1,&nl2};
371 static namespace_set_t nopackage_namespace_set = {&nl1};
373 static void new_state()
376 state_t*oldstate = state;
378 memcpy(s, state, sizeof(state_t)); //shallow copy
380 s->imports = dict_new();
384 state->has_own_imports = 0;
385 state->vars = dict_new();
386 state->old = oldstate;
388 static void state_has_imports()
390 state->wildcard_imports = list_clone(state->wildcard_imports);
391 state->imports = dict_clone(state->imports);
392 state->has_own_imports = 1;
395 static void state_destroy(state_t*state)
397 if(state->has_own_imports) {
398 list_free(state->wildcard_imports);
399 dict_destroy(state->imports);state->imports=0;
401 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
402 dict_destroy(state->imports);state->imports=0;
406 for(t=0;t<state->vars->hashsize;t++) {
407 dictentry_t*e =state->vars->slots[t];
409 free(e->data);e->data=0;
413 dict_destroy(state->vars);state->vars=0;
419 static void old_state()
421 if(!state || !state->old)
422 syntaxerror("invalid nesting");
423 state_t*leaving = state;
425 /*if(state->method->initcode) {
426 printf("residual initcode\n");
427 code_dump(state->method->initcode, 0, 0, "", stdout);
429 state_destroy(leaving);
431 void initialize_state()
433 global = rfx_calloc(sizeof(global_t));
436 state->package = current_filename;
438 global->file = abc_file_new();
439 global->file->flags &= ~ABCFILE_LAZY;
440 global->variable_count = 1;
442 global->init = abc_initscript(global->file, 0);
443 code_t*c = global->init->method->body->code;
445 c = abc_getlocal_0(c);
446 c = abc_pushscope(c);
448 /* findpropstrict doesn't just return a scope object- it
449 also makes it "active" somehow. Push local_0 on the
450 scope stack and read it back with findpropstrict, it'll
451 contain properties like "trace". Trying to find the same
452 property on a "vanilla" local_0 yields only a "undefined" */
453 //c = abc_findpropstrict(c, "[package]::trace");
455 /*c = abc_getlocal_0(c);
456 c = abc_findpropstrict(c, "[package]::trace");
458 c = abc_setlocal_1(c);
460 c = abc_pushbyte(c, 0);
461 c = abc_setlocal_2(c);
463 code_t*xx = c = abc_label(c);
464 c = abc_findpropstrict(c, "[package]::trace");
465 c = abc_pushstring(c, "prop:");
466 c = abc_hasnext2(c, 1, 2);
468 c = abc_setlocal_3(c);
469 c = abc_callpropvoid(c, "[package]::trace", 2);
470 c = abc_getlocal_3(c);
472 c = abc_iftrue(c,xx);*/
474 c = abc_findpropstrict(c, "[package]::trace");
475 c = abc_pushstring(c, "[entering global init function]");
476 c = abc_callpropvoid(c, "[package]::trace", 1);
478 global->init->method->body->code = c;
480 void* finalize_state()
482 if(state->level!=1) {
483 syntaxerror("unexpected end of file");
485 abc_method_body_t*m = global->init->method->body;
488 __ findpropstrict(m, "[package]::trace");
489 __ pushstring(m, "[leaving global init function]");
490 __ callpropvoid(m, "[package]::trace", 1);
493 state_destroy(state);state=0;
499 static void startpackage(char*name)
502 /*printf("entering package \"%s\"\n", name);*/
503 state->package = strdup(name);
504 global->variable_count = 1;
506 static void endpackage()
508 /*printf("leaving package \"%s\"\n", state->package);*/
510 //used e.g. in classinfo_register:
511 //free(state->package);state->package=0;
517 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
520 syntaxerror("inner classes now allowed");
523 global->variable_count = 1;
524 state->cls = rfx_calloc(sizeof(classstate_t));
527 classinfo_list_t*mlist=0;
528 /*printf("entering class %s\n", name);
529 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
531 printf(" extends: %s.%s\n", extends->package, extends->name);
532 printf(" implements (%d): ", list_length(implements));
533 for(mlist=implements;mlist;mlist=mlist->next) {
534 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
539 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
540 syntaxerror("invalid modifier(s)");
542 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
543 syntaxerror("public and internal not supported at the same time.");
545 /* create the class name, together with the proper attributes */
549 if(!(flags&FLAG_PUBLIC) && !state->package) {
550 access = ACCESS_PRIVATE; package = current_filename;
551 } else if(!(flags&FLAG_PUBLIC) && state->package) {
552 access = ACCESS_PACKAGEINTERNAL; package = state->package;
553 } else if(state->package) {
554 access = ACCESS_PACKAGE; package = state->package;
556 syntaxerror("public classes only allowed inside a package");
559 if(registry_findclass(package, classname)) {
560 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
564 /* build info struct */
565 int num_interfaces = (list_length(implements));
566 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
567 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
569 classinfo_list_t*l = implements;
570 for(l=implements;l;l=l->next) {
571 state->cls->info->interfaces[pos++] = l->classinfo;
574 multiname_t*extends2 = sig2mname(extends);
576 MULTINAME(classname2,state->cls->info);
579 state->cls_init = abc_getlocal_0(state->cls_init);
580 state->cls_init = abc_constructsuper(state->cls_init, 0);
583 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
584 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
585 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
587 state->cls->info->flags |= CLASS_INTERFACE;
588 abc_class_interface(state->cls->abc);
591 abc_class_protectedNS(state->cls->abc, classname);
593 for(mlist=implements;mlist;mlist=mlist->next) {
594 MULTINAME(m, mlist->classinfo);
595 abc_class_add_interface(state->cls->abc, &m);
598 /* now write the construction code for this class */
599 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
601 abc_method_body_t*m = global->init->method->body;
602 __ getglobalscope(m);
603 classinfo_t*s = extends;
608 //TODO: take a look at the current scope stack, maybe
609 // we can re-use something
614 multiname_t*s2 = sig2mname(s);
616 multiname_destroy(s2);
618 __ pushscope(m); count++;
619 m->code = m->code->prev->prev; // invert
621 /* continue appending after last op end */
622 while(m->code && m->code->next) m->code = m->code->next;
624 /* TODO: if this is one of *our* classes, we can also
625 do a getglobalscope/getslot <nr> (which references
626 the init function's slots) */
628 __ getlex2(m, extends2);
630 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
631 stack is not the superclass */
632 __ pushscope(m);count++;
635 /* notice: we get a verify error #1107 if the top element on the scope
636 stack is not the global object */
638 __ pushscope(m);count++;
640 __ newclass(m,state->cls->abc);
644 __ setslot(m, slotindex);
646 /* flash.display.MovieClip handling */
647 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
648 if(state->package && state->package[0]) {
649 globalclass = concat3(state->package, ".", classname);
651 globalclass = strdup(classname);
654 multiname_destroy(extends2);
657 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
659 c = code_append(c, initcode);
660 c = code_append(c, body);
661 /* append return if necessary */
662 if(!c || c->opcode != OPCODE_RETURNVOID &&
663 c->opcode != OPCODE_RETURNVALUE) {
664 c = abc_returnvoid(c);
669 static void endclass()
671 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
673 c = abc_getlocal_0(c);
674 c = abc_constructsuper(c, 0);
675 state->cls->init = code_append(state->cls->init, c);
678 if(state->cls->init) {
679 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
680 m->body->code = wrap_function(0, state->cls->init, m->body->code);
682 if(state->cls->static_init) {
683 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
684 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
686 // handy for scope testing
690 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
693 free(state->cls);state->cls=0;
697 typedef struct _variable {
702 static variable_t* find_variable(char*name)
708 v = dict_lookup(s->vars, name);
716 static variable_t* find_variable_safe(char*name)
718 variable_t* v = find_variable(name);
720 syntaxerror("undefined variable: %s", name);
723 static char variable_exists(char*name)
725 return dict_lookup(state->vars, name)!=0;
727 code_t*defaultvalue(code_t*c, classinfo_t*type);
728 static int new_variable(char*name, classinfo_t*type, char init)
731 v->index = global->variable_count;
734 dict_put(state->vars, name, v);
736 if(init && state->method && type) {
737 /* if this is a typed variable:
738 push default value for type on stack at the very beginning of the
739 method, so that it always has that type regardless of the control
741 state->method->initcode = defaultvalue(state->method->initcode, type);
742 state->method->initcode = abc_setlocal(state->method->initcode, v->index);
744 return global->variable_count++;
746 #define TEMPVARNAME "__as3_temp__"
747 static int gettempvar()
749 variable_t*v = find_variable(TEMPVARNAME);
752 return new_variable(TEMPVARNAME, 0, 0);
755 code_t* killvars(code_t*c)
758 for(t=0;t<state->vars->hashsize;t++) {
759 dictentry_t*e =state->vars->slots[t];
761 variable_t*v = (variable_t*)e->data;
762 //do this always, otherwise register types don't match
763 //in the verifier when doing nested loops
764 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
765 c = abc_kill(c, v->index);
772 void check_code_for_break(code_t*c)
775 if(c->opcode == OPCODE___BREAK__) {
776 char*name = string_cstr(c->data[0]);
777 syntaxerror("Unresolved \"break %s\"", name);
779 if(c->opcode == OPCODE___CONTINUE__) {
780 char*name = string_cstr(c->data[0]);
781 syntaxerror("Unresolved \"continue %s\"", name);
788 static void check_constant_against_type(classinfo_t*t, constant_t*c)
790 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
791 if(TYPE_IS_NUMBER(t)) {
792 xassert(c->type == CONSTANT_FLOAT
793 || c->type == CONSTANT_INT
794 || c->type == CONSTANT_UINT);
795 } else if(TYPE_IS_UINT(t)) {
796 xassert(c->type == CONSTANT_UINT ||
797 (c->type == CONSTANT_INT && c->i>0));
798 } else if(TYPE_IS_INT(t)) {
799 xassert(c->type == CONSTANT_INT);
800 } else if(TYPE_IS_BOOLEAN(t)) {
801 xassert(c->type == CONSTANT_TRUE
802 || c->type == CONSTANT_FALSE);
807 static int flags2access(int flags)
810 if(flags&FLAG_PUBLIC) {
811 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
812 syntaxerror("invalid combination of access levels");
813 access = ACCESS_PACKAGE;
814 } else if(flags&FLAG_PRIVATE) {
815 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
816 syntaxerror("invalid combination of access levels");
817 access = ACCESS_PRIVATE;
818 } else if(flags&FLAG_PROTECTED) {
819 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
820 syntaxerror("invalid combination of access levels");
821 access = ACCESS_PROTECTED;
823 access = ACCESS_PACKAGEINTERNAL;
829 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
831 memberinfo_t*minfo = 0;
834 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
835 minfo->return_type = return_type;
836 } else if(getset != KW_GET && getset != KW_SET) {
838 if((minfo = registry_findmember(state->cls->info, name, 0))) {
839 if(minfo->parent == state->cls->info) {
840 syntaxerror("class already contains a member/method called '%s'", name);
841 } else if(!minfo->parent) {
842 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
844 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
845 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
848 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
849 minfo->return_type = return_type;
850 // getslot on a member slot only returns "undefined", so no need
851 // to actually store these
852 //state->minfo->slot = state->method->abc->method->trait->slot_id;
854 //class getter/setter
855 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
859 else if(params->list)
860 type = params->list->param->type;
861 // not sure wether to look into superclasses here, too
862 if((minfo=registry_findmember(state->cls->info, name, 0))) {
863 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
864 syntaxerror("class already contains a member or method called '%s'", name);
866 syntaxerror("getter/setter for '%s' already defined", name);
867 /* make a setter or getter into a getset */
872 if(type && minfo->type != type)
873 syntaxerror("different type in getter and setter");
875 minfo = memberinfo_register(state->cls->info, name, gs);
878 /* can't assign a slot as getter and setter might have different slots */
879 //minfo->slot = slot;
881 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
882 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
883 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
884 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
885 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
886 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
890 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
891 params_t*params, classinfo_t*return_type)
894 syntaxerror("not able to start another method scope");
897 global->variable_count = 0;
898 state->method = rfx_calloc(sizeof(methodstate_t));
899 state->method->initcode = 0;
900 state->method->has_super = 0;
902 state->method->is_constructor = !strcmp(state->cls->info->name,name);
903 state->cls->has_constructor |= state->method->is_constructor;
905 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
907 state->method->is_global = 1;
908 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
910 new_variable("globalscope", 0, 0);
913 /* state->vars is initialized by state_new */
916 for(p=params->list;p;p=p->next) {
917 new_variable(p->param->name, p->param->type, 0);
919 if(state->method->is_constructor)
920 name = "__as3_constructor__";
921 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
924 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
925 params_t*params, classinfo_t*return_type, code_t*body)
929 multiname_t*type2 = sig2mname(return_type);
931 if(state->method->is_constructor) {
932 f = abc_class_getconstructor(state->cls->abc, type2);
933 } else if(!state->method->is_global) {
934 namespace_t mname_ns = flags2namespace(flags, "");
935 multiname_t mname = {QNAME, &mname_ns, 0, name};
937 if(flags&FLAG_STATIC)
938 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
940 f = abc_class_method(state->cls->abc, type2, &mname);
941 slot = f->trait->slot_id;
943 namespace_t mname_ns = flags2namespace(flags, state->package);
944 multiname_t mname = {QNAME, &mname_ns, 0, name};
946 f = abc_method_new(global->file, type2, 1);
947 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
948 //abc_code_t*c = global->init->method->body->code;
950 //flash doesn't seem to allow us to access function slots
951 //state->method->info->slot = slot;
953 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
954 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
955 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
956 if(params->varargs) f->flags |= METHOD_NEED_REST;
960 for(p=params->list;p;p=p->next) {
961 if(params->varargs && !p->next) {
962 break; //varargs: omit last parameter in function signature
964 multiname_t*m = sig2mname(p->param->type);
965 list_append(f->parameters, m);
966 if(p->param->value) {
967 check_constant_against_type(p->param->type, p->param->value);
968 opt=1;list_append(f->optional_parameters, p->param->value);
970 syntaxerror("non-optional parameter not allowed after optional parameters");
973 check_code_for_break(body);
976 f->body->code = body;
977 f->body->exceptions = state->method->exceptions;
980 syntaxerror("interface methods can't have a method body");
983 free(state->method);state->method=0;
989 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
994 void breakjumpsto(code_t*c, char*name, code_t*jump)
997 if(c->opcode == OPCODE___BREAK__) {
998 string_t*name2 = c->data[0];
999 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1000 c->opcode = OPCODE_JUMP;
1007 void continuejumpsto(code_t*c, char*name, code_t*jump)
1010 if(c->opcode == OPCODE___CONTINUE__) {
1011 string_t*name2 = c->data[0];
1012 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1013 c->opcode = OPCODE_JUMP;
1021 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1023 if(!type1 || !type2)
1024 return registry_getanytype();
1025 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1026 return registry_getanytype();
1029 return registry_getanytype();
1031 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1036 return abc_coerce_a(c);
1040 // cast an "any" type to a specific type. subject to
1041 // runtime exceptions
1042 return abc_coerce2(c, &m);
1045 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1046 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1047 // allow conversion between number types
1048 return abc_coerce2(c, &m);
1050 //printf("%s.%s\n", from.package, from.name);
1051 //printf("%s.%s\n", to.package, to.name);
1053 classinfo_t*supertype = from;
1055 if(supertype == to) {
1056 // target type is one of from's superclasses
1057 return abc_coerce2(c, &m);
1060 while(supertype->interfaces[t]) {
1061 if(supertype->interfaces[t]==to) {
1062 // target type is one of from's interfaces
1063 return abc_coerce2(c, &m);
1067 supertype = supertype->superclass;
1069 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1071 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1073 syntaxerror("can't convert type %s to %s", from->name, to->name);
1076 code_t*defaultvalue(code_t*c, classinfo_t*type)
1078 if(TYPE_IS_INT(type)) {
1079 c = abc_pushbyte(c, 0);
1080 } else if(TYPE_IS_UINT(type)) {
1081 c = abc_pushuint(c, 0);
1082 } else if(TYPE_IS_FLOAT(type)) {
1084 } else if(TYPE_IS_BOOLEAN(type)) {
1085 c = abc_pushfalse(c);
1087 c = abc_pushnull(c);
1092 char is_pushundefined(code_t*c)
1094 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1097 void parserassert(int b)
1099 if(!b) syntaxerror("internal error: assertion failed");
1102 static classinfo_t* find_class(char*name)
1106 c = registry_findclass(state->package, name);
1109 /* try explicit imports */
1110 dictentry_t* e = dict_get_slot(state->imports, name);
1113 if(!strcmp(e->key, name)) {
1114 c = (classinfo_t*)e->data;
1120 /* try package.* imports */
1121 import_list_t*l = state->wildcard_imports;
1123 //printf("does package %s contain a class %s?\n", l->import->package, name);
1124 c = registry_findclass(l->import->package, name);
1129 /* try global package */
1130 c = registry_findclass("", name);
1133 /* try local "filename" package */
1134 c = registry_findclass(current_filename, name);
1140 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1144 [prefix code] [read instruction]
1148 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1151 if(in && in->opcode == OPCODE_COERCE_A) {
1152 in = code_cutlast(in);
1155 syntaxerror("internal error");
1157 /* chop off read instruction */
1161 prefix = r->prev;r->prev = 0;
1167 char use_temp_var = readbefore;
1169 /* generate the write instruction, and maybe append a dup to the prefix code */
1170 code_t* write = abc_nop(0);
1171 if(r->opcode == OPCODE_GETPROPERTY) {
1172 write->opcode = OPCODE_SETPROPERTY;
1173 multiname_t*m = (multiname_t*)r->data[0];
1174 write->data[0] = multiname_clone(m);
1175 if(m->type == QNAME || m->type == MULTINAME) {
1177 prefix = abc_dup(prefix); // we need the object, too
1180 } else if(m->type == MULTINAMEL) {
1182 /* dupping two values on the stack requires 5 operations and one register-
1183 couldn't adobe just have given us a dup2? */
1184 int temp = gettempvar();
1185 prefix = abc_setlocal(prefix, temp);
1186 prefix = abc_dup(prefix);
1187 prefix = abc_getlocal(prefix, temp);
1188 prefix = abc_swap(prefix);
1189 prefix = abc_getlocal(prefix, temp);
1191 prefix = abc_kill(prefix, temp);
1195 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1197 } else if(r->opcode == OPCODE_GETSLOT) {
1198 write->opcode = OPCODE_SETSLOT;
1199 write->data[0] = r->data[0];
1201 prefix = abc_dup(prefix); // we need the object, too
1204 } else if(r->opcode == OPCODE_GETLOCAL) {
1205 write->opcode = OPCODE_SETLOCAL;
1206 write->data[0] = r->data[0];
1207 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1208 write->opcode = OPCODE_SETLOCAL_0;
1209 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1210 write->opcode = OPCODE_SETLOCAL_1;
1211 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1212 write->opcode = OPCODE_SETLOCAL_2;
1213 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1214 write->opcode = OPCODE_SETLOCAL_3;
1216 code_dump(r, 0, 0, "", stdout);
1217 syntaxerror("illegal lvalue: can't assign a value to this expression");
1224 /* with getproperty/getslot, we have to be extra careful not
1225 to execute the read code twice, as it might have side-effects
1226 (e.g. if the property is in fact a setter/getter combination)
1228 So read the value, modify it, and write it again,
1229 using prefix only once and making sure (by using a temporary
1230 register) that the return value is what we just wrote */
1231 temp = gettempvar();
1232 c = code_append(c, prefix);
1233 c = code_append(c, r);
1236 c = abc_setlocal(c, temp);
1238 c = code_append(c, middlepart);
1241 c = abc_setlocal(c, temp);
1243 c = code_append(c, write);
1244 c = abc_getlocal(c, temp);
1245 c = abc_kill(c, temp);
1247 /* if we're allowed to execute the read code twice *and*
1248 the middlepart doesn't modify the code, things are easier.
1250 code_t* r2 = code_dup(r);
1251 //c = code_append(c, prefix);
1252 parserassert(!prefix);
1253 c = code_append(c, r);
1254 c = code_append(c, middlepart);
1255 c = code_append(c, write);
1256 c = code_append(c, r2);
1259 /* even smaller version: overwrite the value without reading
1263 c = code_append(c, prefix);
1266 c = code_append(c, middlepart);
1267 c = code_append(c, write);
1268 c = code_append(c, r);
1270 temp = gettempvar();
1272 c = code_append(c, prefix);
1274 c = code_append(c, middlepart);
1276 c = abc_setlocal(c, temp);
1277 c = code_append(c, write);
1278 c = abc_getlocal(c, temp);
1279 c = abc_kill(c, temp);
1286 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1287 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1294 /* ------------ code blocks / statements ---------------- */
1296 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1298 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1299 PROGRAM_CODE_LIST: PROGRAM_CODE
1300 | PROGRAM_CODE_LIST PROGRAM_CODE
1302 PROGRAM_CODE: PACKAGE_DECLARATION
1303 | INTERFACE_DECLARATION
1305 | FUNCTION_DECLARATION
1310 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1311 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1312 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1314 INPACKAGE_CODE: INTERFACE_DECLARATION
1316 | FUNCTION_DECLARATION
1321 MAYBECODE: CODE {$$=$1;}
1322 MAYBECODE: {$$=code_new();}
1324 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1325 CODE: CODEPIECE {$$=$1;}
1327 // code which also may appear outside a method
1328 CODE_STATEMENT: IMPORT
1329 CODE_STATEMENT: VOIDEXPRESSION
1331 CODE_STATEMENT: FOR_IN
1332 CODE_STATEMENT: WHILE
1333 CODE_STATEMENT: DO_WHILE
1334 CODE_STATEMENT: SWITCH
1336 CODE_STATEMENT: WITH
1339 // code which may appear anywhere
1340 CODEPIECE: ';' {$$=0;}
1341 CODEPIECE: VARIABLE_DECLARATION
1342 CODEPIECE: CODE_STATEMENT
1348 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1349 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1351 CODEBLOCK : '{' CODE '}' {$$=$2;}
1352 CODEBLOCK : '{' '}' {$$=0;}
1353 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1354 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1356 /* ------------ package init code ------------------- */
1358 PACKAGE_INITCODE: CODE_STATEMENT {
1359 if($1) warning("code ignored");
1362 /* ------------ variables --------------------------- */
1364 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1365 | {$$.c=abc_pushundefined(0);
1369 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1370 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1372 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1373 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1375 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1377 if(variable_exists($1))
1378 syntaxerror("Variable %s already defined", $1);
1380 if(!is_subtype_of($3.t, $2)) {
1381 syntaxerror("Can't convert %s to %s", $3.t->name,
1385 int index = new_variable($1, $2, 1);
1388 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1390 $$ = converttype($$, $3.t, $2);
1391 $$ = abc_setlocal($$, index);
1393 $$ = defaultvalue(0, $2);
1394 $$ = abc_setlocal($$, index);
1397 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1399 $$ = abc_coerce_a($$);
1400 $$ = abc_setlocal($$, index);
1406 /* that's the default for a local register, anyway
1408 state->method->initcode = abc_pushundefined(state->method->initcode);
1409 state->method->initcode = abc_setlocal(state->method->initcode, index);
1411 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1414 /* ------------ control flow ------------------------- */
1416 MAYBEELSE: %prec below_else {$$ = code_new();}
1417 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1418 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1420 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1422 $$ = code_append($$, $4.c);
1423 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1425 $$ = code_append($$, $6);
1427 myjmp = $$ = abc_jump($$, 0);
1429 myif->branch = $$ = abc_nop($$);
1431 $$ = code_append($$, $7);
1432 myjmp->branch = $$ = abc_nop($$);
1435 $$ = killvars($$);old_state();
1438 FOR_INIT : {$$=code_new();}
1439 FOR_INIT : VARIABLE_DECLARATION
1440 FOR_INIT : VOIDEXPRESSION
1441 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1442 $$=$2;new_variable($2,$3,1);
1444 FOR_IN_INIT : T_IDENTIFIER {
1448 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1449 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1451 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1452 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1454 $$ = code_append($$, $2);
1455 code_t*loopstart = $$ = abc_label($$);
1456 $$ = code_append($$, $4.c);
1457 code_t*myif = $$ = abc_iffalse($$, 0);
1458 $$ = code_append($$, $8);
1459 code_t*cont = $$ = abc_nop($$);
1460 $$ = code_append($$, $6);
1461 $$ = abc_jump($$, loopstart);
1462 code_t*out = $$ = abc_nop($$);
1463 breakjumpsto($$, $1.name, out);
1464 continuejumpsto($$, $1.name, cont);
1467 $$ = killvars($$);old_state();
1470 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1471 variable_t*var = find_variable($2);
1472 char*tmp1name = concat2($2, "__tmp1__");
1473 int it = new_variable(tmp1name, TYPE_INT, 0);
1474 char*tmp2name = concat2($2, "__array__");
1475 int array = new_variable(tmp1name, 0, 0);
1478 $$ = code_append($$, $4.c);
1479 $$ = abc_coerce_a($$);
1480 $$ = abc_setlocal($$, array);
1481 $$ = abc_pushbyte($$, 0);
1482 $$ = abc_setlocal($$, it);
1484 code_t*loopstart = $$ = abc_label($$);
1486 $$ = abc_hasnext2($$, array, it);
1487 code_t*myif = $$ = abc_iffalse($$, 0);
1488 $$ = abc_getlocal($$, array);
1489 $$ = abc_getlocal($$, it);
1491 $$ = abc_nextname($$);
1493 $$ = abc_nextvalue($$);
1494 $$ = converttype($$, 0, var->type);
1495 $$ = abc_setlocal($$, var->index);
1497 $$ = code_append($$, $6);
1498 $$ = abc_jump($$, loopstart);
1500 code_t*out = $$ = abc_nop($$);
1501 breakjumpsto($$, $1.name, out);
1502 continuejumpsto($$, $1.name, loopstart);
1513 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1516 code_t*myjmp = $$ = abc_jump($$, 0);
1517 code_t*loopstart = $$ = abc_label($$);
1518 $$ = code_append($$, $6);
1519 code_t*cont = $$ = abc_nop($$);
1520 myjmp->branch = cont;
1521 $$ = code_append($$, $4.c);
1522 $$ = abc_iftrue($$, loopstart);
1523 code_t*out = $$ = abc_nop($$);
1524 breakjumpsto($$, $1, out);
1525 continuejumpsto($$, $1, cont);
1531 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1533 code_t*loopstart = $$ = abc_label($$);
1534 $$ = code_append($$, $3);
1535 code_t*cont = $$ = abc_nop($$);
1536 $$ = code_append($$, $6.c);
1537 $$ = abc_iftrue($$, loopstart);
1538 code_t*out = $$ = abc_nop($$);
1539 breakjumpsto($$, $1, out);
1540 continuejumpsto($$, $1, cont);
1545 BREAK : "break" %prec prec_none {
1546 $$ = abc___break__(0, "");
1548 BREAK : "break" T_IDENTIFIER {
1549 $$ = abc___break__(0, $2);
1551 CONTINUE : "continue" %prec prec_none {
1552 $$ = abc___continue__(0, "");
1554 CONTINUE : "continue" T_IDENTIFIER {
1555 $$ = abc___continue__(0, $2);
1558 MAYBE_CASE_LIST : {$$=0;}
1559 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1560 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1561 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1562 CASE_LIST: CASE {$$=$1}
1563 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1565 CASE: "case" E ':' MAYBECODE {
1567 $$ = code_append($$, $2.c);
1568 code_t*j = $$ = abc_ifne($$, 0);
1569 $$ = code_append($$, $4);
1570 if($$->opcode != OPCODE___BREAK__) {
1571 $$ = abc___fallthrough__($$, "");
1573 code_t*e = $$ = abc_nop($$);
1576 DEFAULT: "default" ':' MAYBECODE {
1579 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1581 $$ = code_append($$, $7);
1582 code_t*out = $$ = abc_pop($$);
1583 breakjumpsto($$, $1, out);
1585 code_t*c = $$,*lastblock=0;
1587 if(c->opcode == OPCODE_IFNE) {
1588 if(!c->next) syntaxerror("internal error in fallthrough handling");
1590 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1592 c->opcode = OPCODE_JUMP;
1593 c->branch = lastblock;
1595 /* fall through end of switch */
1596 c->opcode = OPCODE_NOP;
1604 /* ------------ try / catch /finally ---------------- */
1606 FINALLY: "finally" '{' CODE '}'
1607 MAYBE_FINALLY: | FINALLY
1609 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1612 int i = find_variable_safe($3)->index;
1613 c = abc_setlocal(c, i);
1614 c = code_append(c, $8);
1617 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1618 multiname_t name = {QNAME, &name_ns, 0, $3};
1620 NEW(abc_exception_t, e)
1621 e->exc_type = sig2mname($4);
1622 e->var_name = multiname_clone(&name);
1623 e->target = code_start(c);
1628 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1629 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1631 TRY : "try" '{' CODE '}' CATCH_LIST MAYBE_FINALLY {
1632 code_t*start = code_start($3);
1635 code_t*out = abc_nop(0);
1636 code_t*jmp = $$ = abc_jump($$, out);
1638 abc_exception_list_t*l = $5;
1640 abc_exception_t*e = l->abc_exception;
1643 $$ = code_append($$, e->target);
1644 $$ = abc_jump($$, out);
1647 $$ = code_append($$, out);
1650 list_concat(state->method->exceptions, $5);
1653 /* ------------ throw ------------------------------- */
1655 THROW : "throw" EXPRESSION {
1659 THROW : "throw" %prec prec_none {
1660 if(!state->exception_name)
1661 syntaxerror("re-throw only possible within a catch block");
1662 variable_t*v = find_variable(state->exception_name);
1664 $$=abc_getlocal($$, v->index);
1668 /* ------------ with -------------------------------- */
1670 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1672 $$ = abc_pushscope($$);
1673 $$ = code_append($$, $5);
1674 $$ = abc_popscope($$);
1677 /* ------------ packages and imports ---------------- */
1679 X_IDENTIFIER: T_IDENTIFIER
1680 | "package" {$$="package";}
1682 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1683 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1685 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1686 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1688 IMPORT : "import" QNAME {
1691 syntaxerror("Couldn't import class\n");
1692 state_has_imports();
1693 dict_put(state->imports, c->name, c);
1696 IMPORT : "import" PACKAGE '.' '*' {
1699 state_has_imports();
1700 list_append(state->wildcard_imports, i);
1704 /* ------------ classes and interfaces (header) -------------- */
1706 MAYBE_MODIFIERS : {$$=0;}
1707 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1708 MODIFIER_LIST : MODIFIER {$$=$1;}
1709 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1711 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1712 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1713 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1714 | KW_STATIC {$$=FLAG_STATIC;}
1715 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1716 | KW_FINAL {$$=FLAG_FINAL;}
1717 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1718 | KW_NATIVE {$$=FLAG_NATIVE;}
1719 | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1721 EXTENDS : {$$=registry_getobjectclass();}
1722 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1724 EXTENDS_LIST : {$$=list_new();}
1725 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1727 IMPLEMENTS_LIST : {$$=list_new();}
1728 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1730 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1731 EXTENDS IMPLEMENTS_LIST
1732 '{' {startclass($1,$3,$4,$5, 0);}
1734 '}' {endclass();$$=0;}
1736 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1738 '{' {startclass($1,$3,0,$4,1);}
1739 MAYBE_INTERFACE_BODY
1740 '}' {endclass();$$=0;}
1742 /* ------------ classes and interfaces (body) -------------- */
1745 MAYBE_CLASS_BODY : CLASS_BODY
1746 CLASS_BODY : CLASS_BODY_ITEM
1747 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1748 CLASS_BODY_ITEM : ';'
1749 CLASS_BODY_ITEM : SLOT_DECLARATION
1750 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1752 CLASS_BODY_ITEM : CODE_STATEMENT {
1753 code_t*c = state->cls->static_init;
1754 c = code_append(c, $1);
1755 state->cls->static_init = c;
1758 MAYBE_INTERFACE_BODY :
1759 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1760 INTERFACE_BODY : IDECLARATION
1761 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1763 IDECLARATION : "var" T_IDENTIFIER {
1764 syntaxerror("variable declarations not allowed in interfaces");
1766 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1768 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
1769 syntaxerror("invalid method modifiers: interface methods always need to be public");
1771 startfunction(0,$1,$3,$4,&$6,$8);
1772 endfunction(0,$1,$3,$4,&$6,$8, 0);
1775 /* ------------ classes and interfaces (body, slots ) ------- */
1777 VARCONST: "var" | "const"
1779 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1781 memberinfo_t* info = state->cls?
1782 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1783 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1786 info->flags = flags;
1789 namespace_t mname_ns = {flags2access(flags), ""};
1790 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1792 trait_list_t**traits;
1796 traits = &global->init->traits;
1797 code = &global->init->method->body->code;
1798 } else if(flags&FLAG_STATIC) {
1800 traits = &state->cls->abc->static_traits;
1801 code = &state->cls->static_init;
1803 // instance variable
1804 traits = &state->cls->abc->traits;
1805 code = &state->cls->init;
1811 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1813 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1815 info->slot = t->slot_id;
1817 /* initalization code (if needed) */
1819 if($5.c && !is_pushundefined($5.c)) {
1820 c = abc_getlocal_0(c);
1821 c = code_append(c, $5.c);
1822 c = converttype(c, $5.t, $4);
1823 c = abc_setslot(c, t->slot_id);
1826 *code = code_append(*code, c);
1829 t->kind= TRAIT_CONST;
1835 /* ------------ constants -------------------------------------- */
1837 MAYBESTATICCONSTANT: {$$=0;}
1838 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1840 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1841 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1842 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1843 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1844 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1845 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1846 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1847 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1848 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1850 /* ------------ classes and interfaces (body, functions) ------- */
1852 // non-vararg version
1854 memset(&$$,0,sizeof($$));
1856 MAYBE_PARAM_LIST: PARAM_LIST {
1861 MAYBE_PARAM_LIST: "..." PARAM {
1862 memset(&$$,0,sizeof($$));
1864 list_append($$.list, $2);
1866 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1869 list_append($$.list, $4);
1873 PARAM_LIST: PARAM_LIST ',' PARAM {
1875 list_append($$.list, $3);
1878 memset(&$$,0,sizeof($$));
1879 list_append($$.list, $1);
1882 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1883 $$ = malloc(sizeof(param_t));
1888 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1889 $$ = malloc(sizeof(param_t));
1891 $$->type = TYPE_ANY;
1894 GETSET : "get" {$$=$1;}
1898 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1899 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1902 if(state->method->late_binding) {
1903 c = abc_getlocal_0(c);
1904 c = abc_pushscope(c);
1906 if(state->method->is_constructor && !state->method->has_super) {
1907 // call default constructor
1908 c = abc_getlocal_0(c);
1909 c = abc_constructsuper(c, 0);
1911 c = wrap_function(c, state->method->initcode, $11);
1912 endfunction(0,$1,$3,$4,&$6,$8,c);
1916 /* ------------- package + class ids --------------- */
1918 CLASS: T_IDENTIFIER {
1920 /* try current package */
1921 $$ = find_class($1);
1922 if(!$$) syntaxerror("Could not find class %s\n", $1);
1925 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1926 $$ = registry_findclass($1, $3);
1927 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1931 QNAME: PACKAGEANDCLASS
1934 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1935 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1937 TYPE : QNAME {$$=$1;}
1938 | '*' {$$=registry_getanytype();}
1939 | "void" {$$=registry_getanytype();}
1941 | "String" {$$=registry_getstringclass();}
1942 | "int" {$$=registry_getintclass();}
1943 | "uint" {$$=registry_getuintclass();}
1944 | "Boolean" {$$=registry_getbooleanclass();}
1945 | "Number" {$$=registry_getnumberclass();}
1948 MAYBETYPE: ':' TYPE {$$=$2;}
1951 /* ----------function calls, delete, constructor calls ------ */
1953 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
1954 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1956 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1957 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1958 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
1961 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1963 $$.cc = code_append($1.cc, $3.c);
1966 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1971 $$.c = abc_getglobalscope($$.c);
1972 $$.c = abc_getslot($$.c, $2->slot);
1974 $$.c = abc_findpropstrict2($$.c, &m);
1977 $$.c = code_append($$.c, $3.cc);
1980 $$.c = abc_construct($$.c, $3.len);
1982 $$.c = abc_constructprop2($$.c, &m, $3.len);
1986 /* TODO: use abc_call (for calling local variables),
1987 abc_callstatic (for calling own methods)
1990 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1993 if($$.c->opcode == OPCODE_COERCE_A) {
1994 $$.c = code_cutlast($$.c);
1996 code_t*paramcode = $3.cc;
1999 if($$.c->opcode == OPCODE_GETPROPERTY) {
2000 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2001 $$.c = code_cutlast($$.c);
2002 $$.c = code_append($$.c, paramcode);
2003 $$.c = abc_callproperty2($$.c, name, $3.len);
2004 multiname_destroy(name);
2005 } else if($$.c->opcode == OPCODE_GETSLOT) {
2006 int slot = (int)(ptroff_t)$$.c->data[0];
2007 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2008 if(t->kind!=TRAIT_METHOD) {
2009 //ok: flash allows to assign closures to members.
2011 multiname_t*name = t->name;
2012 $$.c = code_cutlast($$.c);
2013 $$.c = code_append($$.c, paramcode);
2014 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2015 $$.c = abc_callproperty2($$.c, name, $3.len);
2016 } else if($$.c->opcode == OPCODE_GETSUPER) {
2017 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2018 $$.c = code_cutlast($$.c);
2019 $$.c = code_append($$.c, paramcode);
2020 $$.c = abc_callsuper2($$.c, name, $3.len);
2021 multiname_destroy(name);
2023 $$.c = abc_getlocal_0($$.c);
2024 $$.c = code_append($$.c, paramcode);
2025 $$.c = abc_call($$.c, $3.len);
2030 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2031 $$.t = $1.t->function->return_type;
2033 $$.c = abc_coerce_a($$.c);
2038 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2039 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2040 if(!state->method) syntaxerror("super() not allowed outside of a function");
2041 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2044 $$.c = abc_getlocal_0($$.c);
2046 $$.c = code_append($$.c, $3.cc);
2048 this is dependent on the control path, check this somewhere else
2049 if(state->method->has_super)
2050 syntaxerror("constructor may call super() only once");
2052 state->method->has_super = 1;
2053 $$.c = abc_constructsuper($$.c, $3.len);
2054 $$.c = abc_pushundefined($$.c);
2058 DELETE: "delete" E {
2060 if($$.c->opcode == OPCODE_COERCE_A) {
2061 $$.c = code_cutlast($$.c);
2063 multiname_t*name = 0;
2064 if($$.c->opcode == OPCODE_GETPROPERTY) {
2065 $$.c->opcode = OPCODE_DELETEPROPERTY;
2066 } else if($$.c->opcode == OPCODE_GETSLOT) {
2067 int slot = (int)(ptroff_t)$$.c->data[0];
2068 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2069 $$.c = code_cutlast($$.c);
2070 $$.c = abc_deleteproperty2($$.c, name);
2072 $$.c = abc_getlocal_0($$.c);
2073 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2074 $$.c = abc_deleteproperty2($$.c, &m);
2076 $$.t = TYPE_BOOLEAN;
2079 RETURN: "return" %prec prec_none {
2080 $$ = abc_returnvoid(0);
2082 RETURN: "return" EXPRESSION {
2084 $$ = abc_returnvalue($$);
2087 // ----------------------- expression types -------------------------------------
2089 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2090 EXPRESSION : E %prec below_minus {$$ = $1;}
2091 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2093 $$.c = cut_last_push($$.c);
2094 $$.c = code_append($$.c,$3.c);
2097 VOIDEXPRESSION : E %prec below_minus {
2098 $$=cut_last_push($1.c);
2101 // ----------------------- expression evaluation -------------------------------------
2103 //V : CONSTANT {$$ = 0;}
2105 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2106 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2107 //V : NEW {$$ = $1.c;}
2109 //V : DELETE {$$ = $1.c;}
2110 E : DELETE {$$ = $1;}
2114 namespace_t ns = {ACCESS_PACKAGE, ""};
2115 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2117 $$.c = abc_getlex2($$.c, &m);
2118 $$.c = abc_pushstring($$.c, $1.pattern);
2119 $$.c = abc_construct($$.c, 1);
2121 $$.c = abc_getlex2($$.c, &m);
2122 $$.c = abc_pushstring($$.c, $1.pattern);
2123 $$.c = abc_pushstring($$.c, $1.options);
2124 $$.c = abc_construct($$.c, 2);
2129 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2130 //MULTINAME(m, registry_getintclass());
2131 //$$.c = abc_coerce2($$.c, &m); // FIXME
2134 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2137 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2140 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2143 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2146 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2149 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2152 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2153 $$.t = TYPE_BOOLEAN;
2155 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2156 $$.t = TYPE_BOOLEAN;
2158 CONSTANT : "null" {$$.c = abc_pushnull(0);
2163 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2164 $$.t = TYPE_BOOLEAN;
2166 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2167 $$.t = TYPE_BOOLEAN;
2169 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2170 $$.t = TYPE_BOOLEAN;
2172 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2173 $$.t = TYPE_BOOLEAN;
2175 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2176 $$.t = TYPE_BOOLEAN;
2178 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2179 $$.t = TYPE_BOOLEAN;
2181 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2182 $$.t = TYPE_BOOLEAN;
2184 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2185 $$.t = TYPE_BOOLEAN;
2188 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2190 $$.c = converttype($$.c, $1.t, $$.t);
2191 $$.c = abc_dup($$.c);
2192 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2193 $$.c = cut_last_push($$.c);
2194 $$.c = code_append($$.c,$3.c);
2195 $$.c = converttype($$.c, $3.t, $$.t);
2196 code_t*label = $$.c = abc_label($$.c);
2197 jmp->branch = label;
2200 $$.t = join_types($1.t, $3.t, 'A');
2201 /*printf("%08x:\n",$1.t);
2202 code_dump($1.c, 0, 0, "", stdout);
2203 printf("%08x:\n",$3.t);
2204 code_dump($3.c, 0, 0, "", stdout);
2205 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2207 $$.c = converttype($$.c, $1.t, $$.t);
2208 $$.c = abc_dup($$.c);
2209 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2210 $$.c = cut_last_push($$.c);
2211 $$.c = code_append($$.c,$3.c);
2212 $$.c = converttype($$.c, $3.t, $$.t);
2213 code_t*label = $$.c = abc_label($$.c);
2214 jmp->branch = label;
2217 E : '!' E {$$.c=$2.c;
2218 $$.c = abc_not($$.c);
2219 $$.t = TYPE_BOOLEAN;
2222 E : '~' E {$$.c=$2.c;
2223 $$.c = abc_bitnot($$.c);
2227 E : E '&' E {$$.c = code_append($1.c,$3.c);
2228 $$.c = abc_bitand($$.c);
2232 E : E '^' E {$$.c = code_append($1.c,$3.c);
2233 $$.c = abc_bitxor($$.c);
2237 E : E '|' E {$$.c = code_append($1.c,$3.c);
2238 $$.c = abc_bitor($$.c);
2242 E : E '-' E {$$.c = code_append($1.c,$3.c);
2243 if(BOTH_INT($1,$3)) {
2244 $$.c = abc_subtract_i($$.c);
2247 $$.c = abc_subtract($$.c);
2251 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2252 $$.c = abc_rshift($$.c);
2255 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2256 $$.c = abc_urshift($$.c);
2259 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2260 $$.c = abc_lshift($$.c);
2264 E : E '/' E {$$.c = code_append($1.c,$3.c);
2265 $$.c = abc_divide($$.c);
2268 E : E '+' E {$$.c = code_append($1.c,$3.c);
2269 $$.c = abc_add($$.c);
2272 E : E '%' E {$$.c = code_append($1.c,$3.c);
2273 $$.c = abc_modulo($$.c);
2276 E : E '*' E {$$.c = code_append($1.c,$3.c);
2277 if(BOTH_INT($1,$3)) {
2278 $$.c = abc_multiply_i($$.c);
2281 $$.c = abc_multiply($$.c);
2286 E : E "in" E {$$.c = code_append($1.c,$3.c);
2287 $$.c = abc_in($$.c);
2288 $$.t = TYPE_BOOLEAN;
2291 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2292 if(use_astype && TYPE_IS_CLASS($3.t)) {
2293 MULTINAME(m,$3.t->cls);
2294 $$.c = abc_astype2($1.c, &m);
2297 $$.c = code_append($1.c, $3.c);
2298 $$.c = abc_astypelate($$.c);
2303 E : E "instanceof" E
2304 {$$.c = code_append($1.c, $3.c);
2305 $$.c = abc_instanceof($$.c);
2306 $$.t = TYPE_BOOLEAN;
2309 E : E "is" E {$$.c = code_append($1.c, $3.c);
2310 $$.c = abc_istypelate($$.c);
2311 $$.t = TYPE_BOOLEAN;
2314 E : "typeof" '(' E ')' {
2316 $$.c = abc_typeof($$.c);
2321 $$.c = cut_last_push($2.c);
2322 $$.c = abc_pushundefined($$.c);
2326 E : "void" { $$.c = abc_pushundefined(0);
2330 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2335 $$.c=abc_negate_i($$.c);
2338 $$.c=abc_negate($$.c);
2345 $$.c = code_append($$.c, $3.c);
2347 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2348 $$.c = abc_getproperty2($$.c, &m);
2349 $$.t = 0; // array elements have unknown type
2352 E : '[' MAYBE_EXPRESSION_LIST ']' {
2354 $$.c = code_append($$.c, $2.cc);
2355 $$.c = abc_newarray($$.c, $2.len);
2356 $$.t = registry_getarrayclass();
2359 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2360 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2362 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2364 $$.cc = code_append($$.cc, $1.c);
2365 $$.cc = code_append($$.cc, $3.c);
2368 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2371 $$.cc = code_append($$.cc, $3.c);
2372 $$.cc = code_append($$.cc, $5.c);
2377 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2379 $$.c = code_append($$.c, $2.cc);
2380 $$.c = abc_newobject($$.c, $2.len/2);
2381 $$.t = registry_getobjectclass();
2386 if(BOTH_INT($1,$3)) {
2387 c=abc_multiply_i(c);
2391 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2392 $$.c = toreadwrite($1.c, c, 0, 0);
2397 code_t*c = abc_modulo($3.c);
2398 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2399 $$.c = toreadwrite($1.c, c, 0, 0);
2403 code_t*c = abc_lshift($3.c);
2404 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2405 $$.c = toreadwrite($1.c, c, 0, 0);
2409 code_t*c = abc_rshift($3.c);
2410 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2411 $$.c = toreadwrite($1.c, c, 0, 0);
2415 code_t*c = abc_urshift($3.c);
2416 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2417 $$.c = toreadwrite($1.c, c, 0, 0);
2421 code_t*c = abc_divide($3.c);
2422 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2423 $$.c = toreadwrite($1.c, c, 0, 0);
2427 code_t*c = abc_bitor($3.c);
2428 c=converttype(c, TYPE_INT, $1.t);
2429 $$.c = toreadwrite($1.c, c, 0, 0);
2434 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2439 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2441 $$.c = toreadwrite($1.c, c, 0, 0);
2444 E : E "-=" E { code_t*c = $3.c;
2445 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2446 c=abc_subtract_i(c);
2450 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2452 $$.c = toreadwrite($1.c, c, 0, 0);
2455 E : E '=' E { code_t*c = 0;
2456 c = code_append(c, $3.c);
2457 c = converttype(c, $3.t, $1.t);
2458 $$.c = toreadwrite($1.c, c, 1, 0);
2462 E : E '?' E ':' E %prec below_assignment {
2464 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2465 $$.c = code_append($$.c, $3.c);
2466 code_t*j2 = $$.c = abc_jump($$.c, 0);
2467 $$.c = j1->branch = abc_label($$.c);
2468 $$.c = code_append($$.c, $5.c);
2469 $$.c = j2->branch = abc_label($$.c);
2470 $$.t = join_types($3.t,$5.t,'?');
2473 // TODO: use inclocal where appropriate
2474 E : E "++" { code_t*c = 0;
2475 classinfo_t*type = $1.t;
2476 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2477 c=abc_increment_i(c);
2483 c=converttype(c, type, $1.t);
2484 $$.c = toreadwrite($1.c, c, 0, 1);
2487 E : E "--" { code_t*c = 0;
2488 classinfo_t*type = $1.t;
2489 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2490 c=abc_decrement_i(c);
2496 c=converttype(c, type, $1.t);
2497 $$.c = toreadwrite($1.c, c, 0, 1);
2501 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2502 classinfo_t*type = $2.t;
2503 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2504 c=abc_increment_i(c);
2510 c=converttype(c, type, $2.t);
2511 $$.c = toreadwrite($2.c, c, 0, 0);
2515 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2516 classinfo_t*type = $2.t;
2517 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2518 c=abc_decrement_i(c);
2524 c=converttype(c, type, $2.t);
2525 $$.c = toreadwrite($2.c, c, 0, 0);
2529 E : "super" '.' T_IDENTIFIER
2530 { if(!state->cls->info)
2531 syntaxerror("super keyword not allowed outside a class");
2532 classinfo_t*t = state->cls->info->superclass;
2533 if(!t) t = TYPE_OBJECT;
2535 memberinfo_t*f = registry_findmember(t, $3, 1);
2536 namespace_t ns = flags2namespace(f->flags, "");
2537 MEMBER_MULTINAME(m, f, $3);
2539 $$.c = abc_getlocal_0($$.c);
2540 $$.c = abc_getsuper2($$.c, &m);
2541 $$.t = memberinfo_gettype(f);
2544 E : E '.' T_IDENTIFIER
2546 classinfo_t*t = $1.t;
2548 if(TYPE_IS_CLASS(t) && t->cls) {
2553 memberinfo_t*f = registry_findmember(t, $3, 1);
2555 if(f && !is_static != !(f->flags&FLAG_STATIC))
2557 if(f && f->slot && !noslot) {
2558 $$.c = abc_getslot($$.c, f->slot);
2560 MEMBER_MULTINAME(m, f, $3);
2561 $$.c = abc_getproperty2($$.c, &m);
2563 /* determine type */
2564 $$.t = memberinfo_gettype(f);
2566 $$.c = abc_coerce_a($$.c);
2568 /* when resolving a property on an unknown type, we do know the
2569 name of the property (and don't seem to need the package), but
2570 we need to make avm2 try out all access modes */
2571 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2572 $$.c = abc_getproperty2($$.c, &m);
2573 $$.c = abc_coerce_a($$.c);
2574 $$.t = registry_getanytype();
2578 VAR_READ : T_IDENTIFIER {
2585 /* look at variables */
2586 if((v = find_variable($1))) {
2587 // $1 is a local variable
2588 $$.c = abc_getlocal($$.c, v->index);
2591 /* look at current class' members */
2592 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2593 // $1 is a function in this class
2594 int var_is_static = (f->flags&FLAG_STATIC);
2595 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2596 if(var_is_static != i_am_static) {
2597 /* there doesn't seem to be any "static" way to access
2598 static properties of a class */
2599 state->method->late_binding = 1;
2601 namespace_t ns = {flags2access(f->flags), ""};
2602 multiname_t m = {QNAME, &ns, 0, $1};
2603 $$.c = abc_findpropstrict2($$.c, &m);
2604 $$.c = abc_getproperty2($$.c, &m);
2607 $$.c = abc_getlocal_0($$.c);
2608 $$.c = abc_getslot($$.c, f->slot);
2610 namespace_t ns = {flags2access(f->flags), ""};
2611 multiname_t m = {QNAME, &ns, 0, $1};
2612 $$.c = abc_getlocal_0($$.c);
2613 $$.c = abc_getproperty2($$.c, &m);
2616 if(f->kind == MEMBER_METHOD) {
2617 $$.t = TYPE_FUNCTION(f);
2622 /* look at actual classes, in the current package and imported */
2623 } else if((a = find_class($1))) {
2624 if(a->flags & FLAG_METHOD) {
2626 $$.c = abc_findpropstrict2($$.c, &m);
2627 $$.c = abc_getproperty2($$.c, &m);
2628 $$.t = TYPE_FUNCTION(a->function);
2631 $$.c = abc_getglobalscope($$.c);
2632 $$.c = abc_getslot($$.c, a->slot);
2635 $$.c = abc_getlex2($$.c, &m);
2637 $$.t = TYPE_CLASS(a);
2640 /* unknown object, let the avm2 resolve it */
2642 if(strcmp($1,"trace"))
2643 warning("Couldn't resolve '%s', doing late binding", $1);
2644 state->method->late_binding = 1;
2646 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2649 $$.c = abc_findpropstrict2($$.c, &m);
2650 $$.c = abc_getproperty2($$.c, &m);
2655 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2656 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2657 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2659 // ----------------- namespaces -------------------------------------------------
2661 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2662 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2663 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2665 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}