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);
881 f->body->code = body;
884 syntaxerror("interface methods can't have a method body");
891 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
896 void breakjumpsto(code_t*c, char*name, code_t*jump)
899 if(c->opcode == OPCODE___BREAK__) {
900 string_t*name2 = c->data[0];
901 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
902 c->opcode = OPCODE_JUMP;
909 void continuejumpsto(code_t*c, char*name, code_t*jump)
912 if(c->opcode == OPCODE___CONTINUE__) {
913 string_t*name2 = c->data[0];
914 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
915 c->opcode = OPCODE_JUMP;
923 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
926 return registry_getanytype();
927 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
928 return registry_getanytype();
931 return registry_getanytype();
933 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
938 return abc_coerce_a(c);
942 // cast an "any" type to a specific type. subject to
943 // runtime exceptions
944 return abc_coerce2(c, &m);
947 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
948 return abc_coerce2(c, &m);
950 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
951 return abc_coerce2(c, &m);
953 /* these are subject to overflow */
954 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
955 return abc_coerce2(c, &m);
957 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
958 return abc_coerce2(c, &m);
961 classinfo_t*supertype = from;
963 if(supertype == to) {
964 // target type is one of from's superclasses
965 return abc_coerce2(c, &m);
968 while(supertype->interfaces[t]) {
969 if(supertype->interfaces[t]==to) {
970 // to type is one of from's interfaces
971 return abc_coerce2(c, &m);
975 supertype = supertype->superclass;
977 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
979 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
981 syntaxerror("can't convert type %s to %s", from->name, to->name);
984 code_t*defaultvalue(code_t*c, classinfo_t*type)
986 if(TYPE_IS_INT(type)) {
987 c = abc_pushbyte(c, 0);
988 } else if(TYPE_IS_UINT(type)) {
989 c = abc_pushuint(c, 0);
990 } else if(TYPE_IS_FLOAT(type)) {
992 } else if(TYPE_IS_BOOLEAN(type)) {
993 c = abc_pushfalse(c);
1000 char is_pushundefined(code_t*c)
1002 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1005 void parserassert(int b)
1007 if(!b) syntaxerror("internal error: assertion failed");
1010 static classinfo_t* find_class(char*name)
1014 c = registry_findclass(state->package, name);
1016 /* try explicit imports */
1017 dictentry_t* e = dict_get_slot(state->imports, name);
1021 if(!strcmp(e->key, name)) {
1022 c = (classinfo_t*)e->data;
1027 /* try package.* imports */
1028 import_list_t*l = state->wildcard_imports;
1032 //printf("does package %s contain a class %s?\n", l->import->package, name);
1033 c = registry_findclass(l->import->package, name);
1037 /* try global package */
1039 c = registry_findclass("", name);
1044 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1048 [prefix code] [read instruction]
1052 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1055 if(in && in->opcode == OPCODE_COERCE_A) {
1056 in = code_cutlast(in);
1059 syntaxerror("internal error");
1061 /* chop off read instruction */
1065 prefix = r->prev;r->prev = 0;
1071 char use_temp_var = readbefore;
1073 /* generate the write instruction, and maybe append a dup to the prefix code */
1074 code_t* write = abc_nop(0);
1075 if(r->opcode == OPCODE_GETPROPERTY) {
1076 write->opcode = OPCODE_SETPROPERTY;
1077 multiname_t*m = (multiname_t*)r->data[0];
1078 write->data[0] = multiname_clone(m);
1079 if(m->type == QNAME || m->type == MULTINAME) {
1081 prefix = abc_dup(prefix); // we need the object, too
1084 } else if(m->type == MULTINAMEL) {
1086 /* dupping two values on the stack requires 5 operations and one register-
1087 couldn't adobe just have given us a dup2? */
1088 int temp = gettempvar();
1089 prefix = abc_setlocal(prefix, temp);
1090 prefix = abc_dup(prefix);
1091 prefix = abc_getlocal(prefix, temp);
1092 prefix = abc_swap(prefix);
1093 prefix = abc_getlocal(prefix, temp);
1097 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1099 } else if(r->opcode == OPCODE_GETSLOT) {
1100 write->opcode = OPCODE_SETSLOT;
1101 write->data[0] = r->data[0];
1103 prefix = abc_dup(prefix); // we need the object, too
1106 } else if(r->opcode == OPCODE_GETLOCAL) {
1107 write->opcode = OPCODE_SETLOCAL;
1108 write->data[0] = r->data[0];
1109 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1110 write->opcode = OPCODE_SETLOCAL_0;
1111 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1112 write->opcode = OPCODE_SETLOCAL_1;
1113 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1114 write->opcode = OPCODE_SETLOCAL_2;
1115 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1116 write->opcode = OPCODE_SETLOCAL_3;
1118 code_dump(r, 0, 0, "", stdout);
1119 syntaxerror("illegal lvalue: can't assign a value to this expression");
1126 /* with getproperty/getslot, we have to be extra careful not
1127 to execute the read code twice, as it might have side-effects
1128 (e.g. if the property is in fact a setter/getter combination)
1130 So read the value, modify it, and write it again,
1131 using prefix only once and making sure (by using a temporary
1132 register) that the return value is what we just wrote */
1133 temp = gettempvar();
1134 c = code_append(c, prefix);
1135 c = code_append(c, r);
1138 c = abc_setlocal(c, temp);
1140 c = code_append(c, middlepart);
1143 c = abc_setlocal(c, temp);
1145 c = code_append(c, write);
1146 c = abc_getlocal(c, temp);
1147 c = abc_kill(c, temp);
1149 /* if we're allowed to execute the read code twice *and*
1150 the middlepart doesn't modify the code, things are easier.
1152 code_t* r2 = code_dup(r);
1153 //c = code_append(c, prefix);
1154 parserassert(!prefix);
1155 c = code_append(c, r);
1156 c = code_append(c, middlepart);
1157 c = code_append(c, write);
1158 c = code_append(c, r2);
1161 /* even smaller version: overwrite the value without reading
1165 c = code_append(c, prefix);
1168 c = code_append(c, middlepart);
1169 c = code_append(c, write);
1170 c = code_append(c, r);
1172 temp = gettempvar();
1174 c = code_append(c, prefix);
1177 c = code_append(c, middlepart);
1179 c = abc_setlocal(c, temp);
1180 c = code_append(c, write);
1181 c = abc_getlocal(c, temp);
1188 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1189 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1196 /* ------------ code blocks / statements ---------------- */
1200 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1201 MAYBECODE: {$$=code_new();}
1203 CODE: CODE CODEPIECE {
1204 $$=code_append($1,$2);
1210 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1211 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1212 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1213 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1214 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1215 CODEPIECE: ';' {$$=code_new();}
1216 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1217 CODEPIECE: VOIDEXPRESSION {$$=$1}
1218 CODEPIECE: FOR {$$=$1}
1219 CODEPIECE: WHILE {$$=$1}
1220 CODEPIECE: DO_WHILE {$$=$1}
1221 CODEPIECE: BREAK {$$=$1}
1222 CODEPIECE: CONTINUE {$$=$1}
1223 CODEPIECE: RETURN {$$=$1}
1224 CODEPIECE: IF {$$=$1}
1225 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1226 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1228 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1229 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1230 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1232 /* ------------ variables --------------------------- */
1234 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1235 | {$$.c=abc_pushundefined(0);
1239 VAR : "const" | "var"
1240 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1242 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1243 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1245 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1247 if(variable_exists($2))
1248 syntaxerror("Variable %s already defined", $2);
1250 if(!is_subtype_of($4.t, $3)) {
1251 syntaxerror("Can't convert %s to %s", $4.t->name,
1255 int index = new_variable($2, $3);
1258 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1260 $$ = converttype($$, $4.t, $3);
1261 $$ = abc_setlocal($$, index);
1263 $$ = defaultvalue(0, $3);
1264 $$ = abc_setlocal($$, index);
1267 /* if this is a typed variable:
1268 push default value for type on stack */
1270 state->method->initcode = defaultvalue(state->method->initcode, $3);
1271 state->method->initcode = abc_setlocal(state->method->initcode, index);
1274 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1276 $$ = abc_coerce_a($$);
1277 $$ = abc_setlocal($$, index);
1283 /* that's the default for a local register, anyway
1285 state->method->initcode = abc_pushundefined(state->method->initcode);
1286 state->method->initcode = abc_setlocal(state->method->initcode, index);
1288 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1291 /* ------------ control flow ------------------------- */
1293 MAYBEELSE: %prec below_else {$$ = code_new();}
1294 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1295 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1297 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1299 $$ = code_append($$, $4.c);
1300 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1302 $$ = code_append($$, $6);
1304 myjmp = $$ = abc_jump($$, 0);
1306 myif->branch = $$ = abc_nop($$);
1308 $$ = code_append($$, $7);
1309 myjmp->branch = $$ = abc_nop($$);
1312 $$ = killvars($$);old_state();
1315 MAYBELABEL : T_IDENTIFIER ':' {$$=$1;}
1316 MAYBELABEL : {$$="";}
1318 FOR_INIT : {$$=code_new();}
1319 FOR_INIT : VARIABLE_DECLARATION
1320 FOR_INIT : VOIDEXPRESSION
1322 FOR : MAYBELABEL "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1324 $$ = code_append($$, $5);
1325 code_t*loopstart = $$ = abc_label($$);
1326 $$ = code_append($$, $7.c);
1327 code_t*myif = $$ = abc_iffalse($$, 0);
1328 $$ = code_append($$, $11);
1329 code_t*cont = $$ = abc_nop($$);
1330 $$ = code_append($$, $9);
1331 $$ = abc_jump($$, loopstart);
1332 code_t*out = $$ = abc_nop($$);
1333 breakjumpsto($$, $1, out);
1334 continuejumpsto($$, $1, cont);
1337 $$ = killvars($$);old_state();
1340 WHILE : MAYBELABEL "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1343 code_t*myjmp = $$ = abc_jump($$, 0);
1344 code_t*loopstart = $$ = abc_label($$);
1345 $$ = code_append($$, $7);
1346 code_t*cont = $$ = abc_nop($$);
1347 myjmp->branch = cont;
1348 $$ = code_append($$, $5.c);
1349 $$ = abc_iftrue($$, loopstart);
1350 code_t*out = $$ = abc_nop($$);
1351 breakjumpsto($$, $1, out);
1352 continuejumpsto($$, $1, cont);
1358 DO_WHILE : MAYBELABEL "do" {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1360 code_t*loopstart = $$ = abc_label($$);
1361 $$ = code_append($$, $4);
1362 code_t*cont = $$ = abc_nop($$);
1363 $$ = code_append($$, $7.c);
1364 $$ = abc_iftrue($$, loopstart);
1365 code_t*out = $$ = abc_nop($$);
1366 breakjumpsto($$, $1, out);
1367 continuejumpsto($$, $1, cont);
1372 BREAK : "break" %prec prec_none {
1373 $$ = abc___break__(0, "");
1375 BREAK : "break" T_IDENTIFIER {
1376 $$ = abc___break__(0, $2);
1378 CONTINUE : "continue" %prec prec_none {
1379 $$ = abc___continue__(0, "");
1381 CONTINUE : "continue" T_IDENTIFIER {
1382 $$ = abc___continue__(0, $2);
1385 /* ------------ packages and imports ---------------- */
1387 X_IDENTIFIER: T_IDENTIFIER
1388 | "package" {$$="package";}
1390 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1391 PACKAGE: X_IDENTIFIER {$$=$1;}
1393 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1394 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1396 IMPORT : "import" QNAME {
1399 syntaxerror("Couldn't import class\n");
1400 state_has_imports();
1401 dict_put(state->imports, c->name, c);
1404 IMPORT : "import" PACKAGE '.' '*' {
1407 state_has_imports();
1408 list_append(state->wildcard_imports, i);
1412 /* ------------ classes and interfaces (header) -------------- */
1414 MAYBE_MODIFIERS : {$$=0;}
1415 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1416 MODIFIER_LIST : MODIFIER {$$=$1;}
1417 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1419 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1420 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1421 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1422 | KW_STATIC {$$=FLAG_STATIC;}
1423 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1424 | KW_FINAL {$$=FLAG_FINAL;}
1425 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1426 | KW_NATIVE {$$=FLAG_NATIVE;}
1427 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1429 EXTENDS : {$$=registry_getobjectclass();}
1430 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1432 EXTENDS_LIST : {$$=list_new();}
1433 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1435 IMPLEMENTS_LIST : {$$=list_new();}
1436 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1438 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1439 EXTENDS IMPLEMENTS_LIST
1440 '{' {startclass($1,$3,$4,$5, 0);}
1441 MAYBE_DECLARATION_LIST
1444 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1446 '{' {startclass($1,$3,0,$4,1);}
1447 MAYBE_IDECLARATION_LIST
1450 /* ------------ classes and interfaces (body) -------------- */
1452 MAYBE_DECLARATION_LIST :
1453 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1454 DECLARATION_LIST : DECLARATION
1455 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1457 DECLARATION : SLOT_DECLARATION
1458 DECLARATION : FUNCTION_DECLARATION
1460 MAYBE_IDECLARATION_LIST :
1461 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1462 IDECLARATION_LIST : IDECLARATION
1463 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1465 IDECLARATION : "var" T_IDENTIFIER {
1466 syntaxerror("variable declarations not allowed in interfaces");
1468 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1470 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1471 syntaxerror("invalid method modifiers: interface methods always need to be public");
1473 startfunction(0,$1,$3,$4,&$6,$8);
1474 endfunction(0,$1,$3,$4,&$6,$8, 0);
1477 /* ------------ classes and interfaces (body, slots ) ------- */
1479 VARCONST: "var" | "const"
1481 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1483 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1485 info->flags = flags;
1488 namespace_t mname_ns = {flags2access(flags), ""};
1489 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1491 if(!(flags&FLAG_STATIC)) {
1494 t=abc_class_slot(state->cls->abc, &mname, &m);
1496 t=abc_class_slot(state->cls->abc, &mname, 0);
1498 info->slot = t->slot_id;
1502 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1504 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1506 info->slot = t->slot_id;
1508 if($5.c && !is_pushundefined($5.c)) {
1510 c = abc_getlocal_0(c);
1511 c = code_append(c, $5.c);
1512 c = converttype(c, $5.t, $4);
1513 c = abc_setslot(c, t->slot_id);
1514 if(!(flags&FLAG_STATIC))
1515 state->cls->init = code_append(state->cls->init, c);
1517 state->cls->static_init = code_append(state->cls->static_init, c);
1520 t->kind= TRAIT_CONST;
1524 /* ------------ constants -------------------------------------- */
1526 MAYBESTATICCONSTANT: {$$=0;}
1527 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1529 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1530 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1531 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1532 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1533 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1534 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1535 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1536 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1537 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1539 /* ------------ classes and interfaces (body, functions) ------- */
1541 // non-vararg version
1543 memset(&$$,0,sizeof($$));
1545 MAYBE_PARAM_LIST: PARAM_LIST {
1550 MAYBE_PARAM_LIST: "..." PARAM {
1551 memset(&$$,0,sizeof($$));
1553 list_append($$.list, $2);
1555 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1558 list_append($$.list, $4);
1562 PARAM_LIST: PARAM_LIST ',' PARAM {
1564 list_append($$.list, $3);
1567 memset(&$$,0,sizeof($$));
1568 list_append($$.list, $1);
1571 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1572 $$ = malloc(sizeof(param_t));
1577 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1578 $$ = malloc(sizeof(param_t));
1580 $$->type = TYPE_ANY;
1583 GETSET : "get" {$$=$1;}
1587 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1588 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1591 if(state->method->late_binding) {
1592 c = abc_getlocal_0(c);
1593 c = abc_pushscope(c);
1595 if(state->method->is_constructor && !state->method->has_super) {
1596 // call default constructor
1597 c = abc_getlocal_0(c);
1598 c = abc_constructsuper(c, 0);
1600 c = wrap_function(c, state->method->initcode, $11);
1601 endfunction(0,$1,$3,$4,&$6,$8,c);
1604 /* ------------- package + class ids --------------- */
1606 CLASS: T_IDENTIFIER {
1608 /* try current package */
1609 $$ = find_class($1);
1610 if(!$$) syntaxerror("Could not find class %s\n", $1);
1613 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1614 $$ = registry_findclass($1, $3);
1615 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1618 QNAME: PACKAGEANDCLASS
1621 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1622 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1624 TYPE : QNAME {$$=$1;}
1625 | '*' {$$=registry_getanytype();}
1627 | "String" {$$=registry_getstringclass();}
1628 | "int" {$$=registry_getintclass();}
1629 | "uint" {$$=registry_getuintclass();}
1630 | "Boolean" {$$=registry_getbooleanclass();}
1631 | "Number" {$$=registry_getnumberclass();}
1634 MAYBETYPE: ':' TYPE {$$=$2;}
1637 /* ----------function calls, delete, constructor calls ------ */
1639 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1640 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1642 MAYBE_EXPRESSION_LIST : {$$=0;}
1643 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1644 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1645 typedcode_t*t = malloc(sizeof(typedcode_t));
1647 list_append($$, t);}
1648 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1649 typedcode_t*t = malloc(sizeof(typedcode_t));
1651 list_append($$, t);}
1653 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1658 $$.c = abc_getglobalscope($$.c);
1659 $$.c = abc_getslot($$.c, $2->slot);
1661 $$.c = abc_findpropstrict2($$.c, &m);
1664 typedcode_list_t*l = $3;
1667 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1672 $$.c = abc_construct($$.c, len);
1674 $$.c = abc_constructprop2($$.c, &m, len);
1678 /* TODO: use abc_call (for calling local variables),
1679 abc_callstatic (for calling own methods)
1682 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1683 typedcode_list_t*l = $3;
1685 code_t*paramcode = 0;
1687 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1693 if($$.c->opcode == OPCODE_COERCE_A) {
1694 $$.c = code_cutlast($$.c);
1698 multiname_t*name = 0;
1699 if($$.c->opcode == OPCODE_GETPROPERTY) {
1700 name = multiname_clone($$.c->data[0]);
1701 $$.c = code_cutlast($$.c);
1702 $$.c = code_append($$.c, paramcode);
1703 $$.c = abc_callproperty2($$.c, name, len);
1704 } else if($$.c->opcode == OPCODE_GETSLOT) {
1705 int slot = (int)(ptroff_t)$$.c->data[0];
1706 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1707 if(t->kind!=TRAIT_METHOD) {
1708 //ok: flash allows to assign closures to members.
1711 $$.c = code_cutlast($$.c);
1712 $$.c = code_append($$.c, paramcode);
1713 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1714 $$.c = abc_callproperty2($$.c, name, len);
1715 } else if($$.c->opcode == OPCODE_GETSUPER) {
1716 name = multiname_clone($$.c->data[0]);
1717 $$.c = code_cutlast($$.c);
1718 $$.c = code_append($$.c, paramcode);
1719 $$.c = abc_callsuper2($$.c, name, len);
1721 $$.c = abc_getlocal_0($$.c);
1722 $$.c = code_append($$.c, paramcode);
1723 $$.c = abc_call($$.c, len);
1728 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1729 $$.t = $1.t->function->return_type;
1731 $$.c = abc_coerce_a($$.c);
1735 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1736 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1737 if(!state->method) syntaxerror("super() not allowed outside of a function");
1738 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1741 $$.c = abc_getlocal_0($$.c);
1742 typedcode_list_t*l = 0;
1744 for(l=$3;l;l=l->next) {
1745 $$.c = code_append($$.c, l->typedcode->c);len++;
1748 this is dependent on the control path, check this somewhere else
1749 if(state->method->has_super)
1750 syntaxerror("constructor may call super() only once");
1752 state->method->has_super = 1;
1753 $$.c = abc_constructsuper($$.c, len);
1754 $$.c = abc_pushundefined($$.c);
1758 DELETE: "delete" E {
1760 if($$.c->opcode == OPCODE_COERCE_A) {
1761 $$.c = code_cutlast($$.c);
1763 multiname_t*name = 0;
1764 if($$.c->opcode == OPCODE_GETPROPERTY) {
1765 $$.c->opcode = OPCODE_DELETEPROPERTY;
1766 } else if($$.c->opcode == OPCODE_GETSLOT) {
1767 int slot = (int)(ptroff_t)$$.c->data[0];
1768 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1769 $$.c = code_cutlast($$.c);
1770 $$.c = abc_deleteproperty2($$.c, name);
1772 $$.c = abc_getlocal_0($$.c);
1773 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1774 $$.c = abc_deleteproperty2($$.c, &m);
1776 $$.t = TYPE_BOOLEAN;
1779 RETURN: "return" %prec prec_none {
1780 $$ = abc_returnvoid(0);
1782 RETURN: "return" EXPRESSION {
1784 $$ = abc_returnvalue($$);
1787 // ----------------------- expression types -------------------------------------
1789 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1790 EXPRESSION : E %prec below_minus {$$ = $1;}
1791 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1793 $$.c = cut_last_push($$.c);
1794 $$.c = code_append($$.c,$3.c);
1797 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1798 $$=cut_last_push($1.c);
1801 // ----------------------- expression evaluation -------------------------------------
1804 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1806 E : DELETE {$$ = $1;}
1807 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1811 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1812 //MULTINAME(m, registry_getintclass());
1813 //$$.c = abc_coerce2($$.c, &m); // FIXME
1816 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1819 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1822 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1825 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1828 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1831 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1834 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1835 $$.t = TYPE_BOOLEAN;
1837 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1838 $$.t = TYPE_BOOLEAN;
1840 CONSTANT : "null" {$$.c = abc_pushnull(0);
1845 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1846 $$.t = TYPE_BOOLEAN;
1848 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1849 $$.t = TYPE_BOOLEAN;
1851 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1852 $$.t = TYPE_BOOLEAN;
1854 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1855 $$.t = TYPE_BOOLEAN;
1857 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1858 $$.t = TYPE_BOOLEAN;
1860 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1861 $$.t = TYPE_BOOLEAN;
1863 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1864 $$.t = TYPE_BOOLEAN;
1866 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1867 $$.t = TYPE_BOOLEAN;
1870 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1872 $$.c = converttype($$.c, $1.t, $$.t);
1873 $$.c = abc_dup($$.c);
1874 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1875 $$.c = cut_last_push($$.c);
1876 $$.c = code_append($$.c,$3.c);
1877 $$.c = converttype($$.c, $3.t, $$.t);
1878 code_t*label = $$.c = abc_label($$.c);
1879 jmp->branch = label;
1882 $$.t = join_types($1.t, $3.t, 'A');
1883 /*printf("%08x:\n",$1.t);
1884 code_dump($1.c, 0, 0, "", stdout);
1885 printf("%08x:\n",$3.t);
1886 code_dump($3.c, 0, 0, "", stdout);
1887 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1889 $$.c = converttype($$.c, $1.t, $$.t);
1890 $$.c = abc_dup($$.c);
1891 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1892 $$.c = cut_last_push($$.c);
1893 $$.c = code_append($$.c,$3.c);
1894 $$.c = converttype($$.c, $3.t, $$.t);
1895 code_t*label = $$.c = abc_label($$.c);
1896 jmp->branch = label;
1899 E : '!' E {$$.c=$2.c;
1900 $$.c = abc_not($$.c);
1901 $$.t = TYPE_BOOLEAN;
1904 E : '~' E {$$.c=$2.c;
1905 $$.c = abc_bitnot($$.c);
1909 E : E '&' E {$$.c = code_append($1.c,$3.c);
1910 $$.c = abc_bitand($$.c);
1914 E : E '^' E {$$.c = code_append($1.c,$3.c);
1915 $$.c = abc_bitxor($$.c);
1919 E : E '|' E {$$.c = code_append($1.c,$3.c);
1920 $$.c = abc_bitor($$.c);
1924 E : E '-' E {$$.c = code_append($1.c,$3.c);
1925 if(BOTH_INT($1,$3)) {
1926 $$.c = abc_subtract_i($$.c);
1929 $$.c = abc_subtract($$.c);
1933 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1934 $$.c = abc_rshift($$.c);
1937 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1938 $$.c = abc_urshift($$.c);
1941 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1942 $$.c = abc_lshift($$.c);
1946 E : E '/' E {$$.c = code_append($1.c,$3.c);
1947 $$.c = abc_divide($$.c);
1950 E : E '+' E {$$.c = code_append($1.c,$3.c);
1951 $$.c = abc_add($$.c);
1954 E : E '%' E {$$.c = code_append($1.c,$3.c);
1955 $$.c = abc_modulo($$.c);
1958 E : E '*' E {$$.c = code_append($1.c,$3.c);
1959 if(BOTH_INT($1,$3)) {
1960 $$.c = abc_multiply_i($$.c);
1963 $$.c = abc_multiply($$.c);
1968 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1969 if(use_astype && TYPE_IS_CLASS($3.t)) {
1970 MULTINAME(m,$3.t->cls);
1971 $$.c = abc_astype2($1.c, &m);
1974 $$.c = code_append($1.c, $3.c);
1975 $$.c = abc_astypelate($$.c);
1980 E : E "instanceof" E
1981 {$$.c = code_append($1.c, $3.c);
1982 $$.c = abc_instanceof($$.c);
1983 $$.t = TYPE_BOOLEAN;
1986 E : E "is" E {$$.c = code_append($1.c, $3.c);
1987 $$.c = abc_istypelate($$.c);
1988 $$.t = TYPE_BOOLEAN;
1991 E : "typeof" '(' E ')' {
1993 $$.c = abc_typeof($$.c);
1998 $$.c = cut_last_push($2.c);
1999 $$.c = abc_pushundefined($$.c);
2003 E : "void" { $$.c = abc_pushundefined(0);
2007 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2012 $$.c=abc_negate_i($$.c);
2015 $$.c=abc_negate($$.c);
2022 $$.c = code_append($$.c, $3.c);
2024 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2025 $$.c = abc_getproperty2($$.c, &m);
2026 $$.t = 0; // array elements have unknown type
2029 E : '[' MAYBE_EXPRESSION_LIST ']' {
2031 typedcode_list_t*l = 0;
2033 for(l=$2;l;l=l->next) {
2034 $$.c = code_append($$.c, l->typedcode->c);len++;
2036 $$.c = abc_newarray($$.c, len);
2037 $$.t = registry_getarrayclass();
2042 if(BOTH_INT($1,$3)) {
2043 c=abc_multiply_i(c);
2047 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2048 $$.c = toreadwrite($1.c, c, 0, 0);
2053 code_t*c = abc_modulo($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_lshift($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_rshift($3.c);
2066 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2067 $$.c = toreadwrite($1.c, c, 0, 0);
2071 code_t*c = abc_urshift($3.c);
2072 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2073 $$.c = toreadwrite($1.c, c, 0, 0);
2077 code_t*c = abc_divide($3.c);
2078 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2079 $$.c = toreadwrite($1.c, c, 0, 0);
2084 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2089 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2091 $$.c = toreadwrite($1.c, c, 0, 0);
2094 E : E "-=" E { code_t*c = $3.c;
2095 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2096 c=abc_subtract_i(c);
2100 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2102 $$.c = toreadwrite($1.c, c, 0, 0);
2105 E : E '=' E { code_t*c = 0;
2106 c = code_append(c, $3.c);
2107 c = converttype(c, $3.t, $1.t);
2108 $$.c = toreadwrite($1.c, c, 1, 0);
2112 E : E '?' E ':' E %prec below_assignment {
2114 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2115 $$.c = code_append($$.c, $3.c);
2116 code_t*j2 = $$.c = abc_jump($$.c, 0);
2117 $$.c = j1->branch = abc_label($$.c);
2118 $$.c = code_append($$.c, $5.c);
2119 $$.c = j2->branch = abc_label($$.c);
2120 $$.t = join_types($3.t,$5.t,'?');
2123 // TODO: use inclocal where appropriate
2124 E : E "++" { code_t*c = 0;
2125 classinfo_t*type = $1.t;
2126 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2127 c=abc_increment_i(c);
2133 c=converttype(c, type, $1.t);
2134 $$.c = toreadwrite($1.c, c, 0, 1);
2137 E : E "--" { code_t*c = 0;
2138 classinfo_t*type = $1.t;
2139 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2140 c=abc_decrement_i(c);
2146 c=converttype(c, type, $1.t);
2147 $$.c = toreadwrite($1.c, c, 0, 1);
2151 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2152 classinfo_t*type = $2.t;
2153 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2154 c=abc_increment_i(c);
2160 c=converttype(c, type, $2.t);
2161 $$.c = toreadwrite($2.c, c, 0, 0);
2165 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2166 classinfo_t*type = $2.t;
2167 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2168 c=abc_decrement_i(c);
2174 c=converttype(c, type, $2.t);
2175 $$.c = toreadwrite($2.c, c, 0, 0);
2179 E : "super" '.' T_IDENTIFIER
2180 { if(!state->cls->info)
2181 syntaxerror("super keyword not allowed outside a class");
2182 classinfo_t*t = state->cls->info->superclass;
2183 if(!t) t = TYPE_OBJECT;
2185 memberinfo_t*f = registry_findmember(t, $3);
2186 namespace_t ns = {flags2access(f->flags), ""};
2187 MEMBER_MULTINAME(m, f, $3);
2189 $$.c = abc_getlocal_0($$.c);
2190 $$.c = abc_getsuper2($$.c, &m);
2191 $$.t = memberinfo_gettype(f);
2194 E : E '.' T_IDENTIFIER
2196 classinfo_t*t = $1.t;
2198 if(TYPE_IS_CLASS(t) && t->cls) {
2203 memberinfo_t*f = registry_findmember(t, $3);
2205 if(f && !is_static != !(f->flags&FLAG_STATIC))
2207 if(f && f->slot && !noslot) {
2208 $$.c = abc_getslot($$.c, f->slot);
2210 MEMBER_MULTINAME(m, f, $3);
2211 $$.c = abc_getproperty2($$.c, &m);
2213 /* determine type */
2214 $$.t = memberinfo_gettype(f);
2216 $$.c = abc_coerce_a($$.c);
2218 /* when resolving a property on an unknown type, we do know the
2219 name of the property (and don't seem to need the package), but
2220 we need to make avm2 try out all access modes */
2221 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2222 $$.c = abc_getproperty2($$.c, &m);
2223 $$.c = abc_coerce_a($$.c);
2224 $$.t = registry_getanytype();
2228 VAR_READ : T_IDENTIFIER {
2235 /* look at variables */
2236 if((i = find_variable($1, &$$.t)) >= 0) {
2237 // $1 is a local variable
2238 $$.c = abc_getlocal($$.c, i);
2240 /* look at current class' members */
2241 } else if((f = registry_findmember(state->cls->info, $1))) {
2242 // $1 is a function in this class
2243 int var_is_static = (f->flags&FLAG_STATIC);
2244 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2245 if(var_is_static != i_am_static) {
2246 /* there doesn't seem to be any "static" way to access
2247 static properties of a class */
2248 state->method->late_binding = 1;
2250 namespace_t ns = {flags2access(f->flags), ""};
2251 multiname_t m = {QNAME, &ns, 0, $1};
2252 $$.c = abc_findpropstrict2($$.c, &m);
2253 $$.c = abc_getproperty2($$.c, &m);
2256 $$.c = abc_getlocal_0($$.c);
2257 $$.c = abc_getslot($$.c, f->slot);
2259 namespace_t ns = {flags2access(f->flags), ""};
2260 multiname_t m = {QNAME, &ns, 0, $1};
2261 $$.c = abc_getlocal_0($$.c);
2262 $$.c = abc_getproperty2($$.c, &m);
2265 if(f->kind == MEMBER_METHOD) {
2266 $$.t = TYPE_FUNCTION(f);
2271 /* look at classes in the current package and imported classes */
2272 } else if((a = find_class($1))) {
2273 if(a->flags & FLAG_METHOD) {
2275 $$.c = abc_findpropstrict2($$.c, &m);
2276 $$.c = abc_getproperty2($$.c, &m);
2277 $$.t = TYPE_FUNCTION(a->function);
2280 $$.c = abc_getglobalscope($$.c);
2281 $$.c = abc_getslot($$.c, a->slot);
2284 $$.c = abc_getlex2($$.c, &m);
2286 $$.t = TYPE_CLASS(a);
2289 /* unknown object, let the avm2 resolve it */
2291 if(strcmp($1,"trace"))
2292 warning("Couldn't resolve '%s', doing late binding", $1);
2293 state->method->late_binding = 1;
2295 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2298 $$.c = abc_findpropstrict2($$.c, &m);
2299 $$.c = abc_getproperty2($$.c, &m);
2304 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2305 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2306 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2308 // ----------------- namespaces -------------------------------------------------
2310 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2311 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2312 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2314 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER