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;
62 %token<id> T_IDENTIFIER
64 %token<token> T_REGEXP
66 %token<number_int> T_INT
67 %token<number_uint> T_UINT
68 %token<number_uint> T_BYTE
69 %token<number_uint> T_SHORT
70 %token<number_float> T_FLOAT
72 %token<token> KW_IMPLEMENTS
73 %token<token> KW_NAMESPACE "namespace"
74 %token<token> KW_PACKAGE "package"
75 %token<token> KW_PROTECTED
76 %token<token> KW_PUBLIC
77 %token<token> KW_PRIVATE
78 %token<token> KW_USE "use"
79 %token<token> KW_INTERNAL
80 %token<token> KW_NEW "new"
81 %token<token> KW_NATIVE
82 %token<token> KW_FUNCTION "function"
83 %token<token> KW_UNDEFINED "undefined"
84 %token<token> KW_CONTINUE "continue"
85 %token<token> KW_FOR "for"
86 %token<token> KW_CLASS "class"
87 %token<token> KW_CONST "const"
88 %token<token> KW_SET "set"
89 %token<token> KW_VOID "void"
90 %token<token> KW_STATIC
91 %token<token> KW_INSTANCEOF "instanceof"
92 %token<token> KW_IMPORT "import"
93 %token<token> KW_RETURN "return"
94 %token<token> KW_TYPEOF "typeof"
95 %token<token> KW_INTERFACE "interface"
96 %token<token> KW_NULL "null"
97 %token<token> KW_VAR "var"
98 %token<token> KW_DYNAMIC
99 %token<token> KW_OVERRIDE
100 %token<token> KW_FINAL
101 %token<token> KW_GET "get"
102 %token<token> KW_SUPER "super"
103 %token<token> KW_EXTENDS
104 %token<token> KW_FALSE "false"
105 %token<token> KW_TRUE "true"
106 %token<token> KW_BOOLEAN "Boolean"
107 %token<token> KW_UINT "uint"
108 %token<token> KW_INT "int"
109 %token<token> KW_WHILE "while"
110 %token<token> KW_NUMBER "Number"
111 %token<token> KW_STRING "String"
112 %token<token> KW_DELETE "delete"
113 %token<token> KW_IF "if"
114 %token<token> KW_ELSE "else"
115 %token<token> KW_BREAK "break"
116 %token<token> KW_IS "is"
117 %token<token> KW_AS "as"
118 %token<token> KW_DO "do"
120 %token<token> T_EQEQ "=="
121 %token<token> T_EQEQEQ "==="
122 %token<token> T_NE "!="
123 %token<token> T_NEE "!=="
124 %token<token> T_LE "<="
125 %token<token> T_GE ">="
126 %token<token> T_DIVBY "/="
127 %token<token> T_MODBY "%="
128 %token<token> T_MULBY "*="
129 %token<token> T_PLUSBY "+="
130 %token<token> T_MINUSBY "-="
131 %token<token> T_SHRBY ">>="
132 %token<token> T_SHLBY "<<="
133 %token<token> T_USHRBY ">>>="
134 %token<token> T_OROR "||"
135 %token<token> T_ANDAND "&&"
136 %token<token> T_COLONCOLON "::"
137 %token<token> T_MINUSMINUS "--"
138 %token<token> T_PLUSPLUS "++"
139 %token<token> T_DOTDOT ".."
140 %token<token> T_DOTDOTDOT "..."
141 %token<token> T_SHL "<<"
142 %token<token> T_USHR ">>>"
143 %token<token> T_SHR ">>"
145 %type <id> X_IDENTIFIER PACKAGE MAYBELABEL
146 %type <token> VARCONST
148 %type <code> CODEPIECE
149 %type <code> CODEBLOCK MAYBECODE
150 %type <token> PACKAGE_DECLARATION
151 %type <token> FUNCTION_DECLARATION
152 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
153 %type <token> CLASS_DECLARATION
154 %type <token> NAMESPACE_DECLARATION
155 %type <token> INTERFACE_DECLARATION
156 %type <code> VOIDEXPRESSION
157 %type <value> EXPRESSION NONCOMMAEXPRESSION
158 %type <value> MAYBEEXPRESSION
159 %type <value> E DELETE
160 %type <value> CONSTANT
161 %type <code> FOR IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
162 %type <token> USE_NAMESPACE
163 %type <code> FOR_INIT
165 %type <classinfo> MAYBETYPE
168 %type <params> PARAM_LIST
169 %type <params> MAYBE_PARAM_LIST
170 %type <flags> MAYBE_MODIFIERS
171 %type <flags> MODIFIER_LIST
172 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
173 %type <classinfo_list> IMPLEMENTS_LIST
174 %type <classinfo> EXTENDS
175 %type <classinfo_list> EXTENDS_LIST
176 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
177 %type <classinfo_list> QNAME_LIST
178 %type <classinfo> TYPE
180 //%type <token> VARIABLE
181 %type <value> VAR_READ
183 //%type <token> T_IDENTIFIER
184 %type <token> MODIFIER
185 %type <value> FUNCTIONCALL
186 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
188 // precedence: from low to high
192 %left below_semicolon
195 %nonassoc below_assignment // for ?:, contrary to spec
196 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
203 %nonassoc "==" "!=" "===" "!=="
205 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
206 %left "<<" ">>" ">>>"
210 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
212 %left '[' ']' '{' "new" '.' ".." "::"
213 %nonassoc T_IDENTIFIER
218 // needed for "return" precedence:
219 %nonassoc T_STRING T_REGEXP
220 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
221 %nonassoc "false" "true" "null" "undefined" "super"
226 static int yyerror(char*s)
228 syntaxerror("%s", s);
230 static char* concat3str(const char* t1, const char* t2, const char* t3)
235 char*text = malloc(l1+l2+l3+1);
236 memcpy(text , t1, l1);
237 memcpy(text+l1, t2, l2);
238 memcpy(text+l1+l2, t3, l3);
243 typedef struct _import {
247 DECLARE_LIST(import);
249 typedef struct _classstate {
255 char has_constructor;
258 typedef struct _methodstate {
262 /* code that needs to be executed at the start of
263 a method (like initializing local registers) */
269 typedef struct _state {
273 import_list_t*wildcard_imports;
275 char has_own_imports;
278 methodstate_t*method;
283 typedef struct _global {
290 static global_t*global = 0;
291 static state_t* state = 0;
295 #define MULTINAME(m,x) \
298 registry_fill_multiname(&m, &m##_ns, x);
300 #define MEMBER_MULTINAME(m,f,n) \
304 m##_ns.access = flags2access(f->flags); \
308 m.namespace_set = 0; \
311 m.type = MULTINAME; \
313 m.namespace_set = &nopackage_namespace_set; \
317 /* warning: list length of namespace set is undefined */
318 #define MULTINAME_LATE(m, access, package) \
319 namespace_t m##_ns = {access, package}; \
320 namespace_set_t m##_nsset; \
321 namespace_list_t m##_l;m##_l.next = 0; \
322 m##_nsset.namespaces = &m##_l; \
323 m##_nsset = m##_nsset; \
324 m##_l.namespace = &m##_ns; \
325 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
327 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
328 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
329 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
330 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
331 static namespace_list_t nl4 = {&ns4,0};
332 static namespace_list_t nl3 = {&ns3,&nl4};
333 static namespace_list_t nl2 = {&ns2,&nl3};
334 static namespace_list_t nl1 = {&ns1,&nl2};
335 static namespace_set_t nopackage_namespace_set = {&nl1};
337 static state_list_t*state_stack=0;
339 static void init_globals()
341 global = rfx_calloc(sizeof(global_t));
344 static void new_state()
347 NEW(state_list_t, sl);
349 state_t*oldstate = state;
351 memcpy(s, state, sizeof(state_t)); //shallow copy
352 sl->next = state_stack;
355 s->imports = dict_new();
360 state->has_own_imports = 0;
361 state->vars = dict_new();
363 static void state_has_imports()
365 state->wildcard_imports = list_clone(state->wildcard_imports);
366 state->imports = dict_clone(state->imports);
367 state->has_own_imports = 1;
370 static void old_state()
372 if(!state_stack || !state_stack->next)
373 syntaxerror("invalid nesting");
374 state_t*oldstate = state;
375 state_list_t*old = state_stack;
376 state_stack = state_stack->next;
378 state = state_stack->state;
379 /*if(state->method->initcode) {
380 printf("residual initcode\n");
381 code_dump(state->method->initcode, 0, 0, "", stdout);
383 if(oldstate->has_own_imports) {
384 list_free(oldstate->wildcard_imports);
385 dict_destroy(oldstate->imports);oldstate->imports=0;
388 void initialize_state()
393 global->file = abc_file_new();
394 global->file->flags &= ~ABCFILE_LAZY;
396 global->init = abc_initscript(global->file, 0);
397 code_t*c = global->init->method->body->code;
399 c = abc_getlocal_0(c);
400 c = abc_pushscope(c);
402 /* findpropstrict doesn't just return a scope object- it
403 also makes it "active" somehow. Push local_0 on the
404 scope stack and read it back with findpropstrict, it'll
405 contain properties like "trace". Trying to find the same
406 property on a "vanilla" local_0 yields only a "undefined" */
407 //c = abc_findpropstrict(c, "[package]::trace");
409 /*c = abc_getlocal_0(c);
410 c = abc_findpropstrict(c, "[package]::trace");
412 c = abc_setlocal_1(c);
414 c = abc_pushbyte(c, 0);
415 c = abc_setlocal_2(c);
417 code_t*xx = c = abc_label(c);
418 c = abc_findpropstrict(c, "[package]::trace");
419 c = abc_pushstring(c, "prop:");
420 c = abc_hasnext2(c, 1, 2);
422 c = abc_setlocal_3(c);
423 c = abc_callpropvoid(c, "[package]::trace", 2);
424 c = abc_getlocal_3(c);
426 c = abc_iftrue(c,xx);*/
428 c = abc_findpropstrict(c, "[package]::trace");
429 c = abc_pushstring(c, "[entering global init function]");
430 c = abc_callpropvoid(c, "[package]::trace", 1);
432 global->init->method->body->code = c;
434 void* finalize_state()
436 if(state->level!=1) {
437 syntaxerror("unexpected end of file");
439 abc_method_body_t*m = global->init->method->body;
442 __ findpropstrict(m, "[package]::trace");
443 __ pushstring(m, "[leaving global init function]");
444 __ callpropvoid(m, "[package]::trace", 1);
450 static void startpackage(char*name)
453 syntaxerror("Packages can not be nested.");
456 /*printf("entering package \"%s\"\n", name);*/
457 state->package = name;
459 static void endpackage()
461 /*printf("leaving package \"%s\"\n", state->package);*/
466 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
469 syntaxerror("inner classes now allowed");
472 state->cls = rfx_calloc(sizeof(classstate_t));
475 classinfo_list_t*mlist=0;
476 /*printf("entering class %s\n", name);
477 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
479 printf(" extends: %s.%s\n", extends->package, extends->name);
480 printf(" implements (%d): ", list_length(implements));
481 for(mlist=implements;mlist;mlist=mlist->next) {
482 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
487 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
488 syntaxerror("invalid modifier(s)");
490 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
491 syntaxerror("public and internal not supported at the same time.");
493 /* create the class name, together with the proper attributes */
497 if(!(flags&FLAG_PUBLIC) && !state->package) {
498 access = ACCESS_PRIVATE; package = current_filename;
499 } else if(!(flags&FLAG_PUBLIC) && state->package) {
500 access = ACCESS_PACKAGEINTERNAL; package = state->package;
501 } else if(state->package) {
502 access = ACCESS_PACKAGE; package = state->package;
504 syntaxerror("public classes only allowed inside a package");
507 if(registry_findclass(package, classname)) {
508 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
512 /* build info struct */
513 int num_interfaces = (list_length(implements));
514 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
515 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
517 classinfo_list_t*l = implements;
518 for(l=implements;l;l=l->next) {
519 state->cls->info->interfaces[pos++] = l->classinfo;
522 multiname_t*extends2 = sig2mname(extends);
524 MULTINAME(classname2,state->cls->info);
527 state->cls_init = abc_getlocal_0(state->cls_init);
528 state->cls_init = abc_constructsuper(state->cls_init, 0);
531 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
532 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
533 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
535 state->cls->info->flags |= CLASS_INTERFACE;
536 abc_class_interface(state->cls->abc);
539 abc_class_protectedNS(state->cls->abc, classname);
541 for(mlist=implements;mlist;mlist=mlist->next) {
542 MULTINAME(m, mlist->classinfo);
543 abc_class_add_interface(state->cls->abc, &m);
546 /* now write the construction code for this class */
547 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
549 abc_method_body_t*m = global->init->method->body;
550 __ getglobalscope(m);
551 classinfo_t*s = extends;
556 //TODO: take a look at the current scope stack, maybe
557 // we can re-use something
562 multiname_t*s2 = sig2mname(s);
564 multiname_destroy(s2);
566 __ pushscope(m); count++;
567 m->code = m->code->prev->prev; // invert
569 /* continue appending after last op end */
570 while(m->code && m->code->next) m->code = m->code->next;
572 /* TODO: if this is one of *our* classes, we can also
573 do a getglobalscope/getslot <nr> (which references
574 the init function's slots) */
576 __ getlex2(m, extends2);
578 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
579 stack is not the superclass */
580 __ pushscope(m);count++;
583 /* notice: we get a verify error #1107 if the top element on the scope
584 stack is not the global object */
586 __ pushscope(m);count++;
588 __ newclass(m,state->cls->abc);
592 __ setslot(m, slotindex);
594 /* flash.display.MovieClip handling */
595 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
596 if(state->package && state->package[0]) {
597 globalclass = concat3str(state->package, ".", classname);
599 globalclass = strdup(classname);
602 multiname_destroy(extends2);
605 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
607 c = code_append(c, initcode);
608 c = code_append(c, body);
609 /* append return if necessary */
610 if(!c || c->opcode != OPCODE_RETURNVOID &&
611 c->opcode != OPCODE_RETURNVALUE) {
612 c = abc_returnvoid(c);
617 static void endclass()
619 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
621 c = abc_getlocal_0(c);
622 c = abc_constructsuper(c, 0);
623 state->cls->init = code_append(state->cls->init, c);
626 if(state->cls->init) {
627 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
628 m->body->code = wrap_function(0, state->cls->init, m->body->code);
630 if(state->cls->static_init) {
631 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
632 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
634 // handy for scope testing
638 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
644 typedef struct _variable {
649 static int find_variable(char*name, classinfo_t**m)
651 state_list_t* s = state_stack;
655 v = dict_lookup(s->state->vars, name);
666 static int find_variable_safe(char*name, classinfo_t**m)
668 int i = find_variable(name, m);
670 syntaxerror("undefined variable: %s", name);
673 static char variable_exists(char*name)
675 return dict_lookup(state->vars, name)!=0;
677 static int new_variable(char*name, classinfo_t*type)
680 v->index = global->variable_count;
682 dict_put(state->vars, name, v);
683 return global->variable_count++;
685 #define TEMPVARNAME "__as3_temp__"
686 static int gettempvar()
688 int i = find_variable(TEMPVARNAME, 0);
690 i = new_variable(TEMPVARNAME, 0);
695 code_t* killvars(code_t*c)
698 for(t=0;t<state->vars->hashsize;t++) {
699 dictentry_t*e =state->vars->slots[t];
701 variable_t*v = (variable_t*)e->data;
702 //do this always, otherwise register types don't match
703 //in the verifier when doing nested loops
704 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
705 c = abc_kill(c, v->index);
712 void check_code_for_break(code_t*c)
715 if(c->opcode == OPCODE___BREAK__) {
716 char*name = string_cstr(c->data[0]);
717 syntaxerror("Unresolved \"break %s\"", name);
719 if(c->opcode == OPCODE___CONTINUE__) {
720 char*name = string_cstr(c->data[0]);
721 syntaxerror("Unresolved \"continue %s\"", name);
728 static void check_constant_against_type(classinfo_t*t, constant_t*c)
730 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
731 if(TYPE_IS_NUMBER(t)) {
732 xassert(c->type == CONSTANT_FLOAT
733 || c->type == CONSTANT_INT
734 || c->type == CONSTANT_UINT);
735 } else if(TYPE_IS_UINT(t)) {
736 xassert(c->type == CONSTANT_UINT ||
737 (c->type == CONSTANT_INT && c->i>0));
738 } else if(TYPE_IS_INT(t)) {
739 xassert(c->type == CONSTANT_INT);
740 } else if(TYPE_IS_BOOLEAN(t)) {
741 xassert(c->type == CONSTANT_TRUE
742 || c->type == CONSTANT_FALSE);
746 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
748 memberinfo_t*minfo = 0;
749 if(getset != KW_GET && getset != KW_SET) {
750 if(registry_findmember(state->cls->info, name)) {
751 syntaxerror("class already contains a member/method called '%s'", name);
753 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
754 minfo->return_type = return_type;
755 // getslot on a member slot only returns "undefined", so no need
756 // to actually store these
757 //state->minfo->slot = state->method->abc->method->trait->slot_id;
759 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
763 else if(params->list)
764 type = params->list->param->type;
765 if((minfo=registry_findmember(state->cls->info, name))) {
766 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
767 syntaxerror("class already contains a member or method called '%s'", name);
769 syntaxerror("getter/setter for '%s' already defined", name);
770 /* make a setter or getter into a getset */
775 if(type && minfo->type != type)
776 syntaxerror("different type in getter and setter");
778 minfo = memberinfo_register(state->cls->info, name, gs);
781 /* can't assign a slot as getter and setter might have different slots */
782 //minfo->slot = slot;
784 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
785 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
786 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
787 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
788 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
792 static int flags2access(int flags)
795 if(flags&FLAG_PUBLIC) {
796 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
797 access = ACCESS_PACKAGE;
798 } else if(flags&FLAG_PRIVATE) {
799 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
800 access = ACCESS_PRIVATE;
801 } else if(flags&FLAG_PROTECTED) {
802 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
803 access = ACCESS_PROTECTED;
805 access = ACCESS_PACKAGEINTERNAL;
810 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
811 params_t*params, classinfo_t*return_type)
814 syntaxerror("not able to start another method scope");
817 state->method = rfx_calloc(sizeof(methodstate_t));
818 state->method->initcode = 0;
819 state->method->is_constructor = !strcmp(state->cls->info->name,name);
820 state->method->has_super = 0;
822 state->cls->has_constructor |= state->method->is_constructor;
824 global->variable_count = 0;
826 /* state->vars is initialized by state_new */
827 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
829 for(p=params->list;p;p=p->next) {
830 new_variable(p->param->name, p->param->type);
832 if(state->method->is_constructor)
833 name = "__as3_constructor__";
834 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
837 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
838 params_t*params, classinfo_t*return_type, code_t*body)
840 namespace_t mname_ns = {flags2access(flags), ""};
841 multiname_t mname = {QNAME, &mname_ns, 0, name};
845 multiname_t*type2 = sig2mname(return_type);
847 if(state->method->is_constructor) {
848 f = abc_class_getconstructor(state->cls->abc, type2);
850 if(flags&FLAG_STATIC)
851 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
853 f = abc_class_method(state->cls->abc, type2, &mname);
854 slot = f->trait->slot_id;
856 //flash doesn't seem to allow us to access function slots
857 //state->method->info->slot = slot;
859 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
860 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
861 if(params->varargs) f->flags |= METHOD_NEED_REST;
865 for(p=params->list;p;p=p->next) {
866 if(params->varargs && !p->next) {
867 break; //varargs: omit last parameter in function signature
869 multiname_t*m = sig2mname(p->param->type);
870 list_append(f->parameters, m);
871 if(p->param->value) {
872 check_constant_against_type(p->param->type, p->param->value);
873 opt=1;list_append(f->optional_parameters, p->param->value);
875 syntaxerror("non-optional parameter not allowed after optional parameters");
878 check_code_for_break(body);
879 f->body->code = body;
886 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
891 void breakjumpsto(code_t*c, char*name, code_t*jump)
894 if(c->opcode == OPCODE___BREAK__) {
895 string_t*name2 = c->data[0];
896 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
897 c->opcode = OPCODE_JUMP;
904 void continuejumpsto(code_t*c, char*name, code_t*jump)
907 if(c->opcode == OPCODE___CONTINUE__) {
908 string_t*name2 = c->data[0];
909 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
910 c->opcode = OPCODE_JUMP;
918 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
921 return registry_getanytype();
922 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
923 return registry_getanytype();
926 return registry_getanytype();
928 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
933 return abc_coerce_a(c);
937 // cast an "any" type to a specific type. subject to
938 // runtime exceptions
939 return abc_coerce2(c, &m);
942 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
943 return abc_coerce2(c, &m);
945 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
946 return abc_coerce2(c, &m);
948 /* these are subject to overflow */
949 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
950 return abc_coerce2(c, &m);
952 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
953 return abc_coerce2(c, &m);
956 classinfo_t*supertype = from;
958 if(supertype == to) {
959 // target type is one of from's superclasses
960 return abc_coerce2(c, &m);
963 while(supertype->interfaces[t]) {
964 if(supertype->interfaces[t]==to) {
965 // to type is one of from's interfaces
966 return abc_coerce2(c, &m);
970 supertype = supertype->superclass;
972 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
974 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
976 syntaxerror("can't convert type %s to %s", from->name, to->name);
979 code_t*defaultvalue(code_t*c, classinfo_t*type)
981 if(TYPE_IS_INT(type)) {
982 c = abc_pushbyte(c, 0);
983 } else if(TYPE_IS_UINT(type)) {
984 c = abc_pushuint(c, 0);
985 } else if(TYPE_IS_FLOAT(type)) {
987 } else if(TYPE_IS_BOOLEAN(type)) {
988 c = abc_pushfalse(c);
995 char is_pushundefined(code_t*c)
997 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1000 void parserassert(int b)
1002 if(!b) syntaxerror("internal error: assertion failed");
1005 static classinfo_t* find_class(char*name)
1009 c = registry_findclass(state->package, name);
1011 /* try explicit imports */
1012 dictentry_t* e = dict_get_slot(state->imports, name);
1016 if(!strcmp(e->key, name)) {
1017 c = (classinfo_t*)e->data;
1022 /* try package.* imports */
1023 import_list_t*l = state->wildcard_imports;
1027 //printf("does package %s contain a class %s?\n", l->import->package, name);
1028 c = registry_findclass(l->import->package, name);
1032 /* try global package */
1034 c = registry_findclass("", name);
1039 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1043 [prefix code] [read instruction]
1047 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1050 if(in && in->opcode == OPCODE_COERCE_A) {
1051 in = code_cutlast(in);
1054 syntaxerror("internal error");
1056 /* chop off read instruction */
1060 prefix = r->prev;r->prev = 0;
1066 char use_temp_var = readbefore;
1068 /* generate the write instruction, and maybe append a dup to the prefix code */
1069 code_t* write = abc_nop(0);
1070 if(r->opcode == OPCODE_GETPROPERTY) {
1071 write->opcode = OPCODE_SETPROPERTY;
1072 multiname_t*m = (multiname_t*)r->data[0];
1073 write->data[0] = multiname_clone(m);
1074 if(m->type == QNAME || m->type == MULTINAME) {
1076 prefix = abc_dup(prefix); // we need the object, too
1079 } else if(m->type == MULTINAMEL) {
1081 /* dupping two values on the stack requires 5 operations and one register-
1082 couldn't adobe just have given us a dup2? */
1083 int temp = gettempvar();
1084 prefix = abc_setlocal(prefix, temp);
1085 prefix = abc_dup(prefix);
1086 prefix = abc_getlocal(prefix, temp);
1087 prefix = abc_swap(prefix);
1088 prefix = abc_getlocal(prefix, temp);
1092 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1094 } else if(r->opcode == OPCODE_GETSLOT) {
1095 write->opcode = OPCODE_SETSLOT;
1096 write->data[0] = r->data[0];
1098 prefix = abc_dup(prefix); // we need the object, too
1101 } else if(r->opcode == OPCODE_GETLOCAL) {
1102 write->opcode = OPCODE_SETLOCAL;
1103 write->data[0] = r->data[0];
1104 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1105 write->opcode = OPCODE_SETLOCAL_0;
1106 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1107 write->opcode = OPCODE_SETLOCAL_1;
1108 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1109 write->opcode = OPCODE_SETLOCAL_2;
1110 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1111 write->opcode = OPCODE_SETLOCAL_3;
1113 code_dump(r, 0, 0, "", stdout);
1114 syntaxerror("illegal lvalue: can't assign a value to this expression");
1121 /* with getproperty/getslot, we have to be extra careful not
1122 to execute the read code twice, as it might have side-effects
1123 (e.g. if the property is in fact a setter/getter combination)
1125 So read the value, modify it, and write it again,
1126 using prefix only once and making sure (by using a temporary
1127 register) that the return value is what we just wrote */
1128 temp = gettempvar();
1129 c = code_append(c, prefix);
1130 c = code_append(c, r);
1133 c = abc_setlocal(c, temp);
1135 c = code_append(c, middlepart);
1138 c = abc_setlocal(c, temp);
1140 c = code_append(c, write);
1141 c = abc_getlocal(c, temp);
1142 c = abc_kill(c, temp);
1144 /* if we're allowed to execute the read code twice *and*
1145 the middlepart doesn't modify the code, things are easier.
1147 code_t* r2 = code_dup(r);
1148 //c = code_append(c, prefix);
1149 parserassert(!prefix);
1150 c = code_append(c, r);
1151 c = code_append(c, middlepart);
1152 c = code_append(c, write);
1153 c = code_append(c, r2);
1156 /* even smaller version: overwrite the value without reading
1160 c = code_append(c, prefix);
1163 c = code_append(c, middlepart);
1164 c = code_append(c, write);
1165 c = code_append(c, r);
1167 temp = gettempvar();
1169 c = code_append(c, prefix);
1172 c = code_append(c, middlepart);
1174 c = abc_setlocal(c, temp);
1175 c = code_append(c, write);
1176 c = abc_getlocal(c, temp);
1183 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1184 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1191 /* ------------ code blocks / statements ---------------- */
1195 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1196 MAYBECODE: {$$=code_new();}
1198 CODE: CODE CODEPIECE {
1199 $$=code_append($1,$2);
1205 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1206 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1207 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1208 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1209 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1210 CODEPIECE: ';' {$$=code_new();}
1211 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1212 CODEPIECE: VOIDEXPRESSION {$$=$1}
1213 CODEPIECE: FOR {$$=$1}
1214 CODEPIECE: WHILE {$$=$1}
1215 CODEPIECE: DO_WHILE {$$=$1}
1216 CODEPIECE: BREAK {$$=$1}
1217 CODEPIECE: CONTINUE {$$=$1}
1218 CODEPIECE: RETURN {$$=$1}
1219 CODEPIECE: IF {$$=$1}
1220 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1221 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1223 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1224 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1225 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1227 /* ------------ variables --------------------------- */
1229 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1230 | {$$.c=abc_pushundefined(0);
1234 VAR : "const" | "var"
1235 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1237 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1238 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1240 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1242 if(variable_exists($2))
1243 syntaxerror("Variable %s already defined", $2);
1245 if(!is_subtype_of($4.t, $3)) {
1246 syntaxerror("Can't convert %s to %s", $4.t->name,
1250 int index = new_variable($2, $3);
1253 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1255 $$ = converttype($$, $4.t, $3);
1256 $$ = abc_setlocal($$, index);
1258 $$ = defaultvalue(0, $3);
1259 $$ = abc_setlocal($$, index);
1262 /* if this is a typed variable:
1263 push default value for type on stack */
1265 state->method->initcode = defaultvalue(state->method->initcode, $3);
1266 state->method->initcode = abc_setlocal(state->method->initcode, index);
1269 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1271 $$ = abc_coerce_a($$);
1272 $$ = abc_setlocal($$, index);
1278 /* that's the default for a local register, anyway
1280 state->method->initcode = abc_pushundefined(state->method->initcode);
1281 state->method->initcode = abc_setlocal(state->method->initcode, index);
1283 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1286 /* ------------ control flow ------------------------- */
1288 MAYBEELSE: %prec below_else {$$ = code_new();}
1289 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1290 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1292 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1294 $$ = code_append($$, $4.c);
1295 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1297 $$ = code_append($$, $6);
1299 myjmp = $$ = abc_jump($$, 0);
1301 myif->branch = $$ = abc_nop($$);
1303 $$ = code_append($$, $7);
1304 myjmp->branch = $$ = abc_nop($$);
1307 $$ = killvars($$);old_state();
1310 MAYBELABEL : T_IDENTIFIER ':' {$$=$1;}
1311 MAYBELABEL : {$$="";}
1313 FOR_INIT : {$$=code_new();}
1314 FOR_INIT : VARIABLE_DECLARATION
1315 FOR_INIT : VOIDEXPRESSION
1317 FOR : MAYBELABEL "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1319 $$ = code_append($$, $5);
1320 code_t*loopstart = $$ = abc_label($$);
1321 $$ = code_append($$, $7.c);
1322 code_t*myif = $$ = abc_iffalse($$, 0);
1323 $$ = code_append($$, $11);
1324 code_t*cont = $$ = abc_nop($$);
1325 $$ = code_append($$, $9);
1326 $$ = abc_jump($$, loopstart);
1327 code_t*out = $$ = abc_nop($$);
1328 breakjumpsto($$, $1, out);
1329 continuejumpsto($$, $1, cont);
1332 $$ = killvars($$);old_state();
1335 WHILE : MAYBELABEL "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1338 code_t*myjmp = $$ = abc_jump($$, 0);
1339 code_t*loopstart = $$ = abc_label($$);
1340 $$ = code_append($$, $7);
1341 myjmp->branch = $$ = abc_nop($$);
1342 $$ = code_append($$, $5.c);
1343 $$ = abc_iftrue($$, loopstart);
1344 code_t*out = $$ = abc_nop($$);
1345 breakjumpsto($$, $1, out);
1346 continuejumpsto($$, $1, loopstart);
1352 DO_WHILE : MAYBELABEL "do" {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1354 code_t*loopstart = $$ = abc_label($$);
1355 $$ = code_append($$, $4);
1356 code_t*cont = $$ = abc_nop($$);
1357 $$ = code_append($$, $7.c);
1358 $$ = abc_iftrue($$, loopstart);
1359 code_t*out = $$ = abc_nop($$);
1360 breakjumpsto($$, $1, out);
1361 continuejumpsto($$, $1, cont);
1366 BREAK : "break" %prec prec_none {
1367 $$ = abc___break__(0, "");
1369 BREAK : "break" T_IDENTIFIER {
1370 $$ = abc___break__(0, $2);
1372 CONTINUE : "continue" %prec prec_none {
1373 $$ = abc___continue__(0, "");
1375 CONTINUE : "continue" T_IDENTIFIER {
1376 $$ = abc___continue__(0, $2);
1379 /* ------------ packages and imports ---------------- */
1381 X_IDENTIFIER: T_IDENTIFIER
1382 | "package" {$$="package";}
1384 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1385 PACKAGE: X_IDENTIFIER {$$=$1;}
1387 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1388 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1390 IMPORT : "import" QNAME {
1393 syntaxerror("Couldn't import class\n");
1394 state_has_imports();
1395 dict_put(state->imports, c->name, c);
1398 IMPORT : "import" PACKAGE '.' '*' {
1401 state_has_imports();
1402 list_append(state->wildcard_imports, i);
1406 /* ------------ classes and interfaces (header) -------------- */
1408 MAYBE_MODIFIERS : {$$=0;}
1409 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1410 MODIFIER_LIST : MODIFIER {$$=$1;}
1411 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1413 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1414 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1415 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1416 | KW_STATIC {$$=FLAG_STATIC;}
1417 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1418 | KW_FINAL {$$=FLAG_FINAL;}
1419 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1420 | KW_NATIVE {$$=FLAG_NATIVE;}
1421 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1423 EXTENDS : {$$=registry_getobjectclass();}
1424 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1426 EXTENDS_LIST : {$$=list_new();}
1427 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1429 IMPLEMENTS_LIST : {$$=list_new();}
1430 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1432 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1433 EXTENDS IMPLEMENTS_LIST
1434 '{' {startclass($1,$3,$4,$5, 0);}
1435 MAYBE_DECLARATION_LIST
1438 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1440 '{' {startclass($1,$3,0,$4,1);}
1441 MAYBE_IDECLARATION_LIST
1444 /* ------------ classes and interfaces (body) -------------- */
1446 MAYBE_DECLARATION_LIST :
1447 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1448 DECLARATION_LIST : DECLARATION
1449 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1451 DECLARATION : SLOT_DECLARATION
1452 DECLARATION : FUNCTION_DECLARATION
1454 MAYBE_IDECLARATION_LIST :
1455 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1456 IDECLARATION_LIST : IDECLARATION
1457 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1459 IDECLARATION : "var" T_IDENTIFIER {
1460 syntaxerror("variable declarations not allowed in interfaces");
1462 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1464 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1465 syntaxerror("invalid method modifiers: interface methods always need to be public");
1467 startfunction(0,$1,$3,$4,&$6,$8);
1468 endfunction(0,$1,$3,$4,&$6,$8, 0);
1471 /* ------------ classes and interfaces (body, slots ) ------- */
1473 VARCONST: "var" | "const"
1475 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1477 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1479 info->flags = flags;
1482 namespace_t mname_ns = {flags2access(flags), ""};
1483 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1485 if(!(flags&FLAG_STATIC)) {
1488 t=abc_class_slot(state->cls->abc, &mname, &m);
1490 t=abc_class_slot(state->cls->abc, &mname, 0);
1492 info->slot = t->slot_id;
1496 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1498 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1500 info->slot = t->slot_id;
1502 if($5.c && !is_pushundefined($5.c)) {
1504 c = abc_getlocal_0(c);
1505 c = code_append(c, $5.c);
1506 c = converttype(c, $5.t, $4);
1507 c = abc_setslot(c, t->slot_id);
1508 if(!(flags&FLAG_STATIC))
1509 state->cls->init = code_append(state->cls->init, c);
1511 state->cls->static_init = code_append(state->cls->static_init, c);
1514 t->kind= TRAIT_CONST;
1518 /* ------------ constants -------------------------------------- */
1520 MAYBESTATICCONSTANT: {$$=0;}
1521 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1523 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1524 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1525 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1526 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1527 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1528 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1529 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1530 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1531 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1533 /* ------------ classes and interfaces (body, functions) ------- */
1535 // non-vararg version
1537 memset(&$$,0,sizeof($$));
1539 MAYBE_PARAM_LIST: PARAM_LIST {
1544 MAYBE_PARAM_LIST: "..." PARAM {
1545 memset(&$$,0,sizeof($$));
1547 list_append($$.list, $2);
1549 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1552 list_append($$.list, $4);
1556 PARAM_LIST: PARAM_LIST ',' PARAM {
1558 list_append($$.list, $3);
1561 memset(&$$,0,sizeof($$));
1562 list_append($$.list, $1);
1565 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1566 $$ = malloc(sizeof(param_t));
1571 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1572 $$ = malloc(sizeof(param_t));
1574 $$->type = TYPE_ANY;
1577 GETSET : "get" {$$=$1;}
1581 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1582 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1585 if(state->method->late_binding) {
1586 c = abc_getlocal_0(c);
1587 c = abc_pushscope(c);
1589 if(state->method->is_constructor && !state->method->has_super) {
1590 // call default constructor
1591 c = abc_getlocal_0(c);
1592 c = abc_constructsuper(c, 0);
1594 c = wrap_function(c, state->method->initcode, $11);
1595 endfunction(0,$1,$3,$4,&$6,$8,c);
1598 /* ------------- package + class ids --------------- */
1600 CLASS: T_IDENTIFIER {
1602 /* try current package */
1603 $$ = find_class($1);
1604 if(!$$) syntaxerror("Could not find class %s\n", $1);
1607 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1608 $$ = registry_findclass($1, $3);
1609 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1612 QNAME: PACKAGEANDCLASS
1615 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1616 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1618 TYPE : QNAME {$$=$1;}
1619 | '*' {$$=registry_getanytype();}
1621 | "String" {$$=registry_getstringclass();}
1622 | "int" {$$=registry_getintclass();}
1623 | "uint" {$$=registry_getuintclass();}
1624 | "Boolean" {$$=registry_getbooleanclass();}
1625 | "Number" {$$=registry_getnumberclass();}
1628 MAYBETYPE: ':' TYPE {$$=$2;}
1631 /* ----------function calls, delete, constructor calls ------ */
1633 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1634 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1636 MAYBE_EXPRESSION_LIST : {$$=0;}
1637 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1638 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1639 typedcode_t*t = malloc(sizeof(typedcode_t));
1641 list_append($$, t);}
1642 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1643 typedcode_t*t = malloc(sizeof(typedcode_t));
1645 list_append($$, t);}
1647 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1652 $$.c = abc_getglobalscope($$.c);
1653 $$.c = abc_getslot($$.c, $2->slot);
1655 $$.c = abc_findpropstrict2($$.c, &m);
1658 typedcode_list_t*l = $3;
1661 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1666 $$.c = abc_construct($$.c, len);
1668 $$.c = abc_constructprop2($$.c, &m, len);
1672 /* TODO: use abc_call (for calling local variables),
1673 abc_callstatic (for calling own methods)
1676 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1677 typedcode_list_t*l = $3;
1679 code_t*paramcode = 0;
1681 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1687 if($$.c->opcode == OPCODE_COERCE_A) {
1688 $$.c = code_cutlast($$.c);
1692 multiname_t*name = 0;
1693 if($$.c->opcode == OPCODE_GETPROPERTY) {
1694 name = multiname_clone($$.c->data[0]);
1695 $$.c = code_cutlast($$.c);
1696 $$.c = code_append($$.c, paramcode);
1697 $$.c = abc_callproperty2($$.c, name, len);
1698 } else if($$.c->opcode == OPCODE_GETSLOT) {
1699 int slot = (int)(ptroff_t)$$.c->data[0];
1700 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1701 if(t->kind!=TRAIT_METHOD) {
1702 //ok: flash allows to assign closures to members.
1705 $$.c = code_cutlast($$.c);
1706 $$.c = code_append($$.c, paramcode);
1707 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1708 $$.c = abc_callproperty2($$.c, name, len);
1709 } else if($$.c->opcode == OPCODE_GETSUPER) {
1710 name = multiname_clone($$.c->data[0]);
1711 $$.c = code_cutlast($$.c);
1712 $$.c = code_append($$.c, paramcode);
1713 $$.c = abc_callsuper2($$.c, name, len);
1715 $$.c = abc_getlocal_0($$.c);
1716 $$.c = code_append($$.c, paramcode);
1717 $$.c = abc_call($$.c, len);
1722 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1723 $$.t = $1.t->function->return_type;
1725 $$.c = abc_coerce_a($$.c);
1729 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1730 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1731 if(!state->method) syntaxerror("super() not allowed outside of a function");
1732 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1735 $$.c = abc_getlocal_0($$.c);
1736 typedcode_list_t*l = 0;
1738 for(l=$3;l;l=l->next) {
1739 $$.c = code_append($$.c, l->typedcode->c);len++;
1742 this is dependent on the control path, check this somewhere else
1743 if(state->method->has_super)
1744 syntaxerror("constructor may call super() only once");
1746 state->method->has_super = 1;
1747 $$.c = abc_constructsuper($$.c, len);
1748 $$.c = abc_pushundefined($$.c);
1752 DELETE: "delete" E {
1754 if($$.c->opcode == OPCODE_COERCE_A) {
1755 $$.c = code_cutlast($$.c);
1757 multiname_t*name = 0;
1758 if($$.c->opcode == OPCODE_GETPROPERTY) {
1759 $$.c->opcode = OPCODE_DELETEPROPERTY;
1760 } else if($$.c->opcode == OPCODE_GETSLOT) {
1761 int slot = (int)(ptroff_t)$$.c->data[0];
1762 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1763 $$.c = code_cutlast($$.c);
1764 $$.c = abc_deleteproperty2($$.c, name);
1766 $$.c = abc_getlocal_0($$.c);
1767 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1768 $$.c = abc_deleteproperty2($$.c, &m);
1770 $$.t = TYPE_BOOLEAN;
1773 RETURN: "return" %prec prec_none {
1774 $$ = abc_returnvoid(0);
1776 RETURN: "return" EXPRESSION {
1778 $$ = abc_returnvalue($$);
1781 // ----------------------- expression types -------------------------------------
1783 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1784 EXPRESSION : E %prec below_minus {$$ = $1;}
1785 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1787 $$.c = cut_last_push($$.c);
1788 $$.c = code_append($$.c,$3.c);
1791 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1792 $$=cut_last_push($1.c);
1795 // ----------------------- expression evaluation -------------------------------------
1798 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1800 E : DELETE {$$ = $1;}
1801 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1805 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1806 //MULTINAME(m, registry_getintclass());
1807 //$$.c = abc_coerce2($$.c, &m); // FIXME
1810 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1813 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1816 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1819 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1822 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1825 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1828 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1829 $$.t = TYPE_BOOLEAN;
1831 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1832 $$.t = TYPE_BOOLEAN;
1834 CONSTANT : "null" {$$.c = abc_pushnull(0);
1839 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1840 $$.t = TYPE_BOOLEAN;
1842 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1843 $$.t = TYPE_BOOLEAN;
1845 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1846 $$.t = TYPE_BOOLEAN;
1848 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1849 $$.t = TYPE_BOOLEAN;
1851 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1852 $$.t = TYPE_BOOLEAN;
1854 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1855 $$.t = TYPE_BOOLEAN;
1857 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1858 $$.t = TYPE_BOOLEAN;
1860 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1861 $$.t = TYPE_BOOLEAN;
1864 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1866 $$.c = converttype($$.c, $1.t, $$.t);
1867 $$.c = abc_dup($$.c);
1868 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1869 $$.c = cut_last_push($$.c);
1870 $$.c = code_append($$.c,$3.c);
1871 $$.c = converttype($$.c, $3.t, $$.t);
1872 code_t*label = $$.c = abc_label($$.c);
1873 jmp->branch = label;
1876 $$.t = join_types($1.t, $3.t, 'A');
1877 /*printf("%08x:\n",$1.t);
1878 code_dump($1.c, 0, 0, "", stdout);
1879 printf("%08x:\n",$3.t);
1880 code_dump($3.c, 0, 0, "", stdout);
1881 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1883 $$.c = converttype($$.c, $1.t, $$.t);
1884 $$.c = abc_dup($$.c);
1885 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1886 $$.c = cut_last_push($$.c);
1887 $$.c = code_append($$.c,$3.c);
1888 $$.c = converttype($$.c, $3.t, $$.t);
1889 code_t*label = $$.c = abc_label($$.c);
1890 jmp->branch = label;
1893 E : '!' E {$$.c=$2.c;
1894 $$.c = abc_not($$.c);
1895 $$.t = TYPE_BOOLEAN;
1898 E : '~' E {$$.c=$2.c;
1899 $$.c = abc_bitnot($$.c);
1903 E : E '&' E {$$.c = code_append($1.c,$3.c);
1904 $$.c = abc_bitand($$.c);
1908 E : E '^' E {$$.c = code_append($1.c,$3.c);
1909 $$.c = abc_bitxor($$.c);
1913 E : E '|' E {$$.c = code_append($1.c,$3.c);
1914 $$.c = abc_bitor($$.c);
1918 E : E '-' E {$$.c = code_append($1.c,$3.c);
1919 if(BOTH_INT($1,$3)) {
1920 $$.c = abc_subtract_i($$.c);
1923 $$.c = abc_subtract($$.c);
1927 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1928 $$.c = abc_rshift($$.c);
1931 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1932 $$.c = abc_urshift($$.c);
1935 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1936 $$.c = abc_lshift($$.c);
1940 E : E '/' E {$$.c = code_append($1.c,$3.c);
1941 $$.c = abc_divide($$.c);
1944 E : E '+' E {$$.c = code_append($1.c,$3.c);
1945 $$.c = abc_add($$.c);
1948 E : E '%' E {$$.c = code_append($1.c,$3.c);
1949 $$.c = abc_modulo($$.c);
1952 E : E '*' E {$$.c = code_append($1.c,$3.c);
1953 if(BOTH_INT($1,$3)) {
1954 $$.c = abc_multiply_i($$.c);
1957 $$.c = abc_multiply($$.c);
1962 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1963 if(use_astype && TYPE_IS_CLASS($3.t)) {
1964 MULTINAME(m,$3.t->cls);
1965 $$.c = abc_astype2($1.c, &m);
1968 $$.c = code_append($1.c, $3.c);
1969 $$.c = abc_astypelate($$.c);
1974 E : E "instanceof" E
1975 {$$.c = code_append($1.c, $3.c);
1976 $$.c = abc_instanceof($$.c);
1977 $$.t = TYPE_BOOLEAN;
1980 E : E "is" E {$$.c = code_append($1.c, $3.c);
1981 $$.c = abc_istypelate($$.c);
1982 $$.t = TYPE_BOOLEAN;
1985 E : "typeof" '(' E ')' {
1987 $$.c = abc_typeof($$.c);
1992 $$.c = cut_last_push($2.c);
1993 $$.c = abc_pushundefined($$.c);
1997 E : "void" { $$.c = abc_pushundefined(0);
2001 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2006 $$.c=abc_negate_i($$.c);
2009 $$.c=abc_negate($$.c);
2016 $$.c = code_append($$.c, $3.c);
2018 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2019 $$.c = abc_getproperty2($$.c, &m);
2020 $$.t = 0; // array elements have unknown type
2023 E : '[' MAYBE_EXPRESSION_LIST ']' {
2025 typedcode_list_t*l = 0;
2027 for(l=$2;l;l=l->next) {
2028 $$.c = code_append($$.c, l->typedcode->c);len++;
2030 $$.c = abc_newarray($$.c, len);
2031 $$.t = registry_getarrayclass();
2036 if(BOTH_INT($1,$3)) {
2037 c=abc_multiply_i(c);
2041 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2042 $$.c = toreadwrite($1.c, c, 0, 0);
2047 code_t*c = abc_modulo($3.c);
2048 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2049 $$.c = toreadwrite($1.c, c, 0, 0);
2053 code_t*c = abc_lshift($3.c);
2054 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2055 $$.c = toreadwrite($1.c, c, 0, 0);
2059 code_t*c = abc_rshift($3.c);
2060 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2061 $$.c = toreadwrite($1.c, c, 0, 0);
2065 code_t*c = abc_urshift($3.c);
2066 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2067 $$.c = toreadwrite($1.c, c, 0, 0);
2071 code_t*c = abc_divide($3.c);
2072 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2073 $$.c = toreadwrite($1.c, c, 0, 0);
2078 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2083 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2085 $$.c = toreadwrite($1.c, c, 0, 0);
2088 E : E "-=" E { code_t*c = $3.c;
2089 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2090 c=abc_subtract_i(c);
2094 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2096 $$.c = toreadwrite($1.c, c, 0, 0);
2099 E : E '=' E { code_t*c = 0;
2100 c = code_append(c, $3.c);
2101 c = converttype(c, $3.t, $1.t);
2102 $$.c = toreadwrite($1.c, c, 1, 0);
2106 E : E '?' E ':' E %prec below_assignment {
2108 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2109 $$.c = code_append($$.c, $3.c);
2110 code_t*j2 = $$.c = abc_jump($$.c, 0);
2111 $$.c = j1->branch = abc_label($$.c);
2112 $$.c = code_append($$.c, $5.c);
2113 $$.c = j2->branch = abc_label($$.c);
2114 $$.t = join_types($3.t,$5.t,'?');
2117 // TODO: use inclocal where appropriate
2118 E : E "++" { code_t*c = 0;
2119 classinfo_t*type = $1.t;
2120 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2121 c=abc_increment_i(c);
2127 c=converttype(c, type, $1.t);
2128 $$.c = toreadwrite($1.c, c, 0, 1);
2131 E : E "--" { code_t*c = 0;
2132 classinfo_t*type = $1.t;
2133 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2134 c=abc_decrement_i(c);
2140 c=converttype(c, type, $1.t);
2141 $$.c = toreadwrite($1.c, c, 0, 1);
2145 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2146 classinfo_t*type = $2.t;
2147 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2148 c=abc_increment_i(c);
2154 c=converttype(c, type, $2.t);
2155 $$.c = toreadwrite($2.c, c, 0, 0);
2159 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2160 classinfo_t*type = $2.t;
2161 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2162 c=abc_decrement_i(c);
2168 c=converttype(c, type, $2.t);
2169 $$.c = toreadwrite($2.c, c, 0, 0);
2173 E : "super" '.' T_IDENTIFIER
2174 { if(!state->cls->info)
2175 syntaxerror("super keyword not allowed outside a class");
2176 classinfo_t*t = state->cls->info->superclass;
2177 if(!t) t = TYPE_OBJECT;
2179 memberinfo_t*f = registry_findmember(t, $3);
2180 namespace_t ns = {flags2access(f->flags), ""};
2181 MEMBER_MULTINAME(m, f, $3);
2183 $$.c = abc_getlocal_0($$.c);
2184 $$.c = abc_getsuper2($$.c, &m);
2185 $$.t = memberinfo_gettype(f);
2188 E : E '.' T_IDENTIFIER
2190 classinfo_t*t = $1.t;
2192 if(TYPE_IS_CLASS(t) && t->cls) {
2197 memberinfo_t*f = registry_findmember(t, $3);
2199 if(f && !is_static != !(f->flags&FLAG_STATIC))
2201 if(f && f->slot && !noslot) {
2202 $$.c = abc_getslot($$.c, f->slot);
2204 MEMBER_MULTINAME(m, f, $3);
2205 $$.c = abc_getproperty2($$.c, &m);
2207 /* determine type */
2208 $$.t = memberinfo_gettype(f);
2210 $$.c = abc_coerce_a($$.c);
2212 /* when resolving a property on an unknown type, we do know the
2213 name of the property (and don't seem to need the package), but
2214 we need to make avm2 try out all access modes */
2215 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2216 $$.c = abc_getproperty2($$.c, &m);
2217 $$.c = abc_coerce_a($$.c);
2218 $$.t = registry_getanytype();
2222 VAR_READ : T_IDENTIFIER {
2229 /* look at variables */
2230 if((i = find_variable($1, &$$.t)) >= 0) {
2231 // $1 is a local variable
2232 $$.c = abc_getlocal($$.c, i);
2234 /* look at current class' members */
2235 } else if((f = registry_findmember(state->cls->info, $1))) {
2236 // $1 is a function in this class
2237 int var_is_static = (f->flags&FLAG_STATIC);
2238 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2239 if(var_is_static != i_am_static) {
2240 /* there doesn't seem to be any "static" way to access
2241 static properties of a class */
2242 state->method->late_binding = 1;
2244 namespace_t ns = {flags2access(f->flags), ""};
2245 multiname_t m = {QNAME, &ns, 0, $1};
2246 $$.c = abc_findpropstrict2($$.c, &m);
2247 $$.c = abc_getproperty2($$.c, &m);
2250 $$.c = abc_getlocal_0($$.c);
2251 $$.c = abc_getslot($$.c, f->slot);
2253 namespace_t ns = {flags2access(f->flags), ""};
2254 multiname_t m = {QNAME, &ns, 0, $1};
2255 $$.c = abc_getlocal_0($$.c);
2256 $$.c = abc_getproperty2($$.c, &m);
2259 if(f->kind == MEMBER_METHOD) {
2260 $$.t = TYPE_FUNCTION(f);
2265 /* look at classes in the current package and imported classes */
2266 } else if((a = find_class($1))) {
2267 if(a->flags & FLAG_METHOD) {
2269 $$.c = abc_findpropstrict2($$.c, &m);
2270 $$.c = abc_getproperty2($$.c, &m);
2271 $$.t = TYPE_FUNCTION(a->function);
2274 $$.c = abc_getglobalscope($$.c);
2275 $$.c = abc_getslot($$.c, a->slot);
2278 $$.c = abc_getlex2($$.c, &m);
2280 $$.t = TYPE_CLASS(a);
2283 /* unknown object, let the avm2 resolve it */
2285 if(strcmp($1,"trace"))
2286 warning("Couldn't resolve '%s', doing late binding", $1);
2287 state->method->late_binding = 1;
2289 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2292 $$.c = abc_findpropstrict2($$.c, &m);
2293 $$.c = abc_getproperty2($$.c, &m);
2298 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2299 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2300 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2302 // ----------------- namespaces -------------------------------------------------
2304 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2305 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2306 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2308 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER