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);
426 void initialize_parser()
428 global = rfx_calloc(sizeof(global_t));
429 global->file = abc_file_new();
430 global->file->flags &= ~ABCFILE_LAZY;
431 global->variable_count = 1;
432 global->init = abc_initscript(global->file);
433 code_t*c = global->init->method->body->code;
434 c = abc_getlocal_0(c);
435 c = abc_pushscope(c);
436 /*c = abc_findpropstrict(c, "[package]::trace");
437 c = abc_pushstring(c, "[entering global init function]");
438 c = abc_callpropvoid(c, "[package]::trace", 1);*/
439 global->init->method->body->code = c;
442 void initialize_file(char*filename)
445 state->package = filename;
449 if(!state || state->level!=1) {
450 syntaxerror("unexpected end of file");
452 state_destroy(state);state=0;
455 void* finish_parser()
457 code_t*c = global->init->method->body->code;
458 /*c = abc_findpropstrict(c, "[package]::trace");
459 c = abc_pushstring(c, "[leaving global init function]");
460 c = abc_callpropvoid(c, "[package]::trace", 1);*/
461 c = abc_returnvoid(c);
462 global->init->method->body->code = c;
467 static void xx_scopetest()
469 /* findpropstrict doesn't just return a scope object- it
470 also makes it "active" somehow. Push local_0 on the
471 scope stack and read it back with findpropstrict, it'll
472 contain properties like "trace". Trying to find the same
473 property on a "vanilla" local_0 yields only a "undefined" */
474 //c = abc_findpropstrict(c, "[package]::trace");
476 /*c = abc_getlocal_0(c);
477 c = abc_findpropstrict(c, "[package]::trace");
479 c = abc_setlocal_1(c);
481 c = abc_pushbyte(c, 0);
482 c = abc_setlocal_2(c);
484 code_t*xx = c = abc_label(c);
485 c = abc_findpropstrict(c, "[package]::trace");
486 c = abc_pushstring(c, "prop:");
487 c = abc_hasnext2(c, 1, 2);
489 c = abc_setlocal_3(c);
490 c = abc_callpropvoid(c, "[package]::trace", 2);
491 c = abc_getlocal_3(c);
493 c = abc_iftrue(c,xx);*/
497 typedef struct _variable {
503 static variable_t* find_variable(char*name)
509 v = dict_lookup(s->vars, name);
517 static variable_t* find_variable_safe(char*name)
519 variable_t* v = find_variable(name);
521 syntaxerror("undefined variable: %s", name);
524 static char variable_exists(char*name)
526 return dict_lookup(state->vars, name)!=0;
528 code_t*defaultvalue(code_t*c, classinfo_t*type);
529 static int new_variable(char*name, classinfo_t*type, char init)
532 v->index = global->variable_count;
536 dict_put(state->vars, name, v);
538 return global->variable_count++;
540 #define TEMPVARNAME "__as3_temp__"
541 static int gettempvar()
543 variable_t*v = find_variable(TEMPVARNAME);
546 return new_variable(TEMPVARNAME, 0, 0);
549 code_t* var_block(code_t*body)
555 for(t=0;t<state->vars->hashsize;t++) {
556 dictentry_t*e = state->vars->slots[t];
558 variable_t*v = (variable_t*)e->data;
559 if(v->type && v->init) {
560 c = defaultvalue(c, v->type);
561 c = abc_setlocal(c, v->index);
562 k = abc_kill(k, v->index);
572 if(x->opcode== OPCODE___BREAK__ ||
573 x->opcode== OPCODE___CONTINUE__) {
574 /* link kill code before break/continue */
575 code_t*e = code_dup(k);
576 code_t*s = code_start(e);
588 c = code_append(c, body);
589 c = code_append(c, k);
593 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
595 c = code_append(c, header);
596 c = code_append(c, var_block(body));
597 /* append return if necessary */
598 if(!c || c->opcode != OPCODE_RETURNVOID &&
599 c->opcode != OPCODE_RETURNVALUE) {
600 c = abc_returnvoid(c);
606 static void startpackage(char*name)
609 /*printf("entering package \"%s\"\n", name);*/
610 state->package = strdup(name);
611 global->variable_count = 1;
613 static void endpackage()
615 /*printf("leaving package \"%s\"\n", state->package);*/
617 //used e.g. in classinfo_register:
618 //free(state->package);state->package=0;
623 char*as3_globalclass=0;
624 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
627 syntaxerror("inner classes now allowed");
630 global->variable_count = 1;
631 state->cls = rfx_calloc(sizeof(classstate_t));
632 state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
635 classinfo_list_t*mlist=0;
637 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
638 syntaxerror("invalid modifier(s)");
640 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
641 syntaxerror("public and internal not supported at the same time.");
643 /* create the class name, together with the proper attributes */
647 if(!(flags&FLAG_PUBLIC) && !state->package) {
648 access = ACCESS_PRIVATE; package = current_filename;
649 } else if(!(flags&FLAG_PUBLIC) && state->package) {
650 access = ACCESS_PACKAGEINTERNAL; package = state->package;
651 } else if(state->package) {
652 access = ACCESS_PACKAGE; package = state->package;
654 syntaxerror("public classes only allowed inside a package");
657 if(registry_findclass(package, classname)) {
658 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
662 /* build info struct */
663 int num_interfaces = (list_length(implements));
664 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
665 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
667 classinfo_list_t*l = implements;
668 for(l=implements;l;l=l->next) {
669 state->cls->info->interfaces[pos++] = l->classinfo;
672 multiname_t*extends2 = sig2mname(extends);
674 MULTINAME(classname2,state->cls->info);
677 state->cls_init = abc_getlocal_0(state->cls_init);
678 state->cls_init = abc_constructsuper(state->cls_init, 0);
681 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
682 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
683 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
685 state->cls->info->flags |= CLASS_INTERFACE;
686 abc_class_interface(state->cls->abc);
689 abc_class_protectedNS(state->cls->abc, classname);
691 for(mlist=implements;mlist;mlist=mlist->next) {
692 MULTINAME(m, mlist->classinfo);
693 abc_class_add_interface(state->cls->abc, &m);
696 /* now write the construction code for this class */
697 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
699 abc_method_body_t*m = global->init->method->body;
700 __ getglobalscope(m);
701 classinfo_t*s = extends;
706 //TODO: take a look at the current scope stack, maybe
707 // we can re-use something
712 multiname_t*s2 = sig2mname(s);
714 multiname_destroy(s2);
716 __ pushscope(m); count++;
717 m->code = m->code->prev->prev; // invert
719 /* continue appending after last op end */
720 while(m->code && m->code->next) m->code = m->code->next;
722 /* TODO: if this is one of *our* classes, we can also
723 do a getglobalscope/getslot <nr> (which references
724 the init function's slots) */
726 __ getlex2(m, extends2);
728 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
729 stack is not the superclass */
730 __ pushscope(m);count++;
733 /* notice: we get a verify error #1107 if the top element on the scope
734 stack is not the global object */
736 __ pushscope(m);count++;
738 __ newclass(m,state->cls->abc);
742 __ setslot(m, slotindex);
744 /* flash.display.MovieClip handling */
745 if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
746 if(state->package && state->package[0]) {
747 as3_globalclass = concat3(state->package, ".", classname);
749 as3_globalclass = strdup(classname);
752 multiname_destroy(extends2);
755 static void endclass()
757 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
759 c = abc_getlocal_0(c);
760 c = abc_constructsuper(c, 0);
761 state->cls->init = code_append(state->cls->init, c);
763 if(!state->method->late_binding) {
764 // class initialization code uses late binding
766 c = abc_getlocal_0(c);
767 c = abc_pushscope(c);
768 state->cls->static_init = code_append(c, state->cls->static_init);
771 if(state->cls->init) {
772 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
773 m->body->code = wrap_function(0, state->cls->init, m->body->code);
775 if(state->cls->static_init) {
776 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
777 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
780 free(state->cls);state->cls=0;
781 free(state->method);state->method=0;
785 void check_code_for_break(code_t*c)
788 if(c->opcode == OPCODE___BREAK__) {
789 char*name = string_cstr(c->data[0]);
790 syntaxerror("Unresolved \"break %s\"", name);
792 if(c->opcode == OPCODE___CONTINUE__) {
793 char*name = string_cstr(c->data[0]);
794 syntaxerror("Unresolved \"continue %s\"", name);
801 static void check_constant_against_type(classinfo_t*t, constant_t*c)
803 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
804 if(TYPE_IS_NUMBER(t)) {
805 xassert(c->type == CONSTANT_FLOAT
806 || c->type == CONSTANT_INT
807 || c->type == CONSTANT_UINT);
808 } else if(TYPE_IS_UINT(t)) {
809 xassert(c->type == CONSTANT_UINT ||
810 (c->type == CONSTANT_INT && c->i>0));
811 } else if(TYPE_IS_INT(t)) {
812 xassert(c->type == CONSTANT_INT);
813 } else if(TYPE_IS_BOOLEAN(t)) {
814 xassert(c->type == CONSTANT_TRUE
815 || c->type == CONSTANT_FALSE);
820 static int flags2access(int flags)
823 if(flags&FLAG_PUBLIC) {
824 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
825 syntaxerror("invalid combination of access levels");
826 access = ACCESS_PACKAGE;
827 } else if(flags&FLAG_PRIVATE) {
828 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
829 syntaxerror("invalid combination of access levels");
830 access = ACCESS_PRIVATE;
831 } else if(flags&FLAG_PROTECTED) {
832 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
833 syntaxerror("invalid combination of access levels");
834 access = ACCESS_PROTECTED;
836 access = ACCESS_PACKAGEINTERNAL;
842 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
844 memberinfo_t*minfo = 0;
847 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
848 minfo->return_type = return_type;
849 } else if(getset != KW_GET && getset != KW_SET) {
851 if((minfo = registry_findmember(state->cls->info, name, 0))) {
852 if(minfo->parent == state->cls->info) {
853 syntaxerror("class already contains a member/method called '%s'", name);
854 } else if(!minfo->parent) {
855 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
857 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
858 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
861 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
862 minfo->return_type = return_type;
863 // getslot on a member slot only returns "undefined", so no need
864 // to actually store these
865 //state->minfo->slot = state->method->abc->method->trait->slot_id;
867 //class getter/setter
868 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
872 else if(params->list)
873 type = params->list->param->type;
874 // not sure wether to look into superclasses here, too
875 if((minfo=registry_findmember(state->cls->info, name, 0))) {
876 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
877 syntaxerror("class already contains a member or method called '%s'", name);
879 syntaxerror("getter/setter for '%s' already defined", name);
880 /* make a setter or getter into a getset */
885 if(type && minfo->type != type)
886 syntaxerror("different type in getter and setter");
888 minfo = memberinfo_register(state->cls->info, name, gs);
891 /* can't assign a slot as getter and setter might have different slots */
892 //minfo->slot = slot;
894 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
895 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
896 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
897 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
898 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
899 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
903 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
904 params_t*params, classinfo_t*return_type)
906 if(state->method && state->method->info) {
907 syntaxerror("not able to start another method scope");
910 global->variable_count = 0;
911 state->method = rfx_calloc(sizeof(methodstate_t));
912 state->method->has_super = 0;
915 state->method->is_constructor = !strcmp(state->cls->info->name,name);
916 state->cls->has_constructor |= state->method->is_constructor;
918 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
920 state->method->is_global = 1;
921 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
923 new_variable("globalscope", 0, 0);
926 /* state->vars is initialized by state_new */
929 for(p=params->list;p;p=p->next) {
930 new_variable(p->param->name, p->param->type, 0);
932 if(state->method->is_constructor)
933 name = "__as3_constructor__";
934 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
937 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
938 params_t*params, classinfo_t*return_type, code_t*body)
942 multiname_t*type2 = sig2mname(return_type);
944 if(state->method->is_constructor) {
945 f = abc_class_getconstructor(state->cls->abc, type2);
946 } else if(!state->method->is_global) {
947 namespace_t mname_ns = flags2namespace(flags, "");
948 multiname_t mname = {QNAME, &mname_ns, 0, name};
950 if(flags&FLAG_STATIC)
951 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
953 f = abc_class_method(state->cls->abc, type2, &mname);
954 slot = f->trait->slot_id;
956 namespace_t mname_ns = flags2namespace(flags, state->package);
957 multiname_t mname = {QNAME, &mname_ns, 0, name};
959 f = abc_method_new(global->file, type2, 1);
960 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
961 //abc_code_t*c = global->init->method->body->code;
963 //flash doesn't seem to allow us to access function slots
964 //state->method->info->slot = slot;
966 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
967 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
968 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
969 if(params->varargs) f->flags |= METHOD_NEED_REST;
973 for(p=params->list;p;p=p->next) {
974 if(params->varargs && !p->next) {
975 break; //varargs: omit last parameter in function signature
977 multiname_t*m = sig2mname(p->param->type);
978 list_append(f->parameters, m);
979 if(p->param->value) {
980 check_constant_against_type(p->param->type, p->param->value);
981 opt=1;list_append(f->optional_parameters, p->param->value);
983 syntaxerror("non-optional parameter not allowed after optional parameters");
986 check_code_for_break(body);
989 f->body->code = body;
990 f->body->exceptions = state->method->exceptions;
993 syntaxerror("interface methods can't have a method body");
996 free(state->method);state->method=0;
1002 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1007 void breakjumpsto(code_t*c, char*name, code_t*jump)
1010 if(c->opcode == OPCODE___BREAK__) {
1011 string_t*name2 = c->data[0];
1012 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1013 c->opcode = OPCODE_JUMP;
1020 void continuejumpsto(code_t*c, char*name, code_t*jump)
1023 if(c->opcode == OPCODE___CONTINUE__) {
1024 string_t*name2 = c->data[0];
1025 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1026 c->opcode = OPCODE_JUMP;
1034 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1035 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1036 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1038 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1040 if(!type1 || !type2)
1041 return registry_getanytype();
1042 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1043 return registry_getanytype();
1046 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1055 return registry_getanytype();
1057 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1062 return abc_coerce_a(c);
1066 // cast an "any" type to a specific type. subject to
1067 // runtime exceptions
1068 return abc_coerce2(c, &m);
1071 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1072 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1073 // allow conversion between number types
1074 return abc_coerce2(c, &m);
1076 //printf("%s.%s\n", from.package, from.name);
1077 //printf("%s.%s\n", to.package, to.name);
1079 classinfo_t*supertype = from;
1081 if(supertype == to) {
1082 // target type is one of from's superclasses
1083 return abc_coerce2(c, &m);
1086 while(supertype->interfaces[t]) {
1087 if(supertype->interfaces[t]==to) {
1088 // target type is one of from's interfaces
1089 return abc_coerce2(c, &m);
1093 supertype = supertype->superclass;
1095 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1097 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1099 syntaxerror("can't convert type %s to %s", from->name, to->name);
1102 code_t*defaultvalue(code_t*c, classinfo_t*type)
1104 if(TYPE_IS_INT(type)) {
1105 c = abc_pushbyte(c, 0);
1106 } else if(TYPE_IS_UINT(type)) {
1107 c = abc_pushuint(c, 0);
1108 } else if(TYPE_IS_FLOAT(type)) {
1110 } else if(TYPE_IS_BOOLEAN(type)) {
1111 c = abc_pushfalse(c);
1113 //c = abc_pushundefined(c);
1115 c = abc_pushnull(c);
1117 c = abc_coerce2(c, &m);
1122 char is_pushundefined(code_t*c)
1124 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1127 void parserassert(int b)
1129 if(!b) syntaxerror("internal error: assertion failed");
1132 static classinfo_t* find_class(char*name)
1136 c = registry_findclass(state->package, name);
1139 /* try explicit imports */
1140 dictentry_t* e = dict_get_slot(state->imports, name);
1143 if(!strcmp(e->key, name)) {
1144 c = (classinfo_t*)e->data;
1150 /* try package.* imports */
1151 import_list_t*l = state->wildcard_imports;
1153 //printf("does package %s contain a class %s?\n", l->import->package, name);
1154 c = registry_findclass(l->import->package, name);
1159 /* try global package */
1160 c = registry_findclass("", name);
1163 /* try local "filename" package */
1164 c = registry_findclass(current_filename, name);
1170 static char is_getlocal(code_t*c)
1172 if(!c || c->prev || c->next)
1174 return(c->opcode == OPCODE_GETLOCAL
1175 || c->opcode == OPCODE_GETLOCAL_0
1176 || c->opcode == OPCODE_GETLOCAL_1
1177 || c->opcode == OPCODE_GETLOCAL_2
1178 || c->opcode == OPCODE_GETLOCAL_3);
1180 static int getlocalnr(code_t*c)
1182 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1183 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1184 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1185 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1186 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1187 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1190 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1194 [prefix code] [read instruction]
1198 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1201 if(in && in->opcode == OPCODE_COERCE_A) {
1202 in = code_cutlast(in);
1205 syntaxerror("internal error");
1207 /* chop off read instruction */
1211 prefix = r->prev;r->prev = 0;
1217 char use_temp_var = readbefore;
1219 /* generate the write instruction, and maybe append a dup to the prefix code */
1220 code_t* write = abc_nop(0);
1221 if(r->opcode == OPCODE_GETPROPERTY) {
1222 write->opcode = OPCODE_SETPROPERTY;
1223 multiname_t*m = (multiname_t*)r->data[0];
1224 write->data[0] = multiname_clone(m);
1225 if(m->type == QNAME || m->type == MULTINAME) {
1227 prefix = abc_dup(prefix); // we need the object, too
1230 } else if(m->type == MULTINAMEL) {
1232 /* dupping two values on the stack requires 5 operations and one register-
1233 couldn't adobe just have given us a dup2? */
1234 int temp = gettempvar();
1235 prefix = abc_setlocal(prefix, temp);
1236 prefix = abc_dup(prefix);
1237 prefix = abc_getlocal(prefix, temp);
1238 prefix = abc_swap(prefix);
1239 prefix = abc_getlocal(prefix, temp);
1241 prefix = abc_kill(prefix, temp);
1245 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1247 } else if(r->opcode == OPCODE_GETSLOT) {
1248 write->opcode = OPCODE_SETSLOT;
1249 write->data[0] = r->data[0];
1251 prefix = abc_dup(prefix); // we need the object, too
1254 } else if(r->opcode == OPCODE_GETLOCAL) {
1255 write->opcode = OPCODE_SETLOCAL;
1256 write->data[0] = r->data[0];
1257 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1258 write->opcode = OPCODE_SETLOCAL_0;
1259 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1260 write->opcode = OPCODE_SETLOCAL_1;
1261 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1262 write->opcode = OPCODE_SETLOCAL_2;
1263 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1264 write->opcode = OPCODE_SETLOCAL_3;
1266 code_dump(r, 0, 0, "", stdout);
1267 syntaxerror("illegal lvalue: can't assign a value to this expression");
1274 /* with getproperty/getslot, we have to be extra careful not
1275 to execute the read code twice, as it might have side-effects
1276 (e.g. if the property is in fact a setter/getter combination)
1278 So read the value, modify it, and write it again,
1279 using prefix only once and making sure (by using a temporary
1280 register) that the return value is what we just wrote */
1281 temp = gettempvar();
1282 c = code_append(c, prefix);
1283 c = code_append(c, r);
1286 c = abc_setlocal(c, temp);
1288 c = code_append(c, middlepart);
1291 c = abc_setlocal(c, temp);
1293 c = code_append(c, write);
1294 c = abc_getlocal(c, temp);
1295 c = abc_kill(c, temp);
1297 /* if we're allowed to execute the read code twice *and*
1298 the middlepart doesn't modify the code, things are easier.
1300 code_t* r2 = code_dup(r);
1301 //c = code_append(c, prefix);
1302 parserassert(!prefix);
1303 c = code_append(c, r);
1304 c = code_append(c, middlepart);
1305 c = code_append(c, write);
1306 c = code_append(c, r2);
1309 /* even smaller version: overwrite the value without reading
1313 c = code_append(c, prefix);
1316 c = code_append(c, middlepart);
1317 c = code_append(c, write);
1318 c = code_append(c, r);
1320 temp = gettempvar();
1322 c = code_append(c, prefix);
1324 c = code_append(c, middlepart);
1326 c = abc_setlocal(c, temp);
1327 c = code_append(c, write);
1328 c = abc_getlocal(c, temp);
1329 c = abc_kill(c, temp);
1342 /* ------------ code blocks / statements ---------------- */
1344 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1346 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1347 PROGRAM_CODE_LIST: PROGRAM_CODE
1348 | PROGRAM_CODE_LIST PROGRAM_CODE
1350 PROGRAM_CODE: PACKAGE_DECLARATION
1351 | INTERFACE_DECLARATION
1353 | FUNCTION_DECLARATION
1358 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1359 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1360 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1362 INPACKAGE_CODE: INTERFACE_DECLARATION
1364 | FUNCTION_DECLARATION
1369 MAYBECODE: CODE {$$=$1;}
1370 MAYBECODE: {$$=code_new();}
1372 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1373 CODE: CODEPIECE {$$=$1;}
1375 // code which also may appear outside a method
1376 CODE_STATEMENT: IMPORT
1377 CODE_STATEMENT: VOIDEXPRESSION
1379 CODE_STATEMENT: FOR_IN
1380 CODE_STATEMENT: WHILE
1381 CODE_STATEMENT: DO_WHILE
1382 CODE_STATEMENT: SWITCH
1384 CODE_STATEMENT: WITH
1387 // code which may appear anywhere
1388 CODEPIECE: ';' {$$=0;}
1389 CODEPIECE: VARIABLE_DECLARATION
1390 CODEPIECE: CODE_STATEMENT
1396 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1397 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1399 CODEBLOCK : '{' CODE '}' {$$=$2;}
1400 CODEBLOCK : '{' '}' {$$=0;}
1401 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1402 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1404 /* ------------ package init code ------------------- */
1406 PACKAGE_INITCODE: CODE_STATEMENT {
1407 if($1) as3_warning("code ignored");
1410 /* ------------ variables --------------------------- */
1412 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1413 | {$$.c=abc_pushundefined(0);
1417 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1418 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1420 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1421 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1423 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1425 if(variable_exists($1))
1426 syntaxerror("Variable %s already defined", $1);
1428 if(!is_subtype_of($3.t, $2)) {
1429 syntaxerror("Can't convert %s to %s", $3.t->name,
1433 int index = new_variable($1, $2, 1);
1436 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1438 $$ = converttype($$, $3.t, $2);
1439 $$ = abc_setlocal($$, index);
1441 $$ = defaultvalue(0, $2);
1442 $$ = abc_setlocal($$, index);
1445 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1447 $$ = abc_coerce_a($$);
1448 $$ = abc_setlocal($$, index);
1454 /* that's the default for a local register, anyway
1456 state->method->initcode = abc_pushundefined(state->method->initcode);
1457 state->method->initcode = abc_setlocal(state->method->initcode, index);
1459 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1462 /* ------------ control flow ------------------------- */
1464 MAYBEELSE: %prec below_else {$$ = code_new();}
1465 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1466 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1468 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1471 $$ = code_append($$, $4.c);
1472 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1474 $$ = code_append($$, $6);
1476 myjmp = $$ = abc_jump($$, 0);
1478 myif->branch = $$ = abc_nop($$);
1480 $$ = code_append($$, $7);
1481 myjmp->branch = $$ = abc_nop($$);
1487 FOR_INIT : {$$=code_new();}
1488 FOR_INIT : VARIABLE_DECLARATION
1489 FOR_INIT : VOIDEXPRESSION
1490 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1491 $$=$2;new_variable($2,$3,1);
1493 FOR_IN_INIT : T_IDENTIFIER {
1497 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1498 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1500 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1501 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1503 $$ = code_append($$, $2);
1504 code_t*loopstart = $$ = abc_label($$);
1505 $$ = code_append($$, $4.c);
1506 code_t*myif = $$ = abc_iffalse($$, 0);
1507 $$ = code_append($$, $8);
1508 code_t*cont = $$ = abc_nop($$);
1509 $$ = code_append($$, $6);
1510 $$ = abc_jump($$, loopstart);
1511 code_t*out = $$ = abc_nop($$);
1512 breakjumpsto($$, $1.name, out);
1513 continuejumpsto($$, $1.name, cont);
1520 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1521 variable_t*var = find_variable($2);
1522 char*tmp1name = concat2($2, "__tmp1__");
1523 int it = new_variable(tmp1name, TYPE_INT, 0);
1524 char*tmp2name = concat2($2, "__array__");
1525 int array = new_variable(tmp1name, 0, 0);
1528 $$ = code_append($$, $4.c);
1529 $$ = abc_coerce_a($$);
1530 $$ = abc_setlocal($$, array);
1531 $$ = abc_pushbyte($$, 0);
1532 $$ = abc_setlocal($$, it);
1534 code_t*loopstart = $$ = abc_label($$);
1536 $$ = abc_hasnext2($$, array, it);
1537 code_t*myif = $$ = abc_iffalse($$, 0);
1538 $$ = abc_getlocal($$, array);
1539 $$ = abc_getlocal($$, it);
1541 $$ = abc_nextname($$);
1543 $$ = abc_nextvalue($$);
1544 $$ = converttype($$, 0, var->type);
1545 $$ = abc_setlocal($$, var->index);
1547 $$ = code_append($$, $6);
1548 $$ = abc_jump($$, loopstart);
1550 code_t*out = $$ = abc_nop($$);
1551 breakjumpsto($$, $1.name, out);
1552 continuejumpsto($$, $1.name, loopstart);
1563 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1567 code_t*myjmp = $$ = abc_jump($$, 0);
1568 code_t*loopstart = $$ = abc_label($$);
1569 $$ = code_append($$, $6);
1570 code_t*cont = $$ = abc_nop($$);
1571 myjmp->branch = cont;
1572 $$ = code_append($$, $4.c);
1573 $$ = abc_iftrue($$, loopstart);
1574 code_t*out = $$ = abc_nop($$);
1575 breakjumpsto($$, $1, out);
1576 continuejumpsto($$, $1, cont);
1582 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1584 code_t*loopstart = $$ = abc_label($$);
1585 $$ = code_append($$, $3);
1586 code_t*cont = $$ = abc_nop($$);
1587 $$ = code_append($$, $6.c);
1588 $$ = abc_iftrue($$, loopstart);
1589 code_t*out = $$ = abc_nop($$);
1590 breakjumpsto($$, $1, out);
1591 continuejumpsto($$, $1, cont);
1597 BREAK : "break" %prec prec_none {
1598 $$ = abc___break__(0, "");
1600 BREAK : "break" T_IDENTIFIER {
1601 $$ = abc___break__(0, $2);
1603 CONTINUE : "continue" %prec prec_none {
1604 $$ = abc___continue__(0, "");
1606 CONTINUE : "continue" T_IDENTIFIER {
1607 $$ = abc___continue__(0, $2);
1610 MAYBE_CASE_LIST : {$$=0;}
1611 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1612 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1613 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1614 CASE_LIST: CASE {$$=$1}
1615 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1617 CASE: "case" E ':' MAYBECODE {
1619 $$ = code_append($$, $2.c);
1620 code_t*j = $$ = abc_ifne($$, 0);
1621 $$ = code_append($$, $4);
1622 if($$->opcode != OPCODE___BREAK__) {
1623 $$ = abc___fallthrough__($$, "");
1625 code_t*e = $$ = abc_nop($$);
1628 DEFAULT: "default" ':' MAYBECODE {
1631 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1633 $$ = code_append($$, $7);
1634 code_t*out = $$ = abc_pop($$);
1635 breakjumpsto($$, $1, out);
1637 code_t*c = $$,*lastblock=0;
1639 if(c->opcode == OPCODE_IFNE) {
1640 if(!c->next) syntaxerror("internal error in fallthrough handling");
1642 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1644 c->opcode = OPCODE_JUMP;
1645 c->branch = lastblock;
1647 /* fall through end of switch */
1648 c->opcode = OPCODE_NOP;
1658 /* ------------ try / catch /finally ---------------- */
1660 FINALLY: "finally" '{' CODE '}'
1661 MAYBE_FINALLY: | FINALLY
1663 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1665 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1666 multiname_t name = {QNAME, &name_ns, 0, $3};
1668 NEW(abc_exception_t, e)
1669 e->exc_type = sig2mname($4);
1670 e->var_name = multiname_clone(&name);
1674 int i = find_variable_safe($3)->index;
1675 e->target = c = abc_setlocal(0, i);
1676 c = code_append(c, $8);
1684 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1685 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1687 TRY : "try" '{' {new_state();} CODE '}' CATCH_LIST MAYBE_FINALLY {
1688 code_t*start = code_start($4);
1691 code_t*out = abc_nop(0);
1692 code_t*jmp = $$ = abc_jump($$, out);
1694 abc_exception_list_t*l = $6;
1696 abc_exception_t*e = l->abc_exception;
1699 $$ = code_append($$, e->target);
1700 $$ = abc_jump($$, out);
1703 $$ = code_append($$, out);
1706 list_concat(state->method->exceptions, $6);
1712 /* ------------ throw ------------------------------- */
1714 THROW : "throw" EXPRESSION {
1718 THROW : "throw" %prec prec_none {
1719 if(!state->exception_name)
1720 syntaxerror("re-throw only possible within a catch block");
1721 variable_t*v = find_variable(state->exception_name);
1723 $$=abc_getlocal($$, v->index);
1727 /* ------------ with -------------------------------- */
1729 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1731 $$ = abc_pushscope($$);
1732 $$ = code_append($$, $5);
1733 $$ = abc_popscope($$);
1736 /* ------------ packages and imports ---------------- */
1738 X_IDENTIFIER: T_IDENTIFIER
1739 | "package" {$$="package";}
1741 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1742 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1744 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1745 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1747 IMPORT : "import" QNAME {
1750 syntaxerror("Couldn't import class\n");
1751 state_has_imports();
1752 dict_put(state->imports, c->name, c);
1755 IMPORT : "import" PACKAGE '.' '*' {
1758 state_has_imports();
1759 list_append(state->wildcard_imports, i);
1763 /* ------------ classes and interfaces (header) -------------- */
1765 MAYBE_MODIFIERS : {$$=0;}
1766 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1767 MODIFIER_LIST : MODIFIER {$$=$1;}
1768 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1770 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1771 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1772 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1773 | KW_STATIC {$$=FLAG_STATIC;}
1774 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1775 | KW_FINAL {$$=FLAG_FINAL;}
1776 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1777 | KW_NATIVE {$$=FLAG_NATIVE;}
1778 | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1780 EXTENDS : {$$=registry_getobjectclass();}
1781 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1783 EXTENDS_LIST : {$$=list_new();}
1784 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1786 IMPLEMENTS_LIST : {$$=list_new();}
1787 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1789 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1790 EXTENDS IMPLEMENTS_LIST
1791 '{' {startclass($1,$3,$4,$5, 0);}
1793 '}' {endclass();$$=0;}
1795 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1797 '{' {startclass($1,$3,0,$4,1);}
1798 MAYBE_INTERFACE_BODY
1799 '}' {endclass();$$=0;}
1801 /* ------------ classes and interfaces (body) -------------- */
1804 MAYBE_CLASS_BODY : CLASS_BODY
1805 CLASS_BODY : CLASS_BODY_ITEM
1806 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1807 CLASS_BODY_ITEM : ';'
1808 CLASS_BODY_ITEM : SLOT_DECLARATION
1809 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1811 CLASS_BODY_ITEM : CODE_STATEMENT {
1812 code_t*c = state->cls->static_init;
1813 c = code_append(c, $1);
1814 state->cls->static_init = c;
1817 MAYBE_INTERFACE_BODY :
1818 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1819 INTERFACE_BODY : IDECLARATION
1820 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1822 IDECLARATION : "var" T_IDENTIFIER {
1823 syntaxerror("variable declarations not allowed in interfaces");
1825 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1827 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
1828 syntaxerror("invalid method modifiers: interface methods always need to be public");
1830 startfunction(0,$1,$3,$4,&$6,$8);
1831 endfunction(0,$1,$3,$4,&$6,$8, 0);
1834 /* ------------ classes and interfaces (body, slots ) ------- */
1836 VARCONST: "var" | "const"
1838 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1840 memberinfo_t* info = state->cls?
1841 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1842 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1845 info->flags = flags;
1848 namespace_t mname_ns = {flags2access(flags), ""};
1849 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1851 trait_list_t**traits;
1855 traits = &global->init->traits;
1856 code = &global->init->method->body->code;
1857 } else if(flags&FLAG_STATIC) {
1859 traits = &state->cls->abc->static_traits;
1860 code = &state->cls->static_init;
1862 // instance variable
1863 traits = &state->cls->abc->traits;
1864 code = &state->cls->init;
1870 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1872 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1874 info->slot = t->slot_id;
1876 /* initalization code (if needed) */
1878 if($5.c && !is_pushundefined($5.c)) {
1879 c = abc_getlocal_0(c);
1880 c = code_append(c, $5.c);
1881 c = converttype(c, $5.t, $4);
1882 c = abc_setslot(c, t->slot_id);
1885 *code = code_append(*code, c);
1888 t->kind= TRAIT_CONST;
1894 /* ------------ constants -------------------------------------- */
1896 MAYBESTATICCONSTANT: {$$=0;}
1897 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1899 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1900 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1901 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1902 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1903 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1904 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1905 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1906 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1907 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1909 /* ------------ classes and interfaces (body, functions) ------- */
1911 // non-vararg version
1913 memset(&$$,0,sizeof($$));
1915 MAYBE_PARAM_LIST: PARAM_LIST {
1920 MAYBE_PARAM_LIST: "..." PARAM {
1921 memset(&$$,0,sizeof($$));
1923 list_append($$.list, $2);
1925 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1928 list_append($$.list, $4);
1932 PARAM_LIST: PARAM_LIST ',' PARAM {
1934 list_append($$.list, $3);
1937 memset(&$$,0,sizeof($$));
1938 list_append($$.list, $1);
1941 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1942 $$ = malloc(sizeof(param_t));
1947 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1948 $$ = malloc(sizeof(param_t));
1950 $$->type = TYPE_ANY;
1953 GETSET : "get" {$$=$1;}
1957 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1958 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1961 if(state->method->late_binding) {
1962 c = abc_getlocal_0(c);
1963 c = abc_pushscope(c);
1965 if(state->method->is_constructor && !state->method->has_super) {
1966 // call default constructor
1967 c = abc_getlocal_0(c);
1968 c = abc_constructsuper(c, 0);
1970 c = wrap_function(c, 0, $11);
1971 endfunction(0,$1,$3,$4,&$6,$8,c);
1975 /* ------------- package + class ids --------------- */
1977 CLASS: T_IDENTIFIER {
1979 /* try current package */
1980 $$ = find_class($1);
1981 if(!$$) syntaxerror("Could not find class %s\n", $1);
1984 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1985 $$ = registry_findclass($1, $3);
1986 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1990 QNAME: PACKAGEANDCLASS
1993 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1994 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1996 TYPE : QNAME {$$=$1;}
1997 | '*' {$$=registry_getanytype();}
1998 | "void" {$$=registry_getanytype();}
2000 | "String" {$$=registry_getstringclass();}
2001 | "int" {$$=registry_getintclass();}
2002 | "uint" {$$=registry_getuintclass();}
2003 | "Boolean" {$$=registry_getbooleanclass();}
2004 | "Number" {$$=registry_getnumberclass();}
2007 MAYBETYPE: ':' TYPE {$$=$2;}
2010 /* ----------function calls, delete, constructor calls ------ */
2012 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2013 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
2015 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2016 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2017 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2020 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2022 $$.cc = code_append($1.cc, $3.c);
2025 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2030 $$.c = abc_getglobalscope($$.c);
2031 $$.c = abc_getslot($$.c, $2->slot);
2033 $$.c = abc_findpropstrict2($$.c, &m);
2036 $$.c = code_append($$.c, $3.cc);
2039 $$.c = abc_construct($$.c, $3.len);
2041 $$.c = abc_constructprop2($$.c, &m, $3.len);
2045 /* TODO: use abc_call (for calling local variables),
2046 abc_callstatic (for calling own methods)
2049 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2052 if($$.c->opcode == OPCODE_COERCE_A) {
2053 $$.c = code_cutlast($$.c);
2055 code_t*paramcode = $3.cc;
2058 if($$.c->opcode == OPCODE_GETPROPERTY) {
2059 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2060 $$.c = code_cutlast($$.c);
2061 $$.c = code_append($$.c, paramcode);
2062 $$.c = abc_callproperty2($$.c, name, $3.len);
2063 multiname_destroy(name);
2064 } else if($$.c->opcode == OPCODE_GETSLOT) {
2065 int slot = (int)(ptroff_t)$$.c->data[0];
2066 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2067 if(t->kind!=TRAIT_METHOD) {
2068 //ok: flash allows to assign closures to members.
2070 multiname_t*name = t->name;
2071 $$.c = code_cutlast($$.c);
2072 $$.c = code_append($$.c, paramcode);
2073 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2074 $$.c = abc_callproperty2($$.c, name, $3.len);
2075 } else if($$.c->opcode == OPCODE_GETSUPER) {
2076 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2077 $$.c = code_cutlast($$.c);
2078 $$.c = code_append($$.c, paramcode);
2079 $$.c = abc_callsuper2($$.c, name, $3.len);
2080 multiname_destroy(name);
2082 $$.c = abc_getlocal_0($$.c);
2083 $$.c = code_append($$.c, paramcode);
2084 $$.c = abc_call($$.c, $3.len);
2089 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2090 $$.t = $1.t->function->return_type;
2092 $$.c = abc_coerce_a($$.c);
2097 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2098 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2099 if(!state->method) syntaxerror("super() not allowed outside of a function");
2100 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2103 $$.c = abc_getlocal_0($$.c);
2105 $$.c = code_append($$.c, $3.cc);
2107 this is dependent on the control path, check this somewhere else
2108 if(state->method->has_super)
2109 syntaxerror("constructor may call super() only once");
2111 state->method->has_super = 1;
2112 $$.c = abc_constructsuper($$.c, $3.len);
2113 $$.c = abc_pushundefined($$.c);
2117 DELETE: "delete" E {
2119 if($$.c->opcode == OPCODE_COERCE_A) {
2120 $$.c = code_cutlast($$.c);
2122 multiname_t*name = 0;
2123 if($$.c->opcode == OPCODE_GETPROPERTY) {
2124 $$.c->opcode = OPCODE_DELETEPROPERTY;
2125 } else if($$.c->opcode == OPCODE_GETSLOT) {
2126 int slot = (int)(ptroff_t)$$.c->data[0];
2127 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2128 $$.c = code_cutlast($$.c);
2129 $$.c = abc_deleteproperty2($$.c, name);
2131 $$.c = abc_getlocal_0($$.c);
2132 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2133 $$.c = abc_deleteproperty2($$.c, &m);
2135 $$.t = TYPE_BOOLEAN;
2138 RETURN: "return" %prec prec_none {
2139 $$ = abc_returnvoid(0);
2141 RETURN: "return" EXPRESSION {
2143 $$ = abc_returnvalue($$);
2146 // ----------------------- expression types -------------------------------------
2148 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2149 EXPRESSION : E %prec below_minus {$$ = $1;}
2150 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2152 $$.c = cut_last_push($$.c);
2153 $$.c = code_append($$.c,$3.c);
2156 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2157 $$=cut_last_push($1.c);
2160 // ----------------------- expression evaluation -------------------------------------
2162 //V : CONSTANT {$$ = 0;}
2164 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2165 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2166 //V : NEW {$$ = $1.c;}
2168 //V : DELETE {$$ = $1.c;}
2169 E : DELETE {$$ = $1;}
2173 namespace_t ns = {ACCESS_PACKAGE, ""};
2174 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2176 $$.c = abc_getlex2($$.c, &m);
2177 $$.c = abc_pushstring($$.c, $1.pattern);
2178 $$.c = abc_construct($$.c, 1);
2180 $$.c = abc_getlex2($$.c, &m);
2181 $$.c = abc_pushstring($$.c, $1.pattern);
2182 $$.c = abc_pushstring($$.c, $1.options);
2183 $$.c = abc_construct($$.c, 2);
2188 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2189 //MULTINAME(m, registry_getintclass());
2190 //$$.c = abc_coerce2($$.c, &m); // FIXME
2193 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2196 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2199 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2202 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2205 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2208 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2211 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2212 $$.t = TYPE_BOOLEAN;
2214 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2215 $$.t = TYPE_BOOLEAN;
2217 CONSTANT : "null" {$$.c = abc_pushnull(0);
2222 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2223 $$.t = TYPE_BOOLEAN;
2225 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2226 $$.t = TYPE_BOOLEAN;
2228 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2229 $$.t = TYPE_BOOLEAN;
2231 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2232 $$.t = TYPE_BOOLEAN;
2234 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2235 $$.t = TYPE_BOOLEAN;
2237 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2238 $$.t = TYPE_BOOLEAN;
2240 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2241 $$.t = TYPE_BOOLEAN;
2243 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2244 $$.t = TYPE_BOOLEAN;
2247 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2249 $$.c = converttype($$.c, $1.t, $$.t);
2250 $$.c = abc_dup($$.c);
2251 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2252 $$.c = cut_last_push($$.c);
2253 $$.c = code_append($$.c,$3.c);
2254 $$.c = converttype($$.c, $3.t, $$.t);
2255 code_t*label = $$.c = abc_label($$.c);
2256 jmp->branch = label;
2259 $$.t = join_types($1.t, $3.t, 'A');
2260 /*printf("%08x:\n",$1.t);
2261 code_dump($1.c, 0, 0, "", stdout);
2262 printf("%08x:\n",$3.t);
2263 code_dump($3.c, 0, 0, "", stdout);
2264 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2266 $$.c = converttype($$.c, $1.t, $$.t);
2267 $$.c = abc_dup($$.c);
2268 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2269 $$.c = cut_last_push($$.c);
2270 $$.c = code_append($$.c,$3.c);
2271 $$.c = converttype($$.c, $3.t, $$.t);
2272 code_t*label = $$.c = abc_label($$.c);
2273 jmp->branch = label;
2276 E : '!' E {$$.c=$2.c;
2277 $$.c = abc_not($$.c);
2278 $$.t = TYPE_BOOLEAN;
2281 E : '~' E {$$.c=$2.c;
2282 $$.c = abc_bitnot($$.c);
2286 E : E '&' E {$$.c = code_append($1.c,$3.c);
2287 $$.c = abc_bitand($$.c);
2291 E : E '^' E {$$.c = code_append($1.c,$3.c);
2292 $$.c = abc_bitxor($$.c);
2296 E : E '|' E {$$.c = code_append($1.c,$3.c);
2297 $$.c = abc_bitor($$.c);
2301 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2302 $$.c = abc_rshift($$.c);
2305 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2306 $$.c = abc_urshift($$.c);
2309 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2310 $$.c = abc_lshift($$.c);
2314 E : E '/' E {$$.c = code_append($1.c,$3.c);
2315 $$.c = abc_divide($$.c);
2318 E : E '%' E {$$.c = code_append($1.c,$3.c);
2319 $$.c = abc_modulo($$.c);
2322 E : E '+' E {$$.c = code_append($1.c,$3.c);
2323 if(BOTH_INT($1.t, $3.t)) {
2324 $$.c = abc_add_i($$.c);
2327 $$.c = abc_add($$.c);
2328 $$.t = join_types($1.t,$3.t,'+');
2331 E : E '-' E {$$.c = code_append($1.c,$3.c);
2332 if(BOTH_INT($1.t,$3.t)) {
2333 $$.c = abc_subtract_i($$.c);
2336 $$.c = abc_subtract($$.c);
2340 E : E '*' E {$$.c = code_append($1.c,$3.c);
2341 if(BOTH_INT($1.t,$3.t)) {
2342 $$.c = abc_multiply_i($$.c);
2345 $$.c = abc_multiply($$.c);
2350 E : E "in" E {$$.c = code_append($1.c,$3.c);
2351 $$.c = abc_in($$.c);
2352 $$.t = TYPE_BOOLEAN;
2355 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2356 if(use_astype && TYPE_IS_CLASS($3.t)) {
2357 MULTINAME(m,$3.t->cls);
2358 $$.c = abc_astype2($1.c, &m);
2361 $$.c = code_append($1.c, $3.c);
2362 $$.c = abc_astypelate($$.c);
2367 E : E "instanceof" E
2368 {$$.c = code_append($1.c, $3.c);
2369 $$.c = abc_instanceof($$.c);
2370 $$.t = TYPE_BOOLEAN;
2373 E : E "is" E {$$.c = code_append($1.c, $3.c);
2374 $$.c = abc_istypelate($$.c);
2375 $$.t = TYPE_BOOLEAN;
2378 E : "typeof" '(' E ')' {
2380 $$.c = abc_typeof($$.c);
2385 $$.c = cut_last_push($2.c);
2386 $$.c = abc_pushundefined($$.c);
2390 E : "void" { $$.c = abc_pushundefined(0);
2394 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2399 $$.c=abc_negate_i($$.c);
2402 $$.c=abc_negate($$.c);
2409 $$.c = code_append($$.c, $3.c);
2411 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2412 $$.c = abc_getproperty2($$.c, &m);
2413 $$.t = 0; // array elements have unknown type
2416 E : '[' MAYBE_EXPRESSION_LIST ']' {
2418 $$.c = code_append($$.c, $2.cc);
2419 $$.c = abc_newarray($$.c, $2.len);
2420 $$.t = registry_getarrayclass();
2423 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2424 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2426 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2428 $$.cc = code_append($$.cc, $1.c);
2429 $$.cc = code_append($$.cc, $3.c);
2432 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2435 $$.cc = code_append($$.cc, $3.c);
2436 $$.cc = code_append($$.cc, $5.c);
2441 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2443 $$.c = code_append($$.c, $2.cc);
2444 $$.c = abc_newobject($$.c, $2.len/2);
2445 $$.t = registry_getobjectclass();
2450 if(BOTH_INT($1.t,$3.t)) {
2451 c=abc_multiply_i(c);
2455 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2456 $$.c = toreadwrite($1.c, c, 0, 0);
2461 code_t*c = abc_modulo($3.c);
2462 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2463 $$.c = toreadwrite($1.c, c, 0, 0);
2467 code_t*c = abc_lshift($3.c);
2468 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2469 $$.c = toreadwrite($1.c, c, 0, 0);
2473 code_t*c = abc_rshift($3.c);
2474 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2475 $$.c = toreadwrite($1.c, c, 0, 0);
2479 code_t*c = abc_urshift($3.c);
2480 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2481 $$.c = toreadwrite($1.c, c, 0, 0);
2485 code_t*c = abc_divide($3.c);
2486 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2487 $$.c = toreadwrite($1.c, c, 0, 0);
2491 code_t*c = abc_bitor($3.c);
2492 c=converttype(c, TYPE_INT, $1.t);
2493 $$.c = toreadwrite($1.c, c, 0, 0);
2499 if(TYPE_IS_INT($1.t)) {
2503 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2506 $$.c = toreadwrite($1.c, c, 0, 0);
2509 E : E "-=" E { code_t*c = $3.c;
2510 if(TYPE_IS_INT($1.t)) {
2511 c=abc_subtract_i(c);
2514 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2517 $$.c = toreadwrite($1.c, c, 0, 0);
2520 E : E '=' E { code_t*c = 0;
2521 c = code_append(c, $3.c);
2522 c = converttype(c, $3.t, $1.t);
2523 $$.c = toreadwrite($1.c, c, 1, 0);
2527 E : E '?' E ':' E %prec below_assignment {
2528 $$.t = join_types($3.t,$5.t,'?');
2530 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2531 $$.c = code_append($$.c, $3.c);
2532 $$.c = converttype($$.c, $3.t, $$.t);
2533 code_t*j2 = $$.c = abc_jump($$.c, 0);
2534 $$.c = j1->branch = abc_label($$.c);
2535 $$.c = code_append($$.c, $5.c);
2536 $$.c = converttype($$.c, $3.t, $$.t);
2537 $$.c = j2->branch = abc_label($$.c);
2540 E : E "++" { code_t*c = 0;
2541 classinfo_t*type = $1.t;
2542 if(is_getlocal($1.c) && TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t)) {
2543 int nr = getlocalnr($1.c);
2544 code_free($1.c);$1.c=0;
2545 if(TYPE_IS_INT($1.t)) {
2546 $$.c = abc_getlocal(0, nr);
2547 $$.c = abc_inclocal_i($$.c, nr);
2548 } else if(TYPE_IS_NUMBER($1.t)) {
2549 $$.c = abc_getlocal(0, nr);
2550 $$.c = abc_inclocal($$.c, nr);
2551 } else syntaxerror("internal error");
2553 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2554 c=abc_increment_i(c);
2560 c=converttype(c, type, $1.t);
2561 $$.c = toreadwrite($1.c, c, 0, 1);
2566 // TODO: use inclocal, like with ++
2567 E : E "--" { code_t*c = 0;
2568 classinfo_t*type = $1.t;
2569 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2570 c=abc_decrement_i(c);
2576 c=converttype(c, type, $1.t);
2577 $$.c = toreadwrite($1.c, c, 0, 1);
2581 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2582 classinfo_t*type = $2.t;
2583 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2584 c=abc_increment_i(c);
2590 c=converttype(c, type, $2.t);
2591 $$.c = toreadwrite($2.c, c, 0, 0);
2595 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2596 classinfo_t*type = $2.t;
2597 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2598 c=abc_decrement_i(c);
2604 c=converttype(c, type, $2.t);
2605 $$.c = toreadwrite($2.c, c, 0, 0);
2609 E : "super" '.' T_IDENTIFIER
2610 { if(!state->cls->info)
2611 syntaxerror("super keyword not allowed outside a class");
2612 classinfo_t*t = state->cls->info->superclass;
2613 if(!t) t = TYPE_OBJECT;
2615 memberinfo_t*f = registry_findmember(t, $3, 1);
2616 namespace_t ns = flags2namespace(f->flags, "");
2617 MEMBER_MULTINAME(m, f, $3);
2619 $$.c = abc_getlocal_0($$.c);
2620 $$.c = abc_getsuper2($$.c, &m);
2621 $$.t = memberinfo_gettype(f);
2624 E : E '.' T_IDENTIFIER
2626 classinfo_t*t = $1.t;
2628 if(TYPE_IS_CLASS(t) && t->cls) {
2633 memberinfo_t*f = registry_findmember(t, $3, 1);
2635 if(f && !is_static != !(f->flags&FLAG_STATIC))
2637 if(f && f->slot && !noslot) {
2638 $$.c = abc_getslot($$.c, f->slot);
2640 MEMBER_MULTINAME(m, f, $3);
2641 $$.c = abc_getproperty2($$.c, &m);
2643 /* determine type */
2644 $$.t = memberinfo_gettype(f);
2646 $$.c = abc_coerce_a($$.c);
2648 /* when resolving a property on an unknown type, we do know the
2649 name of the property (and don't seem to need the package), but
2650 we need to make avm2 try out all access modes */
2651 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2652 $$.c = abc_getproperty2($$.c, &m);
2653 $$.c = abc_coerce_a($$.c);
2654 $$.t = registry_getanytype();
2658 VAR_READ : T_IDENTIFIER {
2665 /* look at variables */
2666 if((v = find_variable($1))) {
2667 // $1 is a local variable
2668 $$.c = abc_getlocal($$.c, v->index);
2671 /* look at current class' members */
2672 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2673 // $1 is a function in this class
2674 int var_is_static = (f->flags&FLAG_STATIC);
2675 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2676 if(var_is_static != i_am_static) {
2677 /* there doesn't seem to be any "static" way to access
2678 static properties of a class */
2679 state->method->late_binding = 1;
2681 namespace_t ns = {flags2access(f->flags), ""};
2682 multiname_t m = {QNAME, &ns, 0, $1};
2683 $$.c = abc_findpropstrict2($$.c, &m);
2684 $$.c = abc_getproperty2($$.c, &m);
2687 $$.c = abc_getlocal_0($$.c);
2688 $$.c = abc_getslot($$.c, f->slot);
2690 namespace_t ns = {flags2access(f->flags), ""};
2691 multiname_t m = {QNAME, &ns, 0, $1};
2692 $$.c = abc_getlocal_0($$.c);
2693 $$.c = abc_getproperty2($$.c, &m);
2696 if(f->kind == MEMBER_METHOD) {
2697 $$.t = TYPE_FUNCTION(f);
2702 /* look at actual classes, in the current package and imported */
2703 } else if((a = find_class($1))) {
2704 if(a->flags & FLAG_METHOD) {
2706 $$.c = abc_findpropstrict2($$.c, &m);
2707 $$.c = abc_getproperty2($$.c, &m);
2708 if(a->function->kind == MEMBER_METHOD) {
2709 $$.t = TYPE_FUNCTION(a->function);
2711 $$.t = a->function->type;
2715 $$.c = abc_getglobalscope($$.c);
2716 $$.c = abc_getslot($$.c, a->slot);
2719 $$.c = abc_getlex2($$.c, &m);
2721 $$.t = TYPE_CLASS(a);
2724 /* unknown object, let the avm2 resolve it */
2726 if(strcmp($1,"trace"))
2727 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
2728 state->method->late_binding = 1;
2730 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2733 $$.c = abc_findpropstrict2($$.c, &m);
2734 $$.c = abc_getproperty2($$.c, &m);
2739 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2740 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2741 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2743 // ----------------- namespaces -------------------------------------------------
2745 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2746 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2747 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2749 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}