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 MAYBE_IDENTIFIER
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 <value> INNERFUNCTION
182 %type <token> USE_NAMESPACE
183 %type <code> FOR_INIT
185 %type <classinfo> MAYBETYPE
188 %type <params> PARAM_LIST
189 %type <params> MAYBE_PARAM_LIST
190 %type <flags> MAYBE_MODIFIERS
191 %type <flags> MODIFIER_LIST
192 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
193 %type <classinfo_list> IMPLEMENTS_LIST
194 %type <classinfo> EXTENDS
195 %type <classinfo_list> EXTENDS_LIST
196 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
197 %type <classinfo_list> QNAME_LIST
198 %type <classinfo> TYPE
199 //%type <token> VARIABLE
200 %type <value> VAR_READ
202 //%type <token> T_IDENTIFIER
203 %type <token> MODIFIER
204 %type <value> FUNCTIONCALL
205 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
207 // precedence: from low to high
211 %left below_semicolon
214 %nonassoc below_assignment // for ?:, contrary to spec
215 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
222 %nonassoc "==" "!=" "===" "!=="
223 %nonassoc "is" "as" "in"
224 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
225 %left "<<" ">>" ">>>"
229 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
231 %nonassoc below_curly
232 %left '[' ']' '{' "new" '.' ".." "::"
233 %nonassoc T_IDENTIFIER
234 %left above_identifier
239 // needed for "return" precedence:
240 %nonassoc T_STRING T_REGEXP
241 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
242 %nonassoc "false" "true" "null" "undefined" "super" "function"
243 %nonassoc above_function
249 static int yyerror(char*s)
251 syntaxerror("%s", s);
254 static char* concat2(const char* t1, const char* t2)
258 char*text = malloc(l1+l2+1);
259 memcpy(text , t1, l1);
260 memcpy(text+l1, t2, l2);
264 static char* concat3(const char* t1, const char* t2, const char* t3)
269 char*text = malloc(l1+l2+l3+1);
270 memcpy(text , t1, l1);
271 memcpy(text+l1, t2, l2);
272 memcpy(text+l1+l2, t3, l3);
277 typedef struct _import {
281 DECLARE_LIST(import);
283 typedef struct _classstate {
289 char has_constructor;
292 typedef struct _methodstate {
299 abc_exception_list_t*exceptions;
302 typedef struct _state {
307 import_list_t*wildcard_imports;
309 char has_own_imports;
312 methodstate_t*method;
319 typedef struct _global {
326 static global_t*global = 0;
327 static state_t* state = 0;
331 #define MULTINAME(m,x) \
334 registry_fill_multiname(&m, &m##_ns, x);
336 #define MEMBER_MULTINAME(m,f,n) \
340 m##_ns = flags2namespace(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;
425 state_destroy(leaving);
428 void initialize_parser()
430 global = rfx_calloc(sizeof(global_t));
431 global->file = abc_file_new();
432 global->file->flags &= ~ABCFILE_LAZY;
433 global->variable_count = 1;
434 global->init = abc_initscript(global->file);
435 code_t*c = global->init->method->body->code;
436 c = abc_getlocal_0(c);
437 c = abc_pushscope(c);
438 /*c = abc_findpropstrict(c, "[package]::trace");
439 c = abc_pushstring(c, "[entering global init function]");
440 c = abc_callpropvoid(c, "[package]::trace", 1);*/
441 global->init->method->body->code = c;
444 void initialize_file(char*filename)
447 state->package = filename;
451 if(!state || state->level!=1) {
452 syntaxerror("unexpected end of file");
454 state_destroy(state);state=0;
457 void* finish_parser()
459 code_t*c = global->init->method->body->code;
460 /*c = abc_findpropstrict(c, "[package]::trace");
461 c = abc_pushstring(c, "[leaving global init function]");
462 c = abc_callpropvoid(c, "[package]::trace", 1);*/
463 c = abc_returnvoid(c);
464 global->init->method->body->code = c;
469 static void xx_scopetest()
471 /* findpropstrict doesn't just return a scope object- it
472 also makes it "active" somehow. Push local_0 on the
473 scope stack and read it back with findpropstrict, it'll
474 contain properties like "trace". Trying to find the same
475 property on a "vanilla" local_0 yields only a "undefined" */
476 //c = abc_findpropstrict(c, "[package]::trace");
478 /*c = abc_getlocal_0(c);
479 c = abc_findpropstrict(c, "[package]::trace");
481 c = abc_setlocal_1(c);
483 c = abc_pushbyte(c, 0);
484 c = abc_setlocal_2(c);
486 code_t*xx = c = abc_label(c);
487 c = abc_findpropstrict(c, "[package]::trace");
488 c = abc_pushstring(c, "prop:");
489 c = abc_hasnext2(c, 1, 2);
491 c = abc_setlocal_3(c);
492 c = abc_callpropvoid(c, "[package]::trace", 2);
493 c = abc_getlocal_3(c);
495 c = abc_iftrue(c,xx);*/
499 typedef struct _variable {
505 static variable_t* find_variable(char*name)
511 v = dict_lookup(s->vars, name);
519 static variable_t* find_variable_safe(char*name)
521 variable_t* v = find_variable(name);
523 syntaxerror("undefined variable: %s", name);
526 static char variable_exists(char*name)
528 return dict_lookup(state->vars, name)!=0;
530 code_t*defaultvalue(code_t*c, classinfo_t*type);
531 static int new_variable(char*name, classinfo_t*type, char init)
534 v->index = global->variable_count;
538 dict_put(state->vars, name, v);
540 return global->variable_count++;
542 #define TEMPVARNAME "__as3_temp__"
543 static int gettempvar()
545 variable_t*v = find_variable(TEMPVARNAME);
548 return new_variable(TEMPVARNAME, 0, 0);
551 code_t* var_block(code_t*body)
557 for(t=0;t<state->vars->hashsize;t++) {
558 dictentry_t*e = state->vars->slots[t];
560 variable_t*v = (variable_t*)e->data;
561 if(v->type && v->init) {
562 c = defaultvalue(c, v->type);
563 c = abc_setlocal(c, v->index);
564 k = abc_kill(k, v->index);
574 if(x->opcode== OPCODE___BREAK__ ||
575 x->opcode== OPCODE___CONTINUE__) {
576 /* link kill code before break/continue */
577 code_t*e = code_dup(k);
578 code_t*s = code_start(e);
590 c = code_append(c, body);
591 c = code_append(c, k);
595 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
597 c = code_append(c, header);
598 c = code_append(c, var_block(body));
599 /* append return if necessary */
600 if(!c || c->opcode != OPCODE_RETURNVOID &&
601 c->opcode != OPCODE_RETURNVALUE) {
602 c = abc_returnvoid(c);
608 static void startpackage(char*name)
611 /*printf("entering package \"%s\"\n", name);*/
612 state->package = strdup(name);
613 global->variable_count = 1;
615 static void endpackage()
617 /*printf("leaving package \"%s\"\n", state->package);*/
619 //used e.g. in classinfo_register:
620 //free(state->package);state->package=0;
625 char*as3_globalclass=0;
626 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
629 syntaxerror("inner classes now allowed");
632 global->variable_count = 1;
633 state->cls = rfx_calloc(sizeof(classstate_t));
634 state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
637 classinfo_list_t*mlist=0;
639 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
640 syntaxerror("invalid modifier(s)");
642 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
643 syntaxerror("public and internal not supported at the same time.");
645 /* create the class name, together with the proper attributes */
649 if(!(flags&FLAG_PUBLIC) && !state->package) {
650 access = ACCESS_PRIVATE; package = current_filename;
651 } else if(!(flags&FLAG_PUBLIC) && state->package) {
652 access = ACCESS_PACKAGEINTERNAL; package = state->package;
653 } else if(state->package) {
654 access = ACCESS_PACKAGE; package = state->package;
656 syntaxerror("public classes only allowed inside a package");
659 if(registry_findclass(package, classname)) {
660 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
664 /* build info struct */
665 int num_interfaces = (list_length(implements));
666 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
667 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
669 classinfo_list_t*l = implements;
670 for(l=implements;l;l=l->next) {
671 state->cls->info->interfaces[pos++] = l->classinfo;
674 multiname_t*extends2 = sig2mname(extends);
676 MULTINAME(classname2,state->cls->info);
679 state->cls_init = abc_getlocal_0(state->cls_init);
680 state->cls_init = abc_constructsuper(state->cls_init, 0);
683 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
684 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
685 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
687 state->cls->info->flags |= CLASS_INTERFACE;
688 abc_class_interface(state->cls->abc);
691 abc_class_protectedNS(state->cls->abc, classname);
693 for(mlist=implements;mlist;mlist=mlist->next) {
694 MULTINAME(m, mlist->classinfo);
695 abc_class_add_interface(state->cls->abc, &m);
698 /* now write the construction code for this class */
699 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
701 abc_method_body_t*m = global->init->method->body;
702 __ getglobalscope(m);
703 classinfo_t*s = extends;
708 //TODO: take a look at the current scope stack, maybe
709 // we can re-use something
714 multiname_t*s2 = sig2mname(s);
716 multiname_destroy(s2);
718 __ pushscope(m); count++;
719 m->code = m->code->prev->prev; // invert
721 /* continue appending after last op end */
722 while(m->code && m->code->next) m->code = m->code->next;
724 /* TODO: if this is one of *our* classes, we can also
725 do a getglobalscope/getslot <nr> (which references
726 the init function's slots) */
728 __ getlex2(m, extends2);
730 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
731 stack is not the superclass */
732 __ pushscope(m);count++;
735 /* notice: we get a verify error #1107 if the top element on the scope
736 stack is not the global object */
738 __ pushscope(m);count++;
740 __ newclass(m,state->cls->abc);
744 __ setslot(m, slotindex);
746 /* flash.display.MovieClip handling */
747 if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
748 if(state->package && state->package[0]) {
749 as3_globalclass = concat3(state->package, ".", classname);
751 as3_globalclass = strdup(classname);
754 multiname_destroy(extends2);
757 static void endclass()
759 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
761 c = abc_getlocal_0(c);
762 c = abc_constructsuper(c, 0);
763 state->cls->init = code_append(state->cls->init, c);
765 if(!state->method->late_binding) {
766 // class initialization code uses late binding
768 c = abc_getlocal_0(c);
769 c = abc_pushscope(c);
770 state->cls->static_init = code_append(c, state->cls->static_init);
773 if(state->cls->init) {
774 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
775 m->body->code = wrap_function(0, state->cls->init, m->body->code);
777 if(state->cls->static_init) {
778 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
779 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
782 free(state->cls);state->cls=0;
783 free(state->method);state->method=0;
787 void check_code_for_break(code_t*c)
790 if(c->opcode == OPCODE___BREAK__) {
791 char*name = string_cstr(c->data[0]);
792 syntaxerror("Unresolved \"break %s\"", name);
794 if(c->opcode == OPCODE___CONTINUE__) {
795 char*name = string_cstr(c->data[0]);
796 syntaxerror("Unresolved \"continue %s\"", name);
803 static void check_constant_against_type(classinfo_t*t, constant_t*c)
805 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
806 if(TYPE_IS_NUMBER(t)) {
807 xassert(c->type == CONSTANT_FLOAT
808 || c->type == CONSTANT_INT
809 || c->type == CONSTANT_UINT);
810 } else if(TYPE_IS_UINT(t)) {
811 xassert(c->type == CONSTANT_UINT ||
812 (c->type == CONSTANT_INT && c->i>0));
813 } else if(TYPE_IS_INT(t)) {
814 xassert(c->type == CONSTANT_INT);
815 } else if(TYPE_IS_BOOLEAN(t)) {
816 xassert(c->type == CONSTANT_TRUE
817 || c->type == CONSTANT_FALSE);
822 static int flags2access(int flags)
825 if(flags&FLAG_PUBLIC) {
826 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
827 syntaxerror("invalid combination of access levels");
828 access = ACCESS_PACKAGE;
829 } else if(flags&FLAG_PRIVATE) {
830 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
831 syntaxerror("invalid combination of access levels");
832 access = ACCESS_PRIVATE;
833 } else if(flags&FLAG_PROTECTED) {
834 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
835 syntaxerror("invalid combination of access levels");
836 access = ACCESS_PROTECTED;
838 access = ACCESS_PACKAGEINTERNAL;
844 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
846 memberinfo_t*minfo = 0;
849 minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
850 minfo->return_type = return_type;
851 } else if(getset != KW_GET && getset != KW_SET) {
853 if((minfo = registry_findmember(state->cls->info, name, 0))) {
854 if(minfo->parent == state->cls->info) {
855 syntaxerror("class already contains a member/method called '%s'", name);
856 } else if(!minfo->parent) {
857 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
859 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
860 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
863 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
864 minfo->return_type = return_type;
865 // getslot on a member slot only returns "undefined", so no need
866 // to actually store these
867 //state->minfo->slot = state->method->abc->method->trait->slot_id;
869 //class getter/setter
870 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
874 else if(params->list)
875 type = params->list->param->type;
876 // not sure wether to look into superclasses here, too
877 if((minfo=registry_findmember(state->cls->info, name, 0))) {
878 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
879 syntaxerror("class already contains a member or method called '%s'", name);
881 syntaxerror("getter/setter for '%s' already defined", name);
882 /* make a setter or getter into a getset */
887 if(type && minfo->type != type)
888 syntaxerror("different type in getter and setter");
890 minfo = memberinfo_register(state->cls->info, name, gs);
893 /* can't assign a slot as getter and setter might have different slots */
894 //minfo->slot = slot;
896 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
897 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
898 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
899 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
900 if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
901 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
905 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
906 params_t*params, classinfo_t*return_type)
908 if(state->method && state->method->info) {
909 syntaxerror("not able to start another method scope");
912 global->variable_count = 0;
913 state->method = rfx_calloc(sizeof(methodstate_t));
914 state->method->has_super = 0;
917 state->method->is_constructor = !strcmp(state->cls->info->name,name);
918 state->cls->has_constructor |= state->method->is_constructor;
920 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
922 state->method->is_global = 1;
923 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
925 new_variable("globalscope", 0, 0);
928 /* state->vars is initialized by state_new */
931 for(p=params->list;p;p=p->next) {
932 new_variable(p->param->name, p->param->type, 0);
934 if(state->method->is_constructor)
935 name = "__as3_constructor__";
936 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
939 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
940 params_t*params, classinfo_t*return_type, code_t*body)
944 multiname_t*type2 = sig2mname(return_type);
946 if(state->method->is_constructor) {
947 f = abc_class_getconstructor(state->cls->abc, type2);
948 } else if(!state->method->is_global) {
949 namespace_t mname_ns = flags2namespace(flags, "");
950 multiname_t mname = {QNAME, &mname_ns, 0, name};
952 if(flags&FLAG_STATIC)
953 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
955 f = abc_class_method(state->cls->abc, type2, &mname);
956 slot = f->trait->slot_id;
958 namespace_t mname_ns = flags2namespace(flags, state->package);
959 multiname_t mname = {QNAME, &mname_ns, 0, name};
961 f = abc_method_new(global->file, type2, 1);
962 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
963 //abc_code_t*c = global->init->method->body->code;
965 //flash doesn't seem to allow us to access function slots
966 //state->method->info->slot = slot;
968 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
969 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
970 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
971 if(params->varargs) f->flags |= METHOD_NEED_REST;
975 for(p=params->list;p;p=p->next) {
976 if(params->varargs && !p->next) {
977 break; //varargs: omit last parameter in function signature
979 multiname_t*m = sig2mname(p->param->type);
980 list_append(f->parameters, m);
981 if(p->param->value) {
982 check_constant_against_type(p->param->type, p->param->value);
983 opt=1;list_append(f->optional_parameters, p->param->value);
985 syntaxerror("non-optional parameter not allowed after optional parameters");
988 check_code_for_break(body);
991 f->body->code = body;
992 f->body->exceptions = state->method->exceptions;
995 syntaxerror("interface methods can't have a method body");
998 free(state->method);state->method=0;
1004 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1009 void breakjumpsto(code_t*c, char*name, code_t*jump)
1012 if(c->opcode == OPCODE___BREAK__) {
1013 string_t*name2 = c->data[0];
1014 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1015 c->opcode = OPCODE_JUMP;
1022 void continuejumpsto(code_t*c, char*name, code_t*jump)
1025 if(c->opcode == OPCODE___CONTINUE__) {
1026 string_t*name2 = c->data[0];
1027 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1028 c->opcode = OPCODE_JUMP;
1036 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1037 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1038 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1040 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1042 if(!type1 || !type2)
1043 return registry_getanytype();
1044 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1045 return registry_getanytype();
1048 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1057 return registry_getanytype();
1059 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1064 return abc_coerce_a(c);
1068 // cast an "any" type to a specific type. subject to
1069 // runtime exceptions
1070 return abc_coerce2(c, &m);
1073 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1074 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1075 // allow conversion between number types
1076 return abc_coerce2(c, &m);
1078 //printf("%s.%s\n", from.package, from.name);
1079 //printf("%s.%s\n", to.package, to.name);
1081 classinfo_t*supertype = from;
1083 if(supertype == to) {
1084 // target type is one of from's superclasses
1085 return abc_coerce2(c, &m);
1088 while(supertype->interfaces[t]) {
1089 if(supertype->interfaces[t]==to) {
1090 // target type is one of from's interfaces
1091 return abc_coerce2(c, &m);
1095 supertype = supertype->superclass;
1097 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1099 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1101 syntaxerror("can't convert type %s to %s", from->name, to->name);
1104 code_t*defaultvalue(code_t*c, classinfo_t*type)
1106 if(TYPE_IS_INT(type)) {
1107 c = abc_pushbyte(c, 0);
1108 } else if(TYPE_IS_UINT(type)) {
1109 c = abc_pushuint(c, 0);
1110 } else if(TYPE_IS_FLOAT(type)) {
1112 } else if(TYPE_IS_BOOLEAN(type)) {
1113 c = abc_pushfalse(c);
1115 //c = abc_pushundefined(c);
1117 c = abc_pushnull(c);
1119 c = abc_coerce2(c, &m);
1124 char is_pushundefined(code_t*c)
1126 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1129 void parserassert(int b)
1131 if(!b) syntaxerror("internal error: assertion failed");
1134 static classinfo_t* find_class(char*name)
1138 c = registry_findclass(state->package, name);
1141 /* try explicit imports */
1142 dictentry_t* e = dict_get_slot(state->imports, name);
1145 if(!strcmp(e->key, name)) {
1146 c = (classinfo_t*)e->data;
1152 /* try package.* imports */
1153 import_list_t*l = state->wildcard_imports;
1155 //printf("does package %s contain a class %s?\n", l->import->package, name);
1156 c = registry_findclass(l->import->package, name);
1161 /* try global package */
1162 c = registry_findclass("", name);
1165 /* try local "filename" package */
1166 c = registry_findclass(current_filename, name);
1172 static char is_getlocal(code_t*c)
1174 if(!c || c->prev || c->next)
1176 return(c->opcode == OPCODE_GETLOCAL
1177 || c->opcode == OPCODE_GETLOCAL_0
1178 || c->opcode == OPCODE_GETLOCAL_1
1179 || c->opcode == OPCODE_GETLOCAL_2
1180 || c->opcode == OPCODE_GETLOCAL_3);
1182 static int getlocalnr(code_t*c)
1184 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1185 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1186 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1187 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1188 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1189 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1192 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1196 [prefix code] [read instruction]
1200 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1203 if(in && in->opcode == OPCODE_COERCE_A) {
1204 in = code_cutlast(in);
1207 syntaxerror("internal error");
1209 /* chop off read instruction */
1213 prefix = r->prev;r->prev = 0;
1219 char use_temp_var = readbefore;
1221 /* generate the write instruction, and maybe append a dup to the prefix code */
1222 code_t* write = abc_nop(0);
1223 if(r->opcode == OPCODE_GETPROPERTY) {
1224 write->opcode = OPCODE_SETPROPERTY;
1225 multiname_t*m = (multiname_t*)r->data[0];
1226 write->data[0] = multiname_clone(m);
1227 if(m->type == QNAME || m->type == MULTINAME) {
1229 prefix = abc_dup(prefix); // we need the object, too
1232 } else if(m->type == MULTINAMEL) {
1234 /* dupping two values on the stack requires 5 operations and one register-
1235 couldn't adobe just have given us a dup2? */
1236 int temp = gettempvar();
1237 prefix = abc_setlocal(prefix, temp);
1238 prefix = abc_dup(prefix);
1239 prefix = abc_getlocal(prefix, temp);
1240 prefix = abc_swap(prefix);
1241 prefix = abc_getlocal(prefix, temp);
1243 prefix = abc_kill(prefix, temp);
1247 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1249 } else if(r->opcode == OPCODE_GETSLOT) {
1250 write->opcode = OPCODE_SETSLOT;
1251 write->data[0] = r->data[0];
1253 prefix = abc_dup(prefix); // we need the object, too
1256 } else if(r->opcode == OPCODE_GETLOCAL) {
1257 write->opcode = OPCODE_SETLOCAL;
1258 write->data[0] = r->data[0];
1259 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1260 write->opcode = OPCODE_SETLOCAL_0;
1261 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1262 write->opcode = OPCODE_SETLOCAL_1;
1263 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1264 write->opcode = OPCODE_SETLOCAL_2;
1265 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1266 write->opcode = OPCODE_SETLOCAL_3;
1268 code_dump(r, 0, 0, "", stdout);
1269 syntaxerror("illegal lvalue: can't assign a value to this expression");
1276 /* with getproperty/getslot, we have to be extra careful not
1277 to execute the read code twice, as it might have side-effects
1278 (e.g. if the property is in fact a setter/getter combination)
1280 So read the value, modify it, and write it again,
1281 using prefix only once and making sure (by using a temporary
1282 register) that the return value is what we just wrote */
1283 temp = gettempvar();
1284 c = code_append(c, prefix);
1285 c = code_append(c, r);
1288 c = abc_setlocal(c, temp);
1290 c = code_append(c, middlepart);
1293 c = abc_setlocal(c, temp);
1295 c = code_append(c, write);
1296 c = abc_getlocal(c, temp);
1297 c = abc_kill(c, temp);
1299 /* if we're allowed to execute the read code twice *and*
1300 the middlepart doesn't modify the code, things are easier.
1302 code_t* r2 = code_dup(r);
1303 //c = code_append(c, prefix);
1304 parserassert(!prefix);
1305 c = code_append(c, r);
1306 c = code_append(c, middlepart);
1307 c = code_append(c, write);
1308 c = code_append(c, r2);
1311 /* even smaller version: overwrite the value without reading
1315 c = code_append(c, prefix);
1318 c = code_append(c, middlepart);
1319 c = code_append(c, write);
1320 c = code_append(c, r);
1322 temp = gettempvar();
1324 c = code_append(c, prefix);
1326 c = code_append(c, middlepart);
1328 c = abc_setlocal(c, temp);
1329 c = code_append(c, write);
1330 c = abc_getlocal(c, temp);
1331 c = abc_kill(c, temp);
1344 /* ------------ code blocks / statements ---------------- */
1346 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1348 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1349 PROGRAM_CODE_LIST: PROGRAM_CODE
1350 | PROGRAM_CODE_LIST PROGRAM_CODE
1352 PROGRAM_CODE: PACKAGE_DECLARATION
1353 | INTERFACE_DECLARATION
1355 | FUNCTION_DECLARATION
1360 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1361 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1362 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1364 INPACKAGE_CODE: INTERFACE_DECLARATION
1366 | FUNCTION_DECLARATION
1371 MAYBECODE: CODE {$$=$1;}
1372 MAYBECODE: {$$=code_new();}
1374 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1375 CODE: CODEPIECE {$$=$1;}
1377 // code which also may appear outside a method
1378 CODE_STATEMENT: IMPORT
1380 CODE_STATEMENT: FOR_IN
1381 CODE_STATEMENT: WHILE
1382 CODE_STATEMENT: DO_WHILE
1383 CODE_STATEMENT: SWITCH
1385 CODE_STATEMENT: WITH
1387 CODE_STATEMENT: VOIDEXPRESSION
1389 // code which may appear anywhere
1390 CODEPIECE: ';' {$$=0;}
1391 CODEPIECE: CODE_STATEMENT
1392 CODEPIECE: VARIABLE_DECLARATION
1398 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1399 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
1401 CODEBLOCK : '{' CODE '}' {$$=$2;}
1402 CODEBLOCK : '{' '}' {$$=0;}
1403 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1404 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1406 /* ------------ package init code ------------------- */
1408 PACKAGE_INITCODE: CODE_STATEMENT {
1409 if($1) as3_warning("code ignored");
1412 /* ------------ variables --------------------------- */
1414 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1415 | {$$.c=abc_pushundefined(0);
1419 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1420 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1422 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1423 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1425 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1427 if(variable_exists($1))
1428 syntaxerror("Variable %s already defined", $1);
1430 if(!is_subtype_of($3.t, $2)) {
1431 syntaxerror("Can't convert %s to %s", $3.t->name,
1435 int index = new_variable($1, $2, 1);
1438 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1440 $$ = converttype($$, $3.t, $2);
1441 $$ = abc_setlocal($$, index);
1443 $$ = defaultvalue(0, $2);
1444 $$ = abc_setlocal($$, index);
1447 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1449 $$ = abc_coerce_a($$);
1450 $$ = abc_setlocal($$, index);
1456 /* that's the default for a local register, anyway
1458 state->method->initcode = abc_pushundefined(state->method->initcode);
1459 state->method->initcode = abc_setlocal(state->method->initcode, index);
1461 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1464 /* ------------ control flow ------------------------- */
1466 MAYBEELSE: %prec below_else {$$ = code_new();}
1467 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1468 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1470 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1473 $$ = code_append($$, $4.c);
1474 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1476 $$ = code_append($$, $6);
1478 myjmp = $$ = abc_jump($$, 0);
1480 myif->branch = $$ = abc_nop($$);
1482 $$ = code_append($$, $7);
1483 myjmp->branch = $$ = abc_nop($$);
1489 FOR_INIT : {$$=code_new();}
1490 FOR_INIT : VARIABLE_DECLARATION
1491 FOR_INIT : VOIDEXPRESSION
1493 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1494 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1495 $$=$2;new_variable($2,$3,1);
1497 FOR_IN_INIT : T_IDENTIFIER {
1501 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1502 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1504 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1505 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1507 $$ = code_append($$, $2);
1508 code_t*loopstart = $$ = abc_label($$);
1509 $$ = code_append($$, $4.c);
1510 code_t*myif = $$ = abc_iffalse($$, 0);
1511 $$ = code_append($$, $8);
1512 code_t*cont = $$ = abc_nop($$);
1513 $$ = code_append($$, $6);
1514 $$ = abc_jump($$, loopstart);
1515 code_t*out = $$ = abc_nop($$);
1516 breakjumpsto($$, $1.name, out);
1517 continuejumpsto($$, $1.name, cont);
1524 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1525 variable_t*var = find_variable($2);
1526 char*tmp1name = concat2($2, "__tmp1__");
1527 int it = new_variable(tmp1name, TYPE_INT, 0);
1528 char*tmp2name = concat2($2, "__array__");
1529 int array = new_variable(tmp1name, 0, 0);
1532 $$ = code_append($$, $4.c);
1533 $$ = abc_coerce_a($$);
1534 $$ = abc_setlocal($$, array);
1535 $$ = abc_pushbyte($$, 0);
1536 $$ = abc_setlocal($$, it);
1538 code_t*loopstart = $$ = abc_label($$);
1540 $$ = abc_hasnext2($$, array, it);
1541 code_t*myif = $$ = abc_iffalse($$, 0);
1542 $$ = abc_getlocal($$, array);
1543 $$ = abc_getlocal($$, it);
1545 $$ = abc_nextname($$);
1547 $$ = abc_nextvalue($$);
1548 $$ = converttype($$, 0, var->type);
1549 $$ = abc_setlocal($$, var->index);
1551 $$ = code_append($$, $6);
1552 $$ = abc_jump($$, loopstart);
1554 code_t*out = $$ = abc_nop($$);
1555 breakjumpsto($$, $1.name, out);
1556 continuejumpsto($$, $1.name, loopstart);
1567 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1571 code_t*myjmp = $$ = abc_jump($$, 0);
1572 code_t*loopstart = $$ = abc_label($$);
1573 $$ = code_append($$, $6);
1574 code_t*cont = $$ = abc_nop($$);
1575 myjmp->branch = cont;
1576 $$ = code_append($$, $4.c);
1577 $$ = abc_iftrue($$, loopstart);
1578 code_t*out = $$ = abc_nop($$);
1579 breakjumpsto($$, $1, out);
1580 continuejumpsto($$, $1, cont);
1586 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1588 code_t*loopstart = $$ = abc_label($$);
1589 $$ = code_append($$, $3);
1590 code_t*cont = $$ = abc_nop($$);
1591 $$ = code_append($$, $6.c);
1592 $$ = abc_iftrue($$, loopstart);
1593 code_t*out = $$ = abc_nop($$);
1594 breakjumpsto($$, $1, out);
1595 continuejumpsto($$, $1, cont);
1601 BREAK : "break" %prec prec_none {
1602 $$ = abc___break__(0, "");
1604 BREAK : "break" T_IDENTIFIER {
1605 $$ = abc___break__(0, $2);
1607 CONTINUE : "continue" %prec prec_none {
1608 $$ = abc___continue__(0, "");
1610 CONTINUE : "continue" T_IDENTIFIER {
1611 $$ = abc___continue__(0, $2);
1614 MAYBE_CASE_LIST : {$$=0;}
1615 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1616 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1617 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1618 CASE_LIST: CASE {$$=$1}
1619 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1621 CASE: "case" E ':' MAYBECODE {
1623 $$ = code_append($$, $2.c);
1624 code_t*j = $$ = abc_ifne($$, 0);
1625 $$ = code_append($$, $4);
1626 if($$->opcode != OPCODE___BREAK__) {
1627 $$ = abc___fallthrough__($$, "");
1629 code_t*e = $$ = abc_nop($$);
1632 DEFAULT: "default" ':' MAYBECODE {
1635 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1637 $$ = code_append($$, $7);
1638 code_t*out = $$ = abc_pop($$);
1639 breakjumpsto($$, $1, out);
1641 code_t*c = $$,*lastblock=0;
1643 if(c->opcode == OPCODE_IFNE) {
1644 if(!c->next) syntaxerror("internal error in fallthrough handling");
1646 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1648 c->opcode = OPCODE_JUMP;
1649 c->branch = lastblock;
1651 /* fall through end of switch */
1652 c->opcode = OPCODE_NOP;
1662 /* ------------ try / catch /finally ---------------- */
1664 FINALLY: "finally" '{' CODE '}'
1665 MAYBE_FINALLY: | FINALLY
1667 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
1669 namespace_t name_ns = {ACCESS_PACKAGE, ""};
1670 multiname_t name = {QNAME, &name_ns, 0, $3};
1672 NEW(abc_exception_t, e)
1673 e->exc_type = sig2mname($4);
1674 e->var_name = multiname_clone(&name);
1678 int i = find_variable_safe($3)->index;
1679 e->target = c = abc_setlocal(0, i);
1680 c = code_append(c, $8);
1688 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1689 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1691 TRY : "try" '{' {new_state();} CODE '}' CATCH_LIST MAYBE_FINALLY {
1692 code_t*start = code_start($4);
1695 code_t*out = abc_nop(0);
1696 code_t*jmp = $$ = abc_jump($$, out);
1698 abc_exception_list_t*l = $6;
1700 abc_exception_t*e = l->abc_exception;
1703 $$ = code_append($$, e->target);
1704 $$ = abc_jump($$, out);
1707 $$ = code_append($$, out);
1710 list_concat(state->method->exceptions, $6);
1716 /* ------------ throw ------------------------------- */
1718 THROW : "throw" EXPRESSION {
1722 THROW : "throw" %prec prec_none {
1723 if(!state->exception_name)
1724 syntaxerror("re-throw only possible within a catch block");
1725 variable_t*v = find_variable(state->exception_name);
1727 $$=abc_getlocal($$, v->index);
1731 /* ------------ with -------------------------------- */
1733 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1735 $$ = abc_pushscope($$);
1736 $$ = code_append($$, $5);
1737 $$ = abc_popscope($$);
1740 /* ------------ packages and imports ---------------- */
1742 X_IDENTIFIER: T_IDENTIFIER
1743 | "package" {$$="package";}
1745 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1746 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1748 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1749 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1751 IMPORT : "import" QNAME {
1754 syntaxerror("Couldn't import class\n");
1755 state_has_imports();
1756 dict_put(state->imports, c->name, c);
1759 IMPORT : "import" PACKAGE '.' '*' {
1762 state_has_imports();
1763 list_append(state->wildcard_imports, i);
1767 /* ------------ classes and interfaces (header) -------------- */
1769 MAYBE_MODIFIERS : %prec above_function {$$=0;}
1770 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1771 MODIFIER_LIST : MODIFIER {$$=$1;}
1772 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1774 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1775 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1776 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1777 | KW_STATIC {$$=FLAG_STATIC;}
1778 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1779 | KW_FINAL {$$=FLAG_FINAL;}
1780 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1781 | KW_NATIVE {$$=FLAG_NATIVE;}
1782 | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1784 EXTENDS : {$$=registry_getobjectclass();}
1785 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1787 EXTENDS_LIST : {$$=list_new();}
1788 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1790 IMPLEMENTS_LIST : {$$=list_new();}
1791 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1793 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1794 EXTENDS IMPLEMENTS_LIST
1795 '{' {startclass($1,$3,$4,$5, 0);}
1797 '}' {endclass();$$=0;}
1799 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1801 '{' {startclass($1,$3,0,$4,1);}
1802 MAYBE_INTERFACE_BODY
1803 '}' {endclass();$$=0;}
1805 /* ------------ classes and interfaces (body) -------------- */
1808 MAYBE_CLASS_BODY : CLASS_BODY
1809 CLASS_BODY : CLASS_BODY_ITEM
1810 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1811 CLASS_BODY_ITEM : ';'
1812 CLASS_BODY_ITEM : SLOT_DECLARATION
1813 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1815 CLASS_BODY_ITEM : CODE_STATEMENT {
1816 code_t*c = state->cls->static_init;
1817 c = code_append(c, $1);
1818 state->cls->static_init = c;
1821 MAYBE_INTERFACE_BODY :
1822 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1823 INTERFACE_BODY : IDECLARATION
1824 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1826 IDECLARATION : "var" T_IDENTIFIER {
1827 syntaxerror("variable declarations not allowed in interfaces");
1829 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1831 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
1832 syntaxerror("invalid method modifiers: interface methods always need to be public");
1834 startfunction(0,$1,$3,$4,&$6,$8);
1835 endfunction(0,$1,$3,$4,&$6,$8, 0);
1838 /* ------------ classes and interfaces (body, slots ) ------- */
1840 VARCONST: "var" | "const"
1842 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1844 memberinfo_t* info = state->cls?
1845 memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1846 memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1849 info->flags = flags;
1852 namespace_t mname_ns = {flags2access(flags), ""};
1853 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1855 trait_list_t**traits;
1859 traits = &global->init->traits;
1860 code = &global->init->method->body->code;
1861 } else if(flags&FLAG_STATIC) {
1863 traits = &state->cls->abc->static_traits;
1864 code = &state->cls->static_init;
1866 // instance variable
1867 traits = &state->cls->abc->traits;
1868 code = &state->cls->init;
1874 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1876 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1878 info->slot = t->slot_id;
1880 /* initalization code (if needed) */
1882 if($5.c && !is_pushundefined($5.c)) {
1883 c = abc_getlocal_0(c);
1884 c = code_append(c, $5.c);
1885 c = converttype(c, $5.t, $4);
1886 c = abc_setslot(c, t->slot_id);
1889 *code = code_append(*code, c);
1892 t->kind= TRAIT_CONST;
1898 /* ------------ constants -------------------------------------- */
1900 MAYBESTATICCONSTANT: {$$=0;}
1901 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1903 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1904 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1905 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1906 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1907 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1908 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1909 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1910 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1911 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1913 /* ------------ classes and interfaces (body, functions) ------- */
1915 // non-vararg version
1917 memset(&$$,0,sizeof($$));
1919 MAYBE_PARAM_LIST: PARAM_LIST {
1924 MAYBE_PARAM_LIST: "..." PARAM {
1925 memset(&$$,0,sizeof($$));
1927 list_append($$.list, $2);
1929 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1932 list_append($$.list, $4);
1936 PARAM_LIST: PARAM_LIST ',' PARAM {
1938 list_append($$.list, $3);
1941 memset(&$$,0,sizeof($$));
1942 list_append($$.list, $1);
1945 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1946 $$ = malloc(sizeof(param_t));
1951 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1952 $$ = malloc(sizeof(param_t));
1954 $$->type = TYPE_ANY;
1957 GETSET : "get" {$$=$1;}
1961 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1962 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1965 if(state->method->late_binding) {
1966 c = abc_getlocal_0(c);
1967 c = abc_pushscope(c);
1969 if(state->method->is_constructor && !state->method->has_super) {
1970 // call default constructor
1971 c = abc_getlocal_0(c);
1972 c = abc_constructsuper(c, 0);
1974 c = wrap_function(c, 0, $11);
1975 endfunction(0,$1,$3,$4,&$6,$8,c);
1979 MAYBE_IDENTIFIER: T_IDENTIFIER
1980 MAYBE_IDENTIFIER: {$$=0;}
1981 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
1983 syntaxerror("nested functions not supported yet");
1987 /* ------------- package + class ids --------------- */
1989 CLASS: T_IDENTIFIER {
1991 /* try current package */
1992 $$ = find_class($1);
1993 if(!$$) syntaxerror("Could not find class %s\n", $1);
1996 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1997 $$ = registry_findclass($1, $3);
1998 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
2002 QNAME: PACKAGEANDCLASS
2005 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
2006 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
2008 TYPE : QNAME {$$=$1;}
2009 | '*' {$$=registry_getanytype();}
2010 | "void" {$$=registry_getanytype();}
2012 | "String" {$$=registry_getstringclass();}
2013 | "int" {$$=registry_getintclass();}
2014 | "uint" {$$=registry_getuintclass();}
2015 | "Boolean" {$$=registry_getbooleanclass();}
2016 | "Number" {$$=registry_getnumberclass();}
2019 MAYBETYPE: ':' TYPE {$$=$2;}
2022 /* ----------function calls, delete, constructor calls ------ */
2024 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2025 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
2027 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2028 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2029 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2032 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2034 $$.cc = code_append($1.cc, $3.c);
2037 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2042 $$.c = abc_getglobalscope($$.c);
2043 $$.c = abc_getslot($$.c, $2->slot);
2045 $$.c = abc_findpropstrict2($$.c, &m);
2048 $$.c = code_append($$.c, $3.cc);
2051 $$.c = abc_construct($$.c, $3.len);
2053 $$.c = abc_constructprop2($$.c, &m, $3.len);
2057 /* TODO: use abc_call (for calling local variables),
2058 abc_callstatic (for calling own methods)
2061 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2064 if($$.c->opcode == OPCODE_COERCE_A) {
2065 $$.c = code_cutlast($$.c);
2067 code_t*paramcode = $3.cc;
2070 if($$.c->opcode == OPCODE_GETPROPERTY) {
2071 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2072 $$.c = code_cutlast($$.c);
2073 $$.c = code_append($$.c, paramcode);
2074 $$.c = abc_callproperty2($$.c, name, $3.len);
2075 multiname_destroy(name);
2076 } else if($$.c->opcode == OPCODE_GETSLOT) {
2077 int slot = (int)(ptroff_t)$$.c->data[0];
2078 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2079 if(t->kind!=TRAIT_METHOD) {
2080 //ok: flash allows to assign closures to members.
2082 multiname_t*name = t->name;
2083 $$.c = code_cutlast($$.c);
2084 $$.c = code_append($$.c, paramcode);
2085 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2086 $$.c = abc_callproperty2($$.c, name, $3.len);
2087 } else if($$.c->opcode == OPCODE_GETSUPER) {
2088 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2089 $$.c = code_cutlast($$.c);
2090 $$.c = code_append($$.c, paramcode);
2091 $$.c = abc_callsuper2($$.c, name, $3.len);
2092 multiname_destroy(name);
2094 $$.c = abc_getlocal_0($$.c);
2095 $$.c = code_append($$.c, paramcode);
2096 $$.c = abc_call($$.c, $3.len);
2101 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2102 $$.t = $1.t->function->return_type;
2104 $$.c = abc_coerce_a($$.c);
2109 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2110 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2111 if(!state->method) syntaxerror("super() not allowed outside of a function");
2112 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2115 $$.c = abc_getlocal_0($$.c);
2117 $$.c = code_append($$.c, $3.cc);
2119 this is dependent on the control path, check this somewhere else
2120 if(state->method->has_super)
2121 syntaxerror("constructor may call super() only once");
2123 state->method->has_super = 1;
2124 $$.c = abc_constructsuper($$.c, $3.len);
2125 $$.c = abc_pushundefined($$.c);
2129 DELETE: "delete" E {
2131 if($$.c->opcode == OPCODE_COERCE_A) {
2132 $$.c = code_cutlast($$.c);
2134 multiname_t*name = 0;
2135 if($$.c->opcode == OPCODE_GETPROPERTY) {
2136 $$.c->opcode = OPCODE_DELETEPROPERTY;
2137 } else if($$.c->opcode == OPCODE_GETSLOT) {
2138 int slot = (int)(ptroff_t)$$.c->data[0];
2139 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2140 $$.c = code_cutlast($$.c);
2141 $$.c = abc_deleteproperty2($$.c, name);
2143 $$.c = abc_getlocal_0($$.c);
2144 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2145 $$.c = abc_deleteproperty2($$.c, &m);
2147 $$.t = TYPE_BOOLEAN;
2150 RETURN: "return" %prec prec_none {
2151 $$ = abc_returnvoid(0);
2153 RETURN: "return" EXPRESSION {
2155 $$ = abc_returnvalue($$);
2158 // ----------------------- expression types -------------------------------------
2160 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2161 EXPRESSION : E %prec below_minus {$$ = $1;}
2162 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2164 $$.c = cut_last_push($$.c);
2165 $$.c = code_append($$.c,$3.c);
2168 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2169 $$=cut_last_push($1.c);
2172 // ----------------------- expression evaluation -------------------------------------
2174 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2175 //V : CONSTANT {$$ = 0;}
2177 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2178 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2179 //V : NEW {$$ = $1.c;}
2181 //V : DELETE {$$ = $1.c;}
2182 E : DELETE {$$ = $1;}
2186 namespace_t ns = {ACCESS_PACKAGE, ""};
2187 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2189 $$.c = abc_getlex2($$.c, &m);
2190 $$.c = abc_pushstring($$.c, $1.pattern);
2191 $$.c = abc_construct($$.c, 1);
2193 $$.c = abc_getlex2($$.c, &m);
2194 $$.c = abc_pushstring($$.c, $1.pattern);
2195 $$.c = abc_pushstring($$.c, $1.options);
2196 $$.c = abc_construct($$.c, 2);
2201 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2202 //MULTINAME(m, registry_getintclass());
2203 //$$.c = abc_coerce2($$.c, &m); // FIXME
2206 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2209 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2212 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2215 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2218 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2221 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2224 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2225 $$.t = TYPE_BOOLEAN;
2227 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2228 $$.t = TYPE_BOOLEAN;
2230 CONSTANT : "null" {$$.c = abc_pushnull(0);
2235 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2236 $$.t = TYPE_BOOLEAN;
2238 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2239 $$.t = TYPE_BOOLEAN;
2241 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2242 $$.t = TYPE_BOOLEAN;
2244 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2245 $$.t = TYPE_BOOLEAN;
2247 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2248 $$.t = TYPE_BOOLEAN;
2250 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2251 $$.t = TYPE_BOOLEAN;
2253 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2254 $$.t = TYPE_BOOLEAN;
2256 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2257 $$.t = TYPE_BOOLEAN;
2260 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2262 $$.c = converttype($$.c, $1.t, $$.t);
2263 $$.c = abc_dup($$.c);
2264 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2265 $$.c = cut_last_push($$.c);
2266 $$.c = code_append($$.c,$3.c);
2267 $$.c = converttype($$.c, $3.t, $$.t);
2268 code_t*label = $$.c = abc_label($$.c);
2269 jmp->branch = label;
2272 $$.t = join_types($1.t, $3.t, 'A');
2273 /*printf("%08x:\n",$1.t);
2274 code_dump($1.c, 0, 0, "", stdout);
2275 printf("%08x:\n",$3.t);
2276 code_dump($3.c, 0, 0, "", stdout);
2277 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2279 $$.c = converttype($$.c, $1.t, $$.t);
2280 $$.c = abc_dup($$.c);
2281 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2282 $$.c = cut_last_push($$.c);
2283 $$.c = code_append($$.c,$3.c);
2284 $$.c = converttype($$.c, $3.t, $$.t);
2285 code_t*label = $$.c = abc_label($$.c);
2286 jmp->branch = label;
2289 E : '!' E {$$.c=$2.c;
2290 $$.c = abc_not($$.c);
2291 $$.t = TYPE_BOOLEAN;
2294 E : '~' E {$$.c=$2.c;
2295 $$.c = abc_bitnot($$.c);
2299 E : E '&' E {$$.c = code_append($1.c,$3.c);
2300 $$.c = abc_bitand($$.c);
2304 E : E '^' E {$$.c = code_append($1.c,$3.c);
2305 $$.c = abc_bitxor($$.c);
2309 E : E '|' E {$$.c = code_append($1.c,$3.c);
2310 $$.c = abc_bitor($$.c);
2314 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2315 $$.c = abc_rshift($$.c);
2318 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2319 $$.c = abc_urshift($$.c);
2322 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2323 $$.c = abc_lshift($$.c);
2327 E : E '/' E {$$.c = code_append($1.c,$3.c);
2328 $$.c = abc_divide($$.c);
2331 E : E '%' E {$$.c = code_append($1.c,$3.c);
2332 $$.c = abc_modulo($$.c);
2335 E : E '+' E {$$.c = code_append($1.c,$3.c);
2336 if(BOTH_INT($1.t, $3.t)) {
2337 $$.c = abc_add_i($$.c);
2340 $$.c = abc_add($$.c);
2341 $$.t = join_types($1.t,$3.t,'+');
2344 E : E '-' E {$$.c = code_append($1.c,$3.c);
2345 if(BOTH_INT($1.t,$3.t)) {
2346 $$.c = abc_subtract_i($$.c);
2349 $$.c = abc_subtract($$.c);
2353 E : E '*' E {$$.c = code_append($1.c,$3.c);
2354 if(BOTH_INT($1.t,$3.t)) {
2355 $$.c = abc_multiply_i($$.c);
2358 $$.c = abc_multiply($$.c);
2363 E : E "in" E {$$.c = code_append($1.c,$3.c);
2364 $$.c = abc_in($$.c);
2365 $$.t = TYPE_BOOLEAN;
2368 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2369 if(use_astype && TYPE_IS_CLASS($3.t)) {
2370 MULTINAME(m,$3.t->cls);
2371 $$.c = abc_astype2($1.c, &m);
2374 $$.c = code_append($1.c, $3.c);
2375 $$.c = abc_astypelate($$.c);
2380 E : E "instanceof" E
2381 {$$.c = code_append($1.c, $3.c);
2382 $$.c = abc_instanceof($$.c);
2383 $$.t = TYPE_BOOLEAN;
2386 E : E "is" E {$$.c = code_append($1.c, $3.c);
2387 $$.c = abc_istypelate($$.c);
2388 $$.t = TYPE_BOOLEAN;
2391 E : "typeof" '(' E ')' {
2393 $$.c = abc_typeof($$.c);
2398 $$.c = cut_last_push($2.c);
2399 $$.c = abc_pushundefined($$.c);
2403 E : "void" { $$.c = abc_pushundefined(0);
2407 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2412 $$.c=abc_negate_i($$.c);
2415 $$.c=abc_negate($$.c);
2422 $$.c = code_append($$.c, $3.c);
2424 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2425 $$.c = abc_getproperty2($$.c, &m);
2426 $$.t = 0; // array elements have unknown type
2429 E : '[' MAYBE_EXPRESSION_LIST ']' {
2431 $$.c = code_append($$.c, $2.cc);
2432 $$.c = abc_newarray($$.c, $2.len);
2433 $$.t = registry_getarrayclass();
2436 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2437 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2439 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2441 $$.cc = code_append($$.cc, $1.c);
2442 $$.cc = code_append($$.cc, $3.c);
2445 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2448 $$.cc = code_append($$.cc, $3.c);
2449 $$.cc = code_append($$.cc, $5.c);
2454 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2456 $$.c = code_append($$.c, $2.cc);
2457 $$.c = abc_newobject($$.c, $2.len/2);
2458 $$.t = registry_getobjectclass();
2463 if(BOTH_INT($1.t,$3.t)) {
2464 c=abc_multiply_i(c);
2468 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2469 $$.c = toreadwrite($1.c, c, 0, 0);
2474 code_t*c = abc_modulo($3.c);
2475 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2476 $$.c = toreadwrite($1.c, c, 0, 0);
2480 code_t*c = abc_lshift($3.c);
2481 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2482 $$.c = toreadwrite($1.c, c, 0, 0);
2486 code_t*c = abc_rshift($3.c);
2487 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2488 $$.c = toreadwrite($1.c, c, 0, 0);
2492 code_t*c = abc_urshift($3.c);
2493 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2494 $$.c = toreadwrite($1.c, c, 0, 0);
2498 code_t*c = abc_divide($3.c);
2499 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2500 $$.c = toreadwrite($1.c, c, 0, 0);
2504 code_t*c = abc_bitor($3.c);
2505 c=converttype(c, TYPE_INT, $1.t);
2506 $$.c = toreadwrite($1.c, c, 0, 0);
2512 if(TYPE_IS_INT($1.t)) {
2516 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2519 $$.c = toreadwrite($1.c, c, 0, 0);
2522 E : E "-=" E { code_t*c = $3.c;
2523 if(TYPE_IS_INT($1.t)) {
2524 c=abc_subtract_i(c);
2527 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2530 $$.c = toreadwrite($1.c, c, 0, 0);
2533 E : E '=' E { code_t*c = 0;
2534 c = code_append(c, $3.c);
2535 c = converttype(c, $3.t, $1.t);
2536 $$.c = toreadwrite($1.c, c, 1, 0);
2540 E : E '?' E ':' E %prec below_assignment {
2541 $$.t = join_types($3.t,$5.t,'?');
2543 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2544 $$.c = code_append($$.c, $3.c);
2545 $$.c = converttype($$.c, $3.t, $$.t);
2546 code_t*j2 = $$.c = abc_jump($$.c, 0);
2547 $$.c = j1->branch = abc_label($$.c);
2548 $$.c = code_append($$.c, $5.c);
2549 $$.c = converttype($$.c, $3.t, $$.t);
2550 $$.c = j2->branch = abc_label($$.c);
2553 E : E "++" { code_t*c = 0;
2554 classinfo_t*type = $1.t;
2555 if(is_getlocal($1.c) && TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t)) {
2556 int nr = getlocalnr($1.c);
2557 code_free($1.c);$1.c=0;
2558 if(TYPE_IS_INT($1.t)) {
2559 $$.c = abc_getlocal(0, nr);
2560 $$.c = abc_inclocal_i($$.c, nr);
2561 } else if(TYPE_IS_NUMBER($1.t)) {
2562 $$.c = abc_getlocal(0, nr);
2563 $$.c = abc_inclocal($$.c, nr);
2564 } else syntaxerror("internal error");
2566 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2567 c=abc_increment_i(c);
2573 c=converttype(c, type, $1.t);
2574 $$.c = toreadwrite($1.c, c, 0, 1);
2579 // TODO: use inclocal, like with ++
2580 E : E "--" { code_t*c = 0;
2581 classinfo_t*type = $1.t;
2582 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2583 c=abc_decrement_i(c);
2589 c=converttype(c, type, $1.t);
2590 $$.c = toreadwrite($1.c, c, 0, 1);
2594 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2595 classinfo_t*type = $2.t;
2596 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2597 c=abc_increment_i(c);
2603 c=converttype(c, type, $2.t);
2604 $$.c = toreadwrite($2.c, c, 0, 0);
2608 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2609 classinfo_t*type = $2.t;
2610 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2611 c=abc_decrement_i(c);
2617 c=converttype(c, type, $2.t);
2618 $$.c = toreadwrite($2.c, c, 0, 0);
2622 E : "super" '.' T_IDENTIFIER
2623 { if(!state->cls->info)
2624 syntaxerror("super keyword not allowed outside a class");
2625 classinfo_t*t = state->cls->info->superclass;
2626 if(!t) t = TYPE_OBJECT;
2628 memberinfo_t*f = registry_findmember(t, $3, 1);
2629 namespace_t ns = flags2namespace(f->flags, "");
2630 MEMBER_MULTINAME(m, f, $3);
2632 $$.c = abc_getlocal_0($$.c);
2633 $$.c = abc_getsuper2($$.c, &m);
2634 $$.t = memberinfo_gettype(f);
2637 E : E '.' T_IDENTIFIER
2639 classinfo_t*t = $1.t;
2641 if(TYPE_IS_CLASS(t) && t->cls) {
2646 memberinfo_t*f = registry_findmember(t, $3, 1);
2648 if(f && !is_static != !(f->flags&FLAG_STATIC))
2650 if(f && f->slot && !noslot) {
2651 $$.c = abc_getslot($$.c, f->slot);
2653 MEMBER_MULTINAME(m, f, $3);
2654 $$.c = abc_getproperty2($$.c, &m);
2656 /* determine type */
2657 $$.t = memberinfo_gettype(f);
2659 $$.c = abc_coerce_a($$.c);
2661 /* when resolving a property on an unknown type, we do know the
2662 name of the property (and don't seem to need the package), but
2663 we need to make avm2 try out all access modes */
2664 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2665 $$.c = abc_getproperty2($$.c, &m);
2666 $$.c = abc_coerce_a($$.c);
2667 $$.t = registry_getanytype();
2671 VAR_READ : T_IDENTIFIER {
2678 /* look at variables */
2679 if((v = find_variable($1))) {
2680 // $1 is a local variable
2681 $$.c = abc_getlocal($$.c, v->index);
2684 /* look at current class' members */
2685 } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2686 // $1 is a function in this class
2687 int var_is_static = (f->flags&FLAG_STATIC);
2688 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2689 if(var_is_static != i_am_static) {
2690 /* there doesn't seem to be any "static" way to access
2691 static properties of a class */
2692 state->method->late_binding = 1;
2694 namespace_t ns = {flags2access(f->flags), ""};
2695 multiname_t m = {QNAME, &ns, 0, $1};
2696 $$.c = abc_findpropstrict2($$.c, &m);
2697 $$.c = abc_getproperty2($$.c, &m);
2700 $$.c = abc_getlocal_0($$.c);
2701 $$.c = abc_getslot($$.c, f->slot);
2703 namespace_t ns = {flags2access(f->flags), ""};
2704 multiname_t m = {QNAME, &ns, 0, $1};
2705 $$.c = abc_getlocal_0($$.c);
2706 $$.c = abc_getproperty2($$.c, &m);
2709 if(f->kind == MEMBER_METHOD) {
2710 $$.t = TYPE_FUNCTION(f);
2715 /* look at actual classes, in the current package and imported */
2716 } else if((a = find_class($1))) {
2717 if(a->flags & FLAG_METHOD) {
2719 $$.c = abc_findpropstrict2($$.c, &m);
2720 $$.c = abc_getproperty2($$.c, &m);
2721 if(a->function->kind == MEMBER_METHOD) {
2722 $$.t = TYPE_FUNCTION(a->function);
2724 $$.t = a->function->type;
2728 $$.c = abc_getglobalscope($$.c);
2729 $$.c = abc_getslot($$.c, a->slot);
2732 $$.c = abc_getlex2($$.c, &m);
2734 $$.t = TYPE_CLASS(a);
2737 /* unknown object, let the avm2 resolve it */
2739 if(strcmp($1,"trace"))
2740 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
2741 state->method->late_binding = 1;
2743 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2746 $$.c = abc_findpropstrict2($$.c, &m);
2747 $$.c = abc_getproperty2($$.c, &m);
2752 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2753 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2754 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2756 // ----------------- namespaces -------------------------------------------------
2758 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2759 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2760 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2762 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}