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;
66 %token<id> T_IDENTIFIER
68 %token<token> T_REGEXP
70 %token<number_int> T_INT
71 %token<number_uint> T_UINT
72 %token<number_uint> T_BYTE
73 %token<number_uint> T_SHORT
74 %token<number_float> T_FLOAT
76 %token<id> T_FOR "for"
77 %token<id> T_WHILE "while"
79 %token<id> T_SWITCH "switch"
81 %token<token> KW_IMPLEMENTS "implements"
82 %token<token> KW_NAMESPACE "namespace"
83 %token<token> KW_PACKAGE "package"
84 %token<token> KW_PROTECTED "protected"
85 %token<token> KW_PUBLIC "public"
86 %token<token> KW_PRIVATE "private"
87 %token<token> KW_USE "use"
88 %token<token> KW_INTERNAL "internal"
89 %token<token> KW_NEW "new"
90 %token<token> KW_NATIVE "native"
91 %token<token> KW_FUNCTION "function"
92 %token<token> KW_UNDEFINED "undefined"
93 %token<token> KW_CONTINUE "continue"
94 %token<token> KW_CLASS "class"
95 %token<token> KW_CONST "const"
96 %token<token> KW_CATCH "catch"
97 %token<token> KW_CASE "case"
98 %token<token> KW_SET "set"
99 %token<token> KW_VOID "void"
100 %token<token> KW_THROW "throw"
101 %token<token> KW_STATIC "static"
102 %token<token> KW_WITH "with"
103 %token<token> KW_INSTANCEOF "instanceof"
104 %token<token> KW_IMPORT "import"
105 %token<token> KW_RETURN "return"
106 %token<token> KW_TYPEOF "typeof"
107 %token<token> KW_INTERFACE "interface"
108 %token<token> KW_NULL "null"
109 %token<token> KW_VAR "var"
110 %token<token> KW_DYNAMIC "dynamic"
111 %token<token> KW_OVERRIDE "override"
112 %token<token> KW_FINAL "final"
113 %token<token> KW_EACH "each"
114 %token<token> KW_GET "get"
115 %token<token> KW_TRY "try"
116 %token<token> KW_SUPER "super"
117 %token<token> KW_EXTENDS "extends"
118 %token<token> KW_FALSE "false"
119 %token<token> KW_TRUE "true"
120 %token<token> KW_BOOLEAN "Boolean"
121 %token<token> KW_UINT "uint"
122 %token<token> KW_INT "int"
123 %token<token> KW_NUMBER "Number"
124 %token<token> KW_STRING "String"
125 %token<token> KW_DEFAULT "default"
126 %token<token> KW_DELETE "delete"
127 %token<token> KW_IF "if"
128 %token<token> KW_ELSE "else"
129 %token<token> KW_BREAK "break"
130 %token<token> KW_IS "is"
131 %token<token> KW_IN "in"
132 %token<token> KW_AS "as"
134 %token<token> T_EQEQ "=="
135 %token<token> T_EQEQEQ "==="
136 %token<token> T_NE "!="
137 %token<token> T_NEE "!=="
138 %token<token> T_LE "<="
139 %token<token> T_GE ">="
140 %token<token> T_DIVBY "/="
141 %token<token> T_MODBY "%="
142 %token<token> T_MULBY "*="
143 %token<token> T_PLUSBY "+="
144 %token<token> T_MINUSBY "-="
145 %token<token> T_SHRBY ">>="
146 %token<token> T_SHLBY "<<="
147 %token<token> T_USHRBY ">>>="
148 %token<token> T_OROR "||"
149 %token<token> T_ANDAND "&&"
150 %token<token> T_COLONCOLON "::"
151 %token<token> T_MINUSMINUS "--"
152 %token<token> T_PLUSPLUS "++"
153 %token<token> T_DOTDOT ".."
154 %token<token> T_DOTDOTDOT "..."
155 %token<token> T_SHL "<<"
156 %token<token> T_USHR ">>>"
157 %token<token> T_SHR ">>"
159 %type <for_start> FOR_START
160 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
161 %type <token> VARCONST
163 %type <code> CODEPIECE CODE_STATEMENT
164 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
165 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
166 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
167 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
168 %type <exception> CATCH
169 %type <exception_list> CATCH_LIST
170 %type <code> CLASS_DECLARATION
171 %type <code> NAMESPACE_DECLARATION
172 %type <code> INTERFACE_DECLARATION
173 %type <code> VOIDEXPRESSION
174 %type <value> EXPRESSION NONCOMMAEXPRESSION
175 %type <value> MAYBEEXPRESSION
176 %type <value> E DELETE
177 %type <value> CONSTANT
178 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
179 %type <token> USE_NAMESPACE
180 %type <code> FOR_INIT
182 %type <classinfo> MAYBETYPE
185 %type <params> PARAM_LIST
186 %type <params> MAYBE_PARAM_LIST
187 %type <flags> MAYBE_MODIFIERS
188 %type <flags> MODIFIER_LIST
189 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
190 %type <classinfo_list> IMPLEMENTS_LIST
191 %type <classinfo> EXTENDS
192 %type <classinfo_list> EXTENDS_LIST
193 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
194 %type <classinfo_list> QNAME_LIST
195 %type <classinfo> TYPE
196 //%type <token> VARIABLE
197 %type <value> VAR_READ
199 //%type <token> T_IDENTIFIER
200 %type <token> MODIFIER
201 %type <value> FUNCTIONCALL
202 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
204 // precedence: from low to high
208 %left below_semicolon
211 %nonassoc below_assignment // for ?:, contrary to spec
212 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
219 %nonassoc "==" "!=" "===" "!=="
220 %nonassoc "is" "as" "in"
221 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
222 %left "<<" ">>" ">>>"
226 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
228 %nonassoc below_curly
229 %left '[' ']' '{' "new" '.' ".." "::"
230 %nonassoc T_IDENTIFIER
231 %left above_identifier
236 // needed for "return" precedence:
237 %nonassoc T_STRING T_REGEXP
238 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
239 %nonassoc "false" "true" "null" "undefined" "super"
245 static int yyerror(char*s)
247 syntaxerror("%s", s);
250 static char* concat2(const char* t1, const char* t2)
254 char*text = malloc(l1+l2+1);
255 memcpy(text , t1, l1);
256 memcpy(text+l1, t2, l2);
260 static char* concat3(const char* t1, const char* t2, const char* t3)
265 char*text = malloc(l1+l2+l3+1);
266 memcpy(text , t1, l1);
267 memcpy(text+l1, t2, l2);
268 memcpy(text+l1+l2, t3, l3);
273 typedef struct _import {
277 DECLARE_LIST(import);
279 typedef struct _classstate {
285 char has_constructor;
288 typedef struct _methodstate {
292 /* code that needs to be executed at the start of
293 a method (like initializing local registers) */
298 abc_exception_list_t*exceptions;
301 typedef struct _state {
306 import_list_t*wildcard_imports;
308 char has_own_imports;
311 methodstate_t*method;
318 typedef struct _global {
325 static global_t*global = 0;
326 static state_t* state = 0;
330 #define MULTINAME(m,x) \
333 registry_fill_multiname(&m, &m##_ns, x);
335 #define MEMBER_MULTINAME(m,f,n) \
339 m##_ns.access = flags2access(f->flags); \
343 m.namespace_set = 0; \
346 m.type = MULTINAME; \
348 m.namespace_set = &nopackage_namespace_set; \
352 /* warning: list length of namespace set is undefined */
353 #define MULTINAME_LATE(m, access, package) \
354 namespace_t m##_ns = {access, package}; \
355 namespace_set_t m##_nsset; \
356 namespace_list_t m##_l;m##_l.next = 0; \
357 m##_nsset.namespaces = &m##_l; \
358 m##_nsset = m##_nsset; \
359 m##_l.namespace = &m##_ns; \
360 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
362 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
363 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
364 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
365 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
366 static namespace_list_t nl4 = {&ns4,0};
367 static namespace_list_t nl3 = {&ns3,&nl4};
368 static namespace_list_t nl2 = {&ns2,&nl3};
369 static namespace_list_t nl1 = {&ns1,&nl2};
370 static namespace_set_t nopackage_namespace_set = {&nl1};
372 static void new_state()
375 state_t*oldstate = state;
377 memcpy(s, state, sizeof(state_t)); //shallow copy
379 s->imports = dict_new();
383 state->has_own_imports = 0;
384 state->vars = dict_new();
385 state->old = oldstate;
387 static void state_has_imports()
389 state->wildcard_imports = list_clone(state->wildcard_imports);
390 state->imports = dict_clone(state->imports);
391 state->has_own_imports = 1;
394 static void state_destroy(state_t*state)
396 if(state->has_own_imports) {
397 list_free(state->wildcard_imports);
398 dict_destroy(state->imports);state->imports=0;
400 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
401 dict_destroy(state->imports);state->imports=0;
405 for(t=0;t<state->vars->hashsize;t++) {
406 dictentry_t*e =state->vars->slots[t];
408 free(e->data);e->data=0;
412 dict_destroy(state->vars);state->vars=0;
418 static void old_state()
420 if(!state || !state->old)
421 syntaxerror("invalid nesting");
422 state_t*leaving = state;
424 /*if(state->method->initcode) {
425 printf("residual initcode\n");
426 code_dump(state->method->initcode, 0, 0, "", stdout);
428 state_destroy(leaving);
430 void initialize_state()
432 global = rfx_calloc(sizeof(global_t));
435 state->package = current_filename;
437 global->file = abc_file_new();
438 global->file->flags &= ~ABCFILE_LAZY;
439 global->variable_count = 1;
441 global->init = abc_initscript(global->file, 0);
442 code_t*c = global->init->method->body->code;
444 c = abc_getlocal_0(c);
445 c = abc_pushscope(c);
447 /* findpropstrict doesn't just return a scope object- it
448 also makes it "active" somehow. Push local_0 on the
449 scope stack and read it back with findpropstrict, it'll
450 contain properties like "trace". Trying to find the same
451 property on a "vanilla" local_0 yields only a "undefined" */
452 //c = abc_findpropstrict(c, "[package]::trace");
454 /*c = abc_getlocal_0(c);
455 c = abc_findpropstrict(c, "[package]::trace");
457 c = abc_setlocal_1(c);
459 c = abc_pushbyte(c, 0);
460 c = abc_setlocal_2(c);
462 code_t*xx = c = abc_label(c);
463 c = abc_findpropstrict(c, "[package]::trace");
464 c = abc_pushstring(c, "prop:");
465 c = abc_hasnext2(c, 1, 2);
467 c = abc_setlocal_3(c);
468 c = abc_callpropvoid(c, "[package]::trace", 2);
469 c = abc_getlocal_3(c);
471 c = abc_iftrue(c,xx);*/
473 c = abc_findpropstrict(c, "[package]::trace");
474 c = abc_pushstring(c, "[entering global init function]");
475 c = abc_callpropvoid(c, "[package]::trace", 1);
477 global->init->method->body->code = c;
479 void* finalize_state()
481 if(state->level!=1) {
482 syntaxerror("unexpected end of file");
484 abc_method_body_t*m = global->init->method->body;
487 __ findpropstrict(m, "[package]::trace");
488 __ pushstring(m, "[leaving global init function]");
489 __ callpropvoid(m, "[package]::trace", 1);
492 state_destroy(state);
498 static void startpackage(char*name)
501 /*printf("entering package \"%s\"\n", name);*/
502 state->package = strdup(name);
503 global->variable_count = 1;
505 static void endpackage()
507 /*printf("leaving package \"%s\"\n", state->package);*/
509 //used e.g. in classinfo_register:
510 //free(state->package);state->package=0;
516 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
519 syntaxerror("inner classes now allowed");
522 global->variable_count = 1;
523 state->cls = rfx_calloc(sizeof(classstate_t));
526 classinfo_list_t*mlist=0;
527 /*printf("entering class %s\n", name);
528 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
530 printf(" extends: %s.%s\n", extends->package, extends->name);
531 printf(" implements (%d): ", list_length(implements));
532 for(mlist=implements;mlist;mlist=mlist->next) {
533 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
538 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
539 syntaxerror("invalid modifier(s)");
541 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
542 syntaxerror("public and internal not supported at the same time.");
544 /* create the class name, together with the proper attributes */
548 if(!(flags&FLAG_PUBLIC) && !state->package) {
549 access = ACCESS_PRIVATE; package = current_filename;
550 } else if(!(flags&FLAG_PUBLIC) && state->package) {
551 access = ACCESS_PACKAGEINTERNAL; package = state->package;
552 } else if(state->package) {
553 access = ACCESS_PACKAGE; package = state->package;
555 syntaxerror("public classes only allowed inside a package");
558 if(registry_findclass(package, classname)) {
559 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
563 /* build info struct */
564 int num_interfaces = (list_length(implements));
565 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
566 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
568 classinfo_list_t*l = implements;
569 for(l=implements;l;l=l->next) {
570 state->cls->info->interfaces[pos++] = l->classinfo;
573 multiname_t*extends2 = sig2mname(extends);
575 MULTINAME(classname2,state->cls->info);
578 state->cls_init = abc_getlocal_0(state->cls_init);
579 state->cls_init = abc_constructsuper(state->cls_init, 0);
582 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
583 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
584 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
586 state->cls->info->flags |= CLASS_INTERFACE;
587 abc_class_interface(state->cls->abc);
590 abc_class_protectedNS(state->cls->abc, classname);
592 for(mlist=implements;mlist;mlist=mlist->next) {
593 MULTINAME(m, mlist->classinfo);
594 abc_class_add_interface(state->cls->abc, &m);
597 /* now write the construction code for this class */
598 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
600 abc_method_body_t*m = global->init->method->body;
601 __ getglobalscope(m);
602 classinfo_t*s = extends;
607 //TODO: take a look at the current scope stack, maybe
608 // we can re-use something
613 multiname_t*s2 = sig2mname(s);
615 multiname_destroy(s2);
617 __ pushscope(m); count++;
618 m->code = m->code->prev->prev; // invert
620 /* continue appending after last op end */
621 while(m->code && m->code->next) m->code = m->code->next;
623 /* TODO: if this is one of *our* classes, we can also
624 do a getglobalscope/getslot <nr> (which references
625 the init function's slots) */
627 __ getlex2(m, extends2);
629 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
630 stack is not the superclass */
631 __ pushscope(m);count++;
634 /* notice: we get a verify error #1107 if the top element on the scope
635 stack is not the global object */
637 __ pushscope(m);count++;
639 __ newclass(m,state->cls->abc);
643 __ setslot(m, slotindex);
645 /* flash.display.MovieClip handling */
646 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
647 if(state->package && state->package[0]) {
648 globalclass = concat3(state->package, ".", classname);
650 globalclass = strdup(classname);
653 multiname_destroy(extends2);
656 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
658 c = code_append(c, initcode);
659 c = code_append(c, body);
660 /* append return if necessary */
661 if(!c || c->opcode != OPCODE_RETURNVOID &&
662 c->opcode != OPCODE_RETURNVALUE) {
663 c = abc_returnvoid(c);
668 static void endclass()
670 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
672 c = abc_getlocal_0(c);
673 c = abc_constructsuper(c, 0);
674 state->cls->init = code_append(state->cls->init, c);
677 if(state->cls->init) {
678 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
679 m->body->code = wrap_function(0, state->cls->init, m->body->code);
681 if(state->cls->static_init) {
682 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
683 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
685 // handy for scope testing
689 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
692 free(state->cls);state->cls=0;
696 typedef struct _variable {
701 static variable_t* find_variable(char*name)
707 v = dict_lookup(s->vars, name);
715 static variable_t* find_variable_safe(char*name)
717 variable_t* v = find_variable(name);
719 syntaxerror("undefined variable: %s", name);
722 static char variable_exists(char*name)
724 return dict_lookup(state->vars, name)!=0;
726 code_t*defaultvalue(code_t*c, classinfo_t*type);
727 static int new_variable(char*name, classinfo_t*type, char init)
730 v->index = global->variable_count;
733 dict_put(state->vars, name, v);
735 if(init && state->method && type) {
736 /* if this is a typed variable:
737 push default value for type on stack at the very beginning of the
738 method, so that it always has that type regardless of the control
740 state->method->initcode = defaultvalue(state->method->initcode, type);
741 state->method->initcode = abc_setlocal(state->method->initcode, v->index);
743 return global->variable_count++;
745 #define TEMPVARNAME "__as3_temp__"
746 static int gettempvar()
748 variable_t*v = find_variable(TEMPVARNAME);
751 return new_variable(TEMPVARNAME, 0, 0);
754 code_t* killvars(code_t*c)
757 for(t=0;t<state->vars->hashsize;t++) {
758 dictentry_t*e =state->vars->slots[t];
760 variable_t*v = (variable_t*)e->data;
761 //do this always, otherwise register types don't match
762 //in the verifier when doing nested loops
763 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
764 c = abc_kill(c, v->index);
771 void check_code_for_break(code_t*c)
774 if(c->opcode == OPCODE___BREAK__) {
775 char*name = string_cstr(c->data[0]);
776 syntaxerror("Unresolved \"break %s\"", name);
778 if(c->opcode == OPCODE___CONTINUE__) {
779 char*name = string_cstr(c->data[0]);
780 syntaxerror("Unresolved \"continue %s\"", name);
787 static void check_constant_against_type(classinfo_t*t, constant_t*c)
789 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
790 if(TYPE_IS_NUMBER(t)) {
791 xassert(c->type == CONSTANT_FLOAT
792 || c->type == CONSTANT_INT
793 || c->type == CONSTANT_UINT);
794 } else if(TYPE_IS_UINT(t)) {
795 xassert(c->type == CONSTANT_UINT ||
796 (c->type == CONSTANT_INT && c->i>0));
797 } else if(TYPE_IS_INT(t)) {
798 xassert(c->type == CONSTANT_INT);
799 } else if(TYPE_IS_BOOLEAN(t)) {
800 xassert(c->type == CONSTANT_TRUE
801 || c->type == CONSTANT_FALSE);
805 static int flags2access(int flags)
808 if(flags&FLAG_PUBLIC) {
809 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
810 access = ACCESS_PACKAGE;
811 } else if(flags&FLAG_PRIVATE) {
812 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
813 access = ACCESS_PRIVATE;
814 } else if(flags&FLAG_PROTECTED) {
815 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
816 access = ACCESS_PROTECTED;
818 access = ACCESS_PACKAGEINTERNAL;
823 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
825 memberinfo_t*minfo = 0;
828 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
829 minfo->return_type = return_type;
830 } else if(getset != KW_GET && getset != KW_SET) {
832 if((minfo = registry_findmember(state->cls->info, name, 0))) {
833 if(minfo->parent == state->cls->info) {
834 syntaxerror("class already contains a member/method called '%s'", name);
835 } else if(!minfo->parent) {
836 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
838 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
839 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
842 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
843 minfo->return_type = return_type;
844 // getslot on a member slot only returns "undefined", so no need
845 // to actually store these
846 //state->minfo->slot = state->method->abc->method->trait->slot_id;
848 //class getter/setter
849 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
853 else if(params->list)
854 type = params->list->param->type;
855 // not sure wether to look into superclasses here, too
856 if((minfo=registry_findmember(state->cls->info, name, 0))) {
857 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
858 syntaxerror("class already contains a member or method called '%s'", name);
860 syntaxerror("getter/setter for '%s' already defined", name);
861 /* make a setter or getter into a getset */
866 if(type && minfo->type != type)
867 syntaxerror("different type in getter and setter");
869 minfo = memberinfo_register(state->cls->info, name, gs);
872 /* can't assign a slot as getter and setter might have different slots */
873 //minfo->slot = slot;
875 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
876 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
877 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
878 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
879 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
880 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
884 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
885 params_t*params, classinfo_t*return_type)
888 syntaxerror("not able to start another method scope");
891 global->variable_count = 0;
892 state->method = rfx_calloc(sizeof(methodstate_t));
893 state->method->initcode = 0;
894 state->method->has_super = 0;
896 state->method->is_constructor = !strcmp(state->cls->info->name,name);
897 state->cls->has_constructor |= state->method->is_constructor;
899 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
901 state->method->is_global = 1;
902 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
904 new_variable("globalscope", 0, 0);
907 /* state->vars is initialized by state_new */
910 for(p=params->list;p;p=p->next) {
911 new_variable(p->param->name, p->param->type, 0);
913 if(state->method->is_constructor)
914 name = "__as3_constructor__";
915 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
918 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
919 params_t*params, classinfo_t*return_type, code_t*body)
923 multiname_t*type2 = sig2mname(return_type);
925 if(state->method->is_constructor) {
926 f = abc_class_getconstructor(state->cls->abc, type2);
927 } else if(!state->method->is_global) {
928 namespace_t mname_ns = {flags2access(flags), ""};
929 multiname_t mname = {QNAME, &mname_ns, 0, name};
931 if(flags&FLAG_STATIC)
932 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
934 f = abc_class_method(state->cls->abc, type2, &mname);
935 slot = f->trait->slot_id;
937 namespace_t mname_ns = {flags2access(flags), state->package};
938 multiname_t mname = {QNAME, &mname_ns, 0, name};
940 f = abc_method_new(global->file, type2, 1);
941 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
942 //abc_code_t*c = global->init->method->body->code;
944 //flash doesn't seem to allow us to access function slots
945 //state->method->info->slot = slot;
947 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
948 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
949 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
950 if(params->varargs) f->flags |= METHOD_NEED_REST;
954 for(p=params->list;p;p=p->next) {
955 if(params->varargs && !p->next) {
956 break; //varargs: omit last parameter in function signature
958 multiname_t*m = sig2mname(p->param->type);
959 list_append(f->parameters, m);
960 if(p->param->value) {
961 check_constant_against_type(p->param->type, p->param->value);
962 opt=1;list_append(f->optional_parameters, p->param->value);
964 syntaxerror("non-optional parameter not allowed after optional parameters");
967 check_code_for_break(body);
970 f->body->code = body;
971 f->body->exceptions = state->method->exceptions;
974 syntaxerror("interface methods can't have a method body");
977 free(state->method);state->method=0;
983 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
988 void breakjumpsto(code_t*c, char*name, code_t*jump)
991 if(c->opcode == OPCODE___BREAK__) {
992 string_t*name2 = c->data[0];
993 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
994 c->opcode = OPCODE_JUMP;
1001 void continuejumpsto(code_t*c, char*name, code_t*jump)
1004 if(c->opcode == OPCODE___CONTINUE__) {
1005 string_t*name2 = c->data[0];
1006 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1007 c->opcode = OPCODE_JUMP;
1015 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1017 if(!type1 || !type2)
1018 return registry_getanytype();
1019 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1020 return registry_getanytype();
1023 return registry_getanytype();
1025 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1030 return abc_coerce_a(c);
1034 // cast an "any" type to a specific type. subject to
1035 // runtime exceptions
1036 return abc_coerce2(c, &m);
1039 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1040 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1041 // allow conversion between number types
1042 return abc_coerce2(c, &m);
1044 //printf("%s.%s\n", from.package, from.name);
1045 //printf("%s.%s\n", to.package, to.name);
1047 classinfo_t*supertype = from;
1049 if(supertype == to) {
1050 // target type is one of from's superclasses
1051 return abc_coerce2(c, &m);
1054 while(supertype->interfaces[t]) {
1055 if(supertype->interfaces[t]==to) {
1056 // target type is one of from's interfaces
1057 return abc_coerce2(c, &m);
1061 supertype = supertype->superclass;
1063 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1065 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1067 syntaxerror("can't convert type %s to %s", from->name, to->name);
1070 code_t*defaultvalue(code_t*c, classinfo_t*type)
1072 if(TYPE_IS_INT(type)) {
1073 c = abc_pushbyte(c, 0);
1074 } else if(TYPE_IS_UINT(type)) {
1075 c = abc_pushuint(c, 0);
1076 } else if(TYPE_IS_FLOAT(type)) {
1078 } else if(TYPE_IS_BOOLEAN(type)) {
1079 c = abc_pushfalse(c);
1081 c = abc_pushnull(c);
1086 char is_pushundefined(code_t*c)
1088 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1091 void parserassert(int b)
1093 if(!b) syntaxerror("internal error: assertion failed");
1096 static classinfo_t* find_class(char*name)
1100 c = registry_findclass(state->package, name);
1103 /* try explicit imports */
1104 dictentry_t* e = dict_get_slot(state->imports, name);
1107 if(!strcmp(e->key, name)) {
1108 c = (classinfo_t*)e->data;
1114 /* try package.* imports */
1115 import_list_t*l = state->wildcard_imports;
1117 //printf("does package %s contain a class %s?\n", l->import->package, name);
1118 c = registry_findclass(l->import->package, name);
1123 /* try global package */
1124 c = registry_findclass("", name);
1127 /* try local "filename" package */
1128 c = registry_findclass(current_filename, name);
1134 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1138 [prefix code] [read instruction]
1142 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1145 if(in && in->opcode == OPCODE_COERCE_A) {
1146 in = code_cutlast(in);
1149 syntaxerror("internal error");
1151 /* chop off read instruction */
1155 prefix = r->prev;r->prev = 0;
1161 char use_temp_var = readbefore;
1163 /* generate the write instruction, and maybe append a dup to the prefix code */
1164 code_t* write = abc_nop(0);
1165 if(r->opcode == OPCODE_GETPROPERTY) {
1166 write->opcode = OPCODE_SETPROPERTY;
1167 multiname_t*m = (multiname_t*)r->data[0];
1168 write->data[0] = multiname_clone(m);
1169 if(m->type == QNAME || m->type == MULTINAME) {
1171 prefix = abc_dup(prefix); // we need the object, too
1174 } else if(m->type == MULTINAMEL) {
1176 /* dupping two values on the stack requires 5 operations and one register-
1177 couldn't adobe just have given us a dup2? */
1178 int temp = gettempvar();
1179 prefix = abc_setlocal(prefix, temp);
1180 prefix = abc_dup(prefix);
1181 prefix = abc_getlocal(prefix, temp);
1182 prefix = abc_swap(prefix);
1183 prefix = abc_getlocal(prefix, temp);
1185 prefix = abc_kill(prefix, temp);
1189 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1191 } else if(r->opcode == OPCODE_GETSLOT) {
1192 write->opcode = OPCODE_SETSLOT;
1193 write->data[0] = r->data[0];
1195 prefix = abc_dup(prefix); // we need the object, too
1198 } else if(r->opcode == OPCODE_GETLOCAL) {
1199 write->opcode = OPCODE_SETLOCAL;
1200 write->data[0] = r->data[0];
1201 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1202 write->opcode = OPCODE_SETLOCAL_0;
1203 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1204 write->opcode = OPCODE_SETLOCAL_1;
1205 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1206 write->opcode = OPCODE_SETLOCAL_2;
1207 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1208 write->opcode = OPCODE_SETLOCAL_3;
1210 code_dump(r, 0, 0, "", stdout);
1211 syntaxerror("illegal lvalue: can't assign a value to this expression");
1218 /* with getproperty/getslot, we have to be extra careful not
1219 to execute the read code twice, as it might have side-effects
1220 (e.g. if the property is in fact a setter/getter combination)
1222 So read the value, modify it, and write it again,
1223 using prefix only once and making sure (by using a temporary
1224 register) that the return value is what we just wrote */
1225 temp = gettempvar();
1226 c = code_append(c, prefix);
1227 c = code_append(c, r);
1230 c = abc_setlocal(c, temp);
1232 c = code_append(c, middlepart);
1235 c = abc_setlocal(c, temp);
1237 c = code_append(c, write);
1238 c = abc_getlocal(c, temp);
1239 c = abc_kill(c, temp);
1241 /* if we're allowed to execute the read code twice *and*
1242 the middlepart doesn't modify the code, things are easier.
1244 code_t* r2 = code_dup(r);
1245 //c = code_append(c, prefix);
1246 parserassert(!prefix);
1247 c = code_append(c, r);
1248 c = code_append(c, middlepart);
1249 c = code_append(c, write);
1250 c = code_append(c, r2);
1253 /* even smaller version: overwrite the value without reading
1257 c = code_append(c, prefix);
1260 c = code_append(c, middlepart);
1261 c = code_append(c, write);
1262 c = code_append(c, r);
1264 temp = gettempvar();
1266 c = code_append(c, prefix);
1268 c = code_append(c, middlepart);
1270 c = abc_setlocal(c, temp);
1271 c = code_append(c, write);
1272 c = abc_getlocal(c, temp);
1273 c = abc_kill(c, temp);
1280 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1281 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1288 /* ------------ code blocks / statements ---------------- */
1290 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1292 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1293 PROGRAM_CODE_LIST: PROGRAM_CODE
1294 | PROGRAM_CODE_LIST PROGRAM_CODE
1296 PROGRAM_CODE: PACKAGE_DECLARATION
1297 | INTERFACE_DECLARATION
1299 | FUNCTION_DECLARATION
1304 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1305 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1306 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1308 INPACKAGE_CODE: INTERFACE_DECLARATION
1310 | FUNCTION_DECLARATION
1315 MAYBECODE: CODE {$$=$1;}
1316 MAYBECODE: {$$=code_new();}
1318 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1319 CODE: CODEPIECE {$$=$1;}
1321 // code which also may appear outside a method
1322 CODE_STATEMENT: IMPORT
1323 CODE_STATEMENT: VOIDEXPRESSION
1325 CODE_STATEMENT: FOR_IN
1326 CODE_STATEMENT: WHILE
1327 CODE_STATEMENT: DO_WHILE
1328 CODE_STATEMENT: SWITCH
1330 CODE_STATEMENT: WITH
1333 // code which may appear anywhere
1334 CODEPIECE: ';' {$$=0;}
1335 CODEPIECE: VARIABLE_DECLARATION
1336 CODEPIECE: CODE_STATEMENT
1342 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1343 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1345 CODEBLOCK : '{' CODE '}' {$$=$2;}
1346 CODEBLOCK : '{' '}' {$$=0;}
1347 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1348 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1350 /* ------------ package init code ------------------- */
1352 PACKAGE_INITCODE: CODE_STATEMENT {
1353 if($1) warning("code ignored");
1356 /* ------------ variables --------------------------- */
1358 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1359 | {$$.c=abc_pushundefined(0);
1363 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1364 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1366 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1367 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1369 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1371 if(variable_exists($1))
1372 syntaxerror("Variable %s already defined", $1);
1374 if(!is_subtype_of($3.t, $2)) {
1375 syntaxerror("Can't convert %s to %s", $3.t->name,
1379 int index = new_variable($1, $2, 1);
1382 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1384 $$ = converttype($$, $3.t, $2);
1385 $$ = abc_setlocal($$, index);
1387 $$ = defaultvalue(0, $2);
1388 $$ = abc_setlocal($$, index);
1391 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1393 $$ = abc_coerce_a($$);
1394 $$ = abc_setlocal($$, index);
1400 /* that's the default for a local register, anyway
1402 state->method->initcode = abc_pushundefined(state->method->initcode);
1403 state->method->initcode = abc_setlocal(state->method->initcode, index);
1405 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1408 /* ------------ control flow ------------------------- */
1410 MAYBEELSE: %prec below_else {$$ = code_new();}
1411 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1412 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1414 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1416 $$ = code_append($$, $4.c);
1417 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1419 $$ = code_append($$, $6);
1421 myjmp = $$ = abc_jump($$, 0);
1423 myif->branch = $$ = abc_nop($$);
1425 $$ = code_append($$, $7);
1426 myjmp->branch = $$ = abc_nop($$);
1429 $$ = killvars($$);old_state();
1432 FOR_INIT : {$$=code_new();}
1433 FOR_INIT : VARIABLE_DECLARATION
1434 FOR_INIT : VOIDEXPRESSION
1435 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1436 $$=$2;new_variable($2,$3,1);
1438 FOR_IN_INIT : T_IDENTIFIER {
1442 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1443 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1445 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1446 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1448 $$ = code_append($$, $2);
1449 code_t*loopstart = $$ = abc_label($$);
1450 $$ = code_append($$, $4.c);
1451 code_t*myif = $$ = abc_iffalse($$, 0);
1452 $$ = code_append($$, $8);
1453 code_t*cont = $$ = abc_nop($$);
1454 $$ = code_append($$, $6);
1455 $$ = abc_jump($$, loopstart);
1456 code_t*out = $$ = abc_nop($$);
1457 breakjumpsto($$, $1.name, out);
1458 continuejumpsto($$, $1.name, cont);
1461 $$ = killvars($$);old_state();
1464 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1465 variable_t*var = find_variable($2);
1466 char*tmp1name = concat2($2, "__tmp1__");
1467 int it = new_variable(tmp1name, TYPE_INT, 0);
1468 char*tmp2name = concat2($2, "__array__");
1469 int array = new_variable(tmp1name, 0, 0);
1472 $$ = code_append($$, $4.c);
1473 $$ = abc_coerce_a($$);
1474 $$ = abc_setlocal($$, array);
1475 $$ = abc_pushbyte($$, 0);
1476 $$ = abc_setlocal($$, it);
1478 code_t*loopstart = $$ = abc_label($$);
1480 $$ = abc_hasnext2($$, array, it);
1481 code_t*myif = $$ = abc_iffalse($$, 0);
1482 $$ = abc_getlocal($$, array);
1483 $$ = abc_getlocal($$, it);
1485 $$ = abc_nextname($$);
1487 $$ = abc_nextvalue($$);
1488 $$ = converttype($$, 0, var->type);
1489 $$ = abc_setlocal($$, var->index);
1491 $$ = code_append($$, $6);
1492 $$ = abc_jump($$, loopstart);
1494 code_t*out = $$ = abc_nop($$);
1495 breakjumpsto($$, $1.name, out);
1496 continuejumpsto($$, $1.name, loopstart);
1507 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1510 code_t*myjmp = $$ = abc_jump($$, 0);
1511 code_t*loopstart = $$ = abc_label($$);
1512 $$ = code_append($$, $6);
1513 code_t*cont = $$ = abc_nop($$);
1514 myjmp->branch = cont;
1515 $$ = code_append($$, $4.c);
1516 $$ = abc_iftrue($$, loopstart);
1517 code_t*out = $$ = abc_nop($$);
1518 breakjumpsto($$, $1, out);
1519 continuejumpsto($$, $1, cont);
1525 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1527 code_t*loopstart = $$ = abc_label($$);
1528 $$ = code_append($$, $3);
1529 code_t*cont = $$ = abc_nop($$);
1530 $$ = code_append($$, $6.c);
1531 $$ = abc_iftrue($$, loopstart);
1532 code_t*out = $$ = abc_nop($$);
1533 breakjumpsto($$, $1, out);
1534 continuejumpsto($$, $1, cont);
1539 BREAK : "break" %prec prec_none {
1540 $$ = abc___break__(0, "");
1542 BREAK : "break" T_IDENTIFIER {
1543 $$ = abc___break__(0, $2);
1545 CONTINUE : "continue" %prec prec_none {
1546 $$ = abc___continue__(0, "");
1548 CONTINUE : "continue" T_IDENTIFIER {
1549 $$ = abc___continue__(0, $2);
1552 MAYBE_CASE_LIST : {$$=0;}
1553 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1554 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1555 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1556 CASE_LIST: CASE {$$=$1}
1557 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1559 CASE: "case" E ':' MAYBECODE {
1561 $$ = code_append($$, $2.c);
1562 code_t*j = $$ = abc_ifne($$, 0);
1563 $$ = code_append($$, $4);
1564 if($$->opcode != OPCODE___BREAK__) {
1565 $$ = abc___fallthrough__($$, "");
1567 code_t*e = $$ = abc_nop($$);
1570 DEFAULT: "default" ':' MAYBECODE {
1573 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1575 $$ = code_append($$, $7);
1576 code_t*out = $$ = abc_pop($$);
1577 breakjumpsto($$, $1, out);
1579 code_t*c = $$,*lastblock=0;
1581 if(c->opcode == OPCODE_IFNE) {
1582 if(!c->next) syntaxerror("internal error in fallthrough handling");
1584 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1586 c->opcode = OPCODE_JUMP;
1587 c->branch = lastblock;
1589 /* fall through end of switch */
1590 c->opcode = OPCODE_NOP;
1598 /* ------------ try / catch /finally ---------------- */
1600 FINALLY: "finally" '{' CODE '}'
1601 MAYBE_FINALLY: | FINALLY
1603 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1606 int i = find_variable_safe($3)->index;
1607 c = abc_setlocal(c, i);
1608 c = code_append(c, $8);
1611 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1612 multiname_t name = {QNAME, &name_ns, 0, $3};
1614 NEW(abc_exception_t, e)
1615 e->exc_type = sig2mname($4);
1616 e->var_name = multiname_clone(&name);
1617 e->target = code_start(c);
1622 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1623 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1625 TRY : "try" '{' CODE '}' CATCH_LIST MAYBE_FINALLY {
1626 code_t*start = code_start($3);
1629 code_t*out = abc_nop(0);
1630 code_t*jmp = $$ = abc_jump($$, out);
1632 abc_exception_list_t*l = $5;
1634 abc_exception_t*e = l->abc_exception;
1637 $$ = code_append($$, e->target);
1638 $$ = abc_jump($$, out);
1641 $$ = code_append($$, out);
1644 list_concat(state->method->exceptions, $5);
1647 /* ------------ throw ------------------------------- */
1649 THROW : "throw" EXPRESSION {
1653 THROW : "throw" %prec prec_none {
1654 if(!state->exception_name)
1655 syntaxerror("re-throw only possible within a catch block");
1656 variable_t*v = find_variable(state->exception_name);
1658 $$=abc_getlocal($$, v->index);
1662 /* ------------ with -------------------------------- */
1664 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1666 $$ = abc_pushscope($$);
1667 $$ = code_append($$, $5);
1668 $$ = abc_popscope($$);
1671 /* ------------ packages and imports ---------------- */
1673 X_IDENTIFIER: T_IDENTIFIER
1674 | "package" {$$="package";}
1676 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1677 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1679 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1680 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1682 IMPORT : "import" QNAME {
1685 syntaxerror("Couldn't import class\n");
1686 state_has_imports();
1687 dict_put(state->imports, c->name, c);
1690 IMPORT : "import" PACKAGE '.' '*' {
1693 state_has_imports();
1694 list_append(state->wildcard_imports, i);
1698 /* ------------ classes and interfaces (header) -------------- */
1700 MAYBE_MODIFIERS : {$$=0;}
1701 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1702 MODIFIER_LIST : MODIFIER {$$=$1;}
1703 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1705 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1706 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1707 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1708 | KW_STATIC {$$=FLAG_STATIC;}
1709 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1710 | KW_FINAL {$$=FLAG_FINAL;}
1711 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1712 | KW_NATIVE {$$=FLAG_NATIVE;}
1713 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1715 EXTENDS : {$$=registry_getobjectclass();}
1716 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1718 EXTENDS_LIST : {$$=list_new();}
1719 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1721 IMPLEMENTS_LIST : {$$=list_new();}
1722 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1724 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1725 EXTENDS IMPLEMENTS_LIST
1726 '{' {startclass($1,$3,$4,$5, 0);}
1728 '}' {endclass();$$=0;}
1730 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1732 '{' {startclass($1,$3,0,$4,1);}
1733 MAYBE_INTERFACE_BODY
1734 '}' {endclass();$$=0;}
1736 /* ------------ classes and interfaces (body) -------------- */
1739 MAYBE_CLASS_BODY : CLASS_BODY
1740 CLASS_BODY : CLASS_BODY_ITEM
1741 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1742 CLASS_BODY_ITEM : ';'
1743 CLASS_BODY_ITEM : SLOT_DECLARATION
1744 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1746 CLASS_BODY_ITEM : CODE_STATEMENT {
1747 code_t*c = state->cls->static_init;
1748 c = code_append(c, $1);
1749 state->cls->static_init = c;
1752 MAYBE_INTERFACE_BODY :
1753 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1754 INTERFACE_BODY : IDECLARATION
1755 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1757 IDECLARATION : "var" T_IDENTIFIER {
1758 syntaxerror("variable declarations not allowed in interfaces");
1760 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1762 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1763 syntaxerror("invalid method modifiers: interface methods always need to be public");
1765 startfunction(0,$1,$3,$4,&$6,$8);
1766 endfunction(0,$1,$3,$4,&$6,$8, 0);
1769 /* ------------ classes and interfaces (body, slots ) ------- */
1771 VARCONST: "var" | "const"
1773 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1775 memberinfo_t* info = state->cls?
1776 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1777 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1780 info->flags = flags;
1783 namespace_t mname_ns = {flags2access(flags), ""};
1784 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1786 trait_list_t**traits;
1790 traits = &global->init->traits;
1791 code = &global->init->method->body->code;
1792 } else if(flags&FLAG_STATIC) {
1794 traits = &state->cls->abc->static_traits;
1795 code = &state->cls->static_init;
1797 // instance variable
1798 traits = &state->cls->abc->traits;
1799 code = &state->cls->init;
1805 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1807 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1809 info->slot = t->slot_id;
1811 /* initalization code (if needed) */
1813 if($5.c && !is_pushundefined($5.c)) {
1814 c = abc_getlocal_0(c);
1815 c = code_append(c, $5.c);
1816 c = converttype(c, $5.t, $4);
1817 c = abc_setslot(c, t->slot_id);
1820 *code = code_append(*code, c);
1823 t->kind= TRAIT_CONST;
1829 /* ------------ constants -------------------------------------- */
1831 MAYBESTATICCONSTANT: {$$=0;}
1832 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1834 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1835 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1836 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1837 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1838 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1839 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1840 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1841 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1842 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1844 /* ------------ classes and interfaces (body, functions) ------- */
1846 // non-vararg version
1848 memset(&$$,0,sizeof($$));
1850 MAYBE_PARAM_LIST: PARAM_LIST {
1855 MAYBE_PARAM_LIST: "..." PARAM {
1856 memset(&$$,0,sizeof($$));
1858 list_append($$.list, $2);
1860 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1863 list_append($$.list, $4);
1867 PARAM_LIST: PARAM_LIST ',' PARAM {
1869 list_append($$.list, $3);
1872 memset(&$$,0,sizeof($$));
1873 list_append($$.list, $1);
1876 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1877 $$ = malloc(sizeof(param_t));
1882 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1883 $$ = malloc(sizeof(param_t));
1885 $$->type = TYPE_ANY;
1888 GETSET : "get" {$$=$1;}
1892 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1893 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1896 if(state->method->late_binding) {
1897 c = abc_getlocal_0(c);
1898 c = abc_pushscope(c);
1900 if(state->method->is_constructor && !state->method->has_super) {
1901 // call default constructor
1902 c = abc_getlocal_0(c);
1903 c = abc_constructsuper(c, 0);
1905 c = wrap_function(c, state->method->initcode, $11);
1906 endfunction(0,$1,$3,$4,&$6,$8,c);
1910 /* ------------- package + class ids --------------- */
1912 CLASS: T_IDENTIFIER {
1914 /* try current package */
1915 $$ = find_class($1);
1916 if(!$$) syntaxerror("Could not find class %s\n", $1);
1919 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1920 $$ = registry_findclass($1, $3);
1921 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1925 QNAME: PACKAGEANDCLASS
1928 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1929 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1931 TYPE : QNAME {$$=$1;}
1932 | '*' {$$=registry_getanytype();}
1933 | "void" {$$=registry_getanytype();}
1935 | "String" {$$=registry_getstringclass();}
1936 | "int" {$$=registry_getintclass();}
1937 | "uint" {$$=registry_getuintclass();}
1938 | "Boolean" {$$=registry_getbooleanclass();}
1939 | "Number" {$$=registry_getnumberclass();}
1942 MAYBETYPE: ':' TYPE {$$=$2;}
1945 /* ----------function calls, delete, constructor calls ------ */
1947 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
1948 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1950 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1951 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1952 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
1955 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1957 $$.cc = code_append($1.cc, $3.c);
1960 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1965 $$.c = abc_getglobalscope($$.c);
1966 $$.c = abc_getslot($$.c, $2->slot);
1968 $$.c = abc_findpropstrict2($$.c, &m);
1971 $$.c = code_append($$.c, $3.cc);
1974 $$.c = abc_construct($$.c, $3.len);
1976 $$.c = abc_constructprop2($$.c, &m, $3.len);
1980 /* TODO: use abc_call (for calling local variables),
1981 abc_callstatic (for calling own methods)
1984 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1987 if($$.c->opcode == OPCODE_COERCE_A) {
1988 $$.c = code_cutlast($$.c);
1990 code_t*paramcode = $3.cc;
1993 if($$.c->opcode == OPCODE_GETPROPERTY) {
1994 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1995 $$.c = code_cutlast($$.c);
1996 $$.c = code_append($$.c, paramcode);
1997 $$.c = abc_callproperty2($$.c, name, $3.len);
1998 multiname_destroy(name);
1999 } else if($$.c->opcode == OPCODE_GETSLOT) {
2000 int slot = (int)(ptroff_t)$$.c->data[0];
2001 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2002 if(t->kind!=TRAIT_METHOD) {
2003 //ok: flash allows to assign closures to members.
2005 multiname_t*name = t->name;
2006 $$.c = code_cutlast($$.c);
2007 $$.c = code_append($$.c, paramcode);
2008 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2009 $$.c = abc_callproperty2($$.c, name, $3.len);
2010 } else if($$.c->opcode == OPCODE_GETSUPER) {
2011 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2012 $$.c = code_cutlast($$.c);
2013 $$.c = code_append($$.c, paramcode);
2014 $$.c = abc_callsuper2($$.c, name, $3.len);
2015 multiname_destroy(name);
2017 $$.c = abc_getlocal_0($$.c);
2018 $$.c = code_append($$.c, paramcode);
2019 $$.c = abc_call($$.c, $3.len);
2024 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2025 $$.t = $1.t->function->return_type;
2027 $$.c = abc_coerce_a($$.c);
2032 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2033 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2034 if(!state->method) syntaxerror("super() not allowed outside of a function");
2035 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2038 $$.c = abc_getlocal_0($$.c);
2040 $$.c = code_append($$.c, $3.cc);
2042 this is dependent on the control path, check this somewhere else
2043 if(state->method->has_super)
2044 syntaxerror("constructor may call super() only once");
2046 state->method->has_super = 1;
2047 $$.c = abc_constructsuper($$.c, $3.len);
2048 $$.c = abc_pushundefined($$.c);
2052 DELETE: "delete" E {
2054 if($$.c->opcode == OPCODE_COERCE_A) {
2055 $$.c = code_cutlast($$.c);
2057 multiname_t*name = 0;
2058 if($$.c->opcode == OPCODE_GETPROPERTY) {
2059 $$.c->opcode = OPCODE_DELETEPROPERTY;
2060 } else if($$.c->opcode == OPCODE_GETSLOT) {
2061 int slot = (int)(ptroff_t)$$.c->data[0];
2062 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2063 $$.c = code_cutlast($$.c);
2064 $$.c = abc_deleteproperty2($$.c, name);
2066 $$.c = abc_getlocal_0($$.c);
2067 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2068 $$.c = abc_deleteproperty2($$.c, &m);
2070 $$.t = TYPE_BOOLEAN;
2073 RETURN: "return" %prec prec_none {
2074 $$ = abc_returnvoid(0);
2076 RETURN: "return" EXPRESSION {
2078 $$ = abc_returnvalue($$);
2081 // ----------------------- expression types -------------------------------------
2083 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2084 EXPRESSION : E %prec below_minus {$$ = $1;}
2085 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2087 $$.c = cut_last_push($$.c);
2088 $$.c = code_append($$.c,$3.c);
2091 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2092 $$=cut_last_push($1.c);
2095 // ----------------------- expression evaluation -------------------------------------
2098 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2100 E : DELETE {$$ = $1;}
2101 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
2105 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2106 //MULTINAME(m, registry_getintclass());
2107 //$$.c = abc_coerce2($$.c, &m); // FIXME
2110 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2113 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2116 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2119 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2122 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2125 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2128 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2129 $$.t = TYPE_BOOLEAN;
2131 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2132 $$.t = TYPE_BOOLEAN;
2134 CONSTANT : "null" {$$.c = abc_pushnull(0);
2139 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2140 $$.t = TYPE_BOOLEAN;
2142 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2143 $$.t = TYPE_BOOLEAN;
2145 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2146 $$.t = TYPE_BOOLEAN;
2148 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2149 $$.t = TYPE_BOOLEAN;
2151 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2152 $$.t = TYPE_BOOLEAN;
2154 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2155 $$.t = TYPE_BOOLEAN;
2157 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2158 $$.t = TYPE_BOOLEAN;
2160 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2161 $$.t = TYPE_BOOLEAN;
2164 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2166 $$.c = converttype($$.c, $1.t, $$.t);
2167 $$.c = abc_dup($$.c);
2168 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2169 $$.c = cut_last_push($$.c);
2170 $$.c = code_append($$.c,$3.c);
2171 $$.c = converttype($$.c, $3.t, $$.t);
2172 code_t*label = $$.c = abc_label($$.c);
2173 jmp->branch = label;
2176 $$.t = join_types($1.t, $3.t, 'A');
2177 /*printf("%08x:\n",$1.t);
2178 code_dump($1.c, 0, 0, "", stdout);
2179 printf("%08x:\n",$3.t);
2180 code_dump($3.c, 0, 0, "", stdout);
2181 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2183 $$.c = converttype($$.c, $1.t, $$.t);
2184 $$.c = abc_dup($$.c);
2185 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2186 $$.c = cut_last_push($$.c);
2187 $$.c = code_append($$.c,$3.c);
2188 $$.c = converttype($$.c, $3.t, $$.t);
2189 code_t*label = $$.c = abc_label($$.c);
2190 jmp->branch = label;
2193 E : '!' E {$$.c=$2.c;
2194 $$.c = abc_not($$.c);
2195 $$.t = TYPE_BOOLEAN;
2198 E : '~' E {$$.c=$2.c;
2199 $$.c = abc_bitnot($$.c);
2203 E : E '&' E {$$.c = code_append($1.c,$3.c);
2204 $$.c = abc_bitand($$.c);
2208 E : E '^' E {$$.c = code_append($1.c,$3.c);
2209 $$.c = abc_bitxor($$.c);
2213 E : E '|' E {$$.c = code_append($1.c,$3.c);
2214 $$.c = abc_bitor($$.c);
2218 E : E '-' E {$$.c = code_append($1.c,$3.c);
2219 if(BOTH_INT($1,$3)) {
2220 $$.c = abc_subtract_i($$.c);
2223 $$.c = abc_subtract($$.c);
2227 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2228 $$.c = abc_rshift($$.c);
2231 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2232 $$.c = abc_urshift($$.c);
2235 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2236 $$.c = abc_lshift($$.c);
2240 E : E '/' E {$$.c = code_append($1.c,$3.c);
2241 $$.c = abc_divide($$.c);
2244 E : E '+' E {$$.c = code_append($1.c,$3.c);
2245 $$.c = abc_add($$.c);
2248 E : E '%' E {$$.c = code_append($1.c,$3.c);
2249 $$.c = abc_modulo($$.c);
2252 E : E '*' E {$$.c = code_append($1.c,$3.c);
2253 if(BOTH_INT($1,$3)) {
2254 $$.c = abc_multiply_i($$.c);
2257 $$.c = abc_multiply($$.c);
2262 E : E "in" E {$$.c = code_append($1.c,$3.c);
2263 $$.c = abc_in($$.c);
2264 $$.t = TYPE_BOOLEAN;
2267 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2268 if(use_astype && TYPE_IS_CLASS($3.t)) {
2269 MULTINAME(m,$3.t->cls);
2270 $$.c = abc_astype2($1.c, &m);
2273 $$.c = code_append($1.c, $3.c);
2274 $$.c = abc_astypelate($$.c);
2279 E : E "instanceof" E
2280 {$$.c = code_append($1.c, $3.c);
2281 $$.c = abc_instanceof($$.c);
2282 $$.t = TYPE_BOOLEAN;
2285 E : E "is" E {$$.c = code_append($1.c, $3.c);
2286 $$.c = abc_istypelate($$.c);
2287 $$.t = TYPE_BOOLEAN;
2290 E : "typeof" '(' E ')' {
2292 $$.c = abc_typeof($$.c);
2297 $$.c = cut_last_push($2.c);
2298 $$.c = abc_pushundefined($$.c);
2302 E : "void" { $$.c = abc_pushundefined(0);
2306 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2311 $$.c=abc_negate_i($$.c);
2314 $$.c=abc_negate($$.c);
2321 $$.c = code_append($$.c, $3.c);
2323 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2324 $$.c = abc_getproperty2($$.c, &m);
2325 $$.t = 0; // array elements have unknown type
2328 E : '[' MAYBE_EXPRESSION_LIST ']' {
2330 $$.c = code_append($$.c, $2.cc);
2331 $$.c = abc_newarray($$.c, $2.len);
2332 $$.t = registry_getarrayclass();
2335 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2336 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2338 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2340 $$.cc = code_append($$.cc, $1.c);
2341 $$.cc = code_append($$.cc, $3.c);
2344 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2347 $$.cc = code_append($$.cc, $3.c);
2348 $$.cc = code_append($$.cc, $5.c);
2353 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2355 $$.c = code_append($$.c, $2.cc);
2356 $$.c = abc_newobject($$.c, $2.len/2);
2357 $$.t = registry_getobjectclass();
2362 if(BOTH_INT($1,$3)) {
2363 c=abc_multiply_i(c);
2367 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2368 $$.c = toreadwrite($1.c, c, 0, 0);
2373 code_t*c = abc_modulo($3.c);
2374 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2375 $$.c = toreadwrite($1.c, c, 0, 0);
2379 code_t*c = abc_lshift($3.c);
2380 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2381 $$.c = toreadwrite($1.c, c, 0, 0);
2385 code_t*c = abc_rshift($3.c);
2386 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2387 $$.c = toreadwrite($1.c, c, 0, 0);
2391 code_t*c = abc_urshift($3.c);
2392 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2393 $$.c = toreadwrite($1.c, c, 0, 0);
2397 code_t*c = abc_divide($3.c);
2398 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2399 $$.c = toreadwrite($1.c, c, 0, 0);
2404 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2409 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2411 $$.c = toreadwrite($1.c, c, 0, 0);
2414 E : E "-=" E { code_t*c = $3.c;
2415 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2416 c=abc_subtract_i(c);
2420 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2422 $$.c = toreadwrite($1.c, c, 0, 0);
2425 E : E '=' E { code_t*c = 0;
2426 c = code_append(c, $3.c);
2427 c = converttype(c, $3.t, $1.t);
2428 $$.c = toreadwrite($1.c, c, 1, 0);
2432 E : E '?' E ':' E %prec below_assignment {
2434 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2435 $$.c = code_append($$.c, $3.c);
2436 code_t*j2 = $$.c = abc_jump($$.c, 0);
2437 $$.c = j1->branch = abc_label($$.c);
2438 $$.c = code_append($$.c, $5.c);
2439 $$.c = j2->branch = abc_label($$.c);
2440 $$.t = join_types($3.t,$5.t,'?');
2443 // TODO: use inclocal where appropriate
2444 E : E "++" { code_t*c = 0;
2445 classinfo_t*type = $1.t;
2446 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2447 c=abc_increment_i(c);
2453 c=converttype(c, type, $1.t);
2454 $$.c = toreadwrite($1.c, c, 0, 1);
2457 E : E "--" { code_t*c = 0;
2458 classinfo_t*type = $1.t;
2459 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2460 c=abc_decrement_i(c);
2466 c=converttype(c, type, $1.t);
2467 $$.c = toreadwrite($1.c, c, 0, 1);
2471 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2472 classinfo_t*type = $2.t;
2473 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2474 c=abc_increment_i(c);
2480 c=converttype(c, type, $2.t);
2481 $$.c = toreadwrite($2.c, c, 0, 0);
2485 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2486 classinfo_t*type = $2.t;
2487 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2488 c=abc_decrement_i(c);
2494 c=converttype(c, type, $2.t);
2495 $$.c = toreadwrite($2.c, c, 0, 0);
2499 E : "super" '.' T_IDENTIFIER
2500 { if(!state->cls->info)
2501 syntaxerror("super keyword not allowed outside a class");
2502 classinfo_t*t = state->cls->info->superclass;
2503 if(!t) t = TYPE_OBJECT;
2505 memberinfo_t*f = registry_findmember(t, $3, 1);
2506 namespace_t ns = {flags2access(f->flags), ""};
2507 MEMBER_MULTINAME(m, f, $3);
2509 $$.c = abc_getlocal_0($$.c);
2510 $$.c = abc_getsuper2($$.c, &m);
2511 $$.t = memberinfo_gettype(f);
2514 E : E '.' T_IDENTIFIER
2516 classinfo_t*t = $1.t;
2518 if(TYPE_IS_CLASS(t) && t->cls) {
2523 memberinfo_t*f = registry_findmember(t, $3, 1);
2525 if(f && !is_static != !(f->flags&FLAG_STATIC))
2527 if(f && f->slot && !noslot) {
2528 $$.c = abc_getslot($$.c, f->slot);
2530 MEMBER_MULTINAME(m, f, $3);
2531 $$.c = abc_getproperty2($$.c, &m);
2533 /* determine type */
2534 $$.t = memberinfo_gettype(f);
2536 $$.c = abc_coerce_a($$.c);
2538 /* when resolving a property on an unknown type, we do know the
2539 name of the property (and don't seem to need the package), but
2540 we need to make avm2 try out all access modes */
2541 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2542 $$.c = abc_getproperty2($$.c, &m);
2543 $$.c = abc_coerce_a($$.c);
2544 $$.t = registry_getanytype();
2548 VAR_READ : T_IDENTIFIER {
2555 /* look at variables */
2556 if((v = find_variable($1))) {
2557 // $1 is a local variable
2558 $$.c = abc_getlocal($$.c, v->index);
2561 /* look at current class' members */
2562 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2563 // $1 is a function in this class
2564 int var_is_static = (f->flags&FLAG_STATIC);
2565 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2566 if(var_is_static != i_am_static) {
2567 /* there doesn't seem to be any "static" way to access
2568 static properties of a class */
2569 state->method->late_binding = 1;
2571 namespace_t ns = {flags2access(f->flags), ""};
2572 multiname_t m = {QNAME, &ns, 0, $1};
2573 $$.c = abc_findpropstrict2($$.c, &m);
2574 $$.c = abc_getproperty2($$.c, &m);
2577 $$.c = abc_getlocal_0($$.c);
2578 $$.c = abc_getslot($$.c, f->slot);
2580 namespace_t ns = {flags2access(f->flags), ""};
2581 multiname_t m = {QNAME, &ns, 0, $1};
2582 $$.c = abc_getlocal_0($$.c);
2583 $$.c = abc_getproperty2($$.c, &m);
2586 if(f->kind == MEMBER_METHOD) {
2587 $$.t = TYPE_FUNCTION(f);
2592 /* look at actual classes, in the current package and imported */
2593 } else if((a = find_class($1))) {
2594 if(a->flags & FLAG_METHOD) {
2596 $$.c = abc_findpropstrict2($$.c, &m);
2597 $$.c = abc_getproperty2($$.c, &m);
2598 $$.t = TYPE_FUNCTION(a->function);
2601 $$.c = abc_getglobalscope($$.c);
2602 $$.c = abc_getslot($$.c, a->slot);
2605 $$.c = abc_getlex2($$.c, &m);
2607 $$.t = TYPE_CLASS(a);
2610 /* unknown object, let the avm2 resolve it */
2612 if(strcmp($1,"trace"))
2613 warning("Couldn't resolve '%s', doing late binding", $1);
2614 state->method->late_binding = 1;
2616 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2619 $$.c = abc_findpropstrict2($$.c, &m);
2620 $$.c = abc_getproperty2($$.c, &m);
2625 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2626 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2627 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2629 // ----------------- namespaces -------------------------------------------------
2631 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2632 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2633 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2635 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}