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_FOR "for"
85 %token<token> KW_CLASS "class"
86 %token<token> KW_CONST "const"
87 %token<token> KW_SET "set"
88 %token<token> KW_VOID "void"
89 %token<token> KW_STATIC
90 %token<token> KW_INSTANCEOF "instanceof"
91 %token<token> KW_IMPORT "import"
92 %token<token> KW_RETURN "return"
93 %token<token> KW_TYPEOF "typeof"
94 %token<token> KW_INTERFACE "interface"
95 %token<token> KW_NULL "null"
96 %token<token> KW_VAR "var"
97 %token<token> KW_DYNAMIC
98 %token<token> KW_OVERRIDE
99 %token<token> KW_FINAL
100 %token<token> KW_GET "get"
101 %token<token> KW_SUPER "super"
102 %token<token> KW_EXTENDS
103 %token<token> KW_FALSE "false"
104 %token<token> KW_TRUE "true"
105 %token<token> KW_BOOLEAN "Boolean"
106 %token<token> KW_UINT "uint"
107 %token<token> KW_INT "int"
108 %token<token> KW_WHILE "while"
109 %token<token> KW_NUMBER "Number"
110 %token<token> KW_STRING "String"
111 %token<token> KW_DELETE "delete"
112 %token<token> KW_IF "if"
113 %token<token> KW_ELSE "else"
114 %token<token> KW_BREAK "break"
115 %token<token> KW_IS "is"
116 %token<token> KW_AS "as"
118 %token<token> T_EQEQ "=="
119 %token<token> T_EQEQEQ "==="
120 %token<token> T_NE "!="
121 %token<token> T_NEE "!=="
122 %token<token> T_LE "<="
123 %token<token> T_GE ">="
124 %token<token> T_DIVBY "/="
125 %token<token> T_MODBY "%="
126 %token<token> T_MULBY "*="
127 %token<token> T_PLUSBY "+="
128 %token<token> T_MINUSBY "-="
129 %token<token> T_SHRBY ">>="
130 %token<token> T_SHLBY "<<="
131 %token<token> T_USHRBY ">>>="
132 %token<token> T_OROR "||"
133 %token<token> T_ANDAND "&&"
134 %token<token> T_COLONCOLON "::"
135 %token<token> T_MINUSMINUS "--"
136 %token<token> T_PLUSPLUS "++"
137 %token<token> T_DOTDOT ".."
138 %token<token> T_DOTDOTDOT "..."
139 %token<token> T_SHL "<<"
140 %token<token> T_USHR ">>>"
141 %token<token> T_SHR ">>"
143 %type <id> X_IDENTIFIER PACKAGE
144 %type <token> VARCONST
146 %type <code> CODEPIECE
147 %type <code> CODEBLOCK MAYBECODE
148 %type <token> PACKAGE_DECLARATION
149 %type <token> FUNCTION_DECLARATION
150 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
151 %type <token> CLASS_DECLARATION
152 %type <token> NAMESPACE_DECLARATION
153 %type <token> INTERFACE_DECLARATION
154 %type <code> VOIDEXPRESSION
155 %type <value> EXPRESSION NONCOMMAEXPRESSION
156 %type <value> MAYBEEXPRESSION
157 %type <value> E DELETE
158 %type <value> CONSTANT
159 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
160 %type <token> USE_NAMESPACE
161 %type <code> FOR_INIT
163 %type <classinfo> MAYBETYPE
166 %type <params> PARAM_LIST
167 %type <params> MAYBE_PARAM_LIST
168 %type <flags> MAYBE_MODIFIERS
169 %type <flags> MODIFIER_LIST
170 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
171 %type <classinfo_list> IMPLEMENTS_LIST
172 %type <classinfo> EXTENDS
173 %type <classinfo_list> EXTENDS_LIST
174 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
175 %type <classinfo_list> QNAME_LIST
176 %type <classinfo> TYPE
178 //%type <token> VARIABLE
179 %type <value> VAR_READ
181 //%type <token> T_IDENTIFIER
182 %type <token> MODIFIER
183 %type <value> FUNCTIONCALL
184 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
186 // precedence: from low to high
190 %left below_semicolon
193 %nonassoc below_assignment // for ?:, contrary to spec
194 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
201 %nonassoc "==" "!=" "===" "!=="
203 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
204 %left "<<" ">>" ">>>"
208 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
210 %left '[' ']' '{' "new" '.' ".." "::"
211 %nonassoc T_IDENTIFIER
216 // needed for "return" precedence:
217 %nonassoc T_STRING T_REGEXP
218 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
219 %nonassoc "false" "true" "null" "undefined" "super"
224 static int yyerror(char*s)
226 syntaxerror("%s", s);
228 static char* concat3str(const char* t1, const char* t2, const char* t3)
233 char*text = malloc(l1+l2+l3+1);
234 memcpy(text , t1, l1);
235 memcpy(text+l1, t2, l2);
236 memcpy(text+l1+l2, t3, l3);
241 typedef struct _import {
245 DECLARE_LIST(import);
247 typedef struct _classstate {
253 char has_constructor;
256 typedef struct _methodstate {
260 /* code that needs to be executed at the start of
261 a method (like initializing local registers) */
267 typedef struct _state {
271 import_list_t*wildcard_imports;
273 char has_own_imports;
276 methodstate_t*method;
281 typedef struct _global {
288 static global_t*global = 0;
289 static state_t* state = 0;
293 #define MULTINAME(m,x) \
296 registry_fill_multiname(&m, &m##_ns, x);
298 #define MEMBER_MULTINAME(m,f,n) \
302 m##_ns.access = flags2access(f->flags); \
306 m.namespace_set = 0; \
309 m.type = MULTINAME; \
311 m.namespace_set = &nopackage_namespace_set; \
315 /* warning: list length of namespace set is undefined */
316 #define MULTINAME_LATE(m, access, package) \
317 namespace_t m##_ns = {access, package}; \
318 namespace_set_t m##_nsset; \
319 namespace_list_t m##_l;m##_l.next = 0; \
320 m##_nsset.namespaces = &m##_l; \
321 m##_nsset = m##_nsset; \
322 m##_l.namespace = &m##_ns; \
323 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
325 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
326 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
327 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
328 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
329 static namespace_list_t nl4 = {&ns4,0};
330 static namespace_list_t nl3 = {&ns3,&nl4};
331 static namespace_list_t nl2 = {&ns2,&nl3};
332 static namespace_list_t nl1 = {&ns1,&nl2};
333 static namespace_set_t nopackage_namespace_set = {&nl1};
335 static state_list_t*state_stack=0;
337 static void init_globals()
339 global = rfx_calloc(sizeof(global_t));
342 static void new_state()
345 NEW(state_list_t, sl);
347 state_t*oldstate = state;
349 memcpy(s, state, sizeof(state_t)); //shallow copy
350 sl->next = state_stack;
353 s->imports = dict_new();
358 state->has_own_imports = 0;
359 state->vars = dict_new();
361 static void state_has_imports()
363 state->wildcard_imports = list_clone(state->wildcard_imports);
364 state->imports = dict_clone(state->imports);
365 state->has_own_imports = 1;
368 static void old_state()
370 if(!state_stack || !state_stack->next)
371 syntaxerror("invalid nesting");
372 state_t*oldstate = state;
373 state_list_t*old = state_stack;
374 state_stack = state_stack->next;
376 state = state_stack->state;
377 /*if(state->method->initcode) {
378 printf("residual initcode\n");
379 code_dump(state->method->initcode, 0, 0, "", stdout);
381 if(oldstate->has_own_imports) {
382 list_free(oldstate->wildcard_imports);
383 dict_destroy(oldstate->imports);oldstate->imports=0;
386 void initialize_state()
391 global->file = abc_file_new();
392 global->file->flags &= ~ABCFILE_LAZY;
394 global->init = abc_initscript(global->file, 0);
395 code_t*c = global->init->method->body->code;
397 c = abc_getlocal_0(c);
398 c = abc_pushscope(c);
400 /* findpropstrict doesn't just return a scope object- it
401 also makes it "active" somehow. Push local_0 on the
402 scope stack and read it back with findpropstrict, it'll
403 contain properties like "trace". Trying to find the same
404 property on a "vanilla" local_0 yields only a "undefined" */
405 //c = abc_findpropstrict(c, "[package]::trace");
407 /*c = abc_getlocal_0(c);
408 c = abc_findpropstrict(c, "[package]::trace");
410 c = abc_setlocal_1(c);
412 c = abc_pushbyte(c, 0);
413 c = abc_setlocal_2(c);
415 code_t*xx = c = abc_label(c);
416 c = abc_findpropstrict(c, "[package]::trace");
417 c = abc_pushstring(c, "prop:");
418 c = abc_hasnext2(c, 1, 2);
420 c = abc_setlocal_3(c);
421 c = abc_callpropvoid(c, "[package]::trace", 2);
422 c = abc_getlocal_3(c);
424 c = abc_iftrue(c,xx);*/
426 c = abc_findpropstrict(c, "[package]::trace");
427 c = abc_pushstring(c, "[entering global init function]");
428 c = abc_callpropvoid(c, "[package]::trace", 1);
430 global->init->method->body->code = c;
432 void* finalize_state()
434 if(state->level!=1) {
435 syntaxerror("unexpected end of file");
437 abc_method_body_t*m = global->init->method->body;
440 __ findpropstrict(m, "[package]::trace");
441 __ pushstring(m, "[leaving global init function]");
442 __ callpropvoid(m, "[package]::trace", 1);
448 static void startpackage(char*name)
451 syntaxerror("Packages can not be nested.");
454 /*printf("entering package \"%s\"\n", name);*/
455 state->package = name;
457 static void endpackage()
459 /*printf("leaving package \"%s\"\n", state->package);*/
464 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
467 syntaxerror("inner classes now allowed");
470 state->cls = rfx_calloc(sizeof(classstate_t));
473 classinfo_list_t*mlist=0;
474 /*printf("entering class %s\n", name);
475 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
477 printf(" extends: %s.%s\n", extends->package, extends->name);
478 printf(" implements (%d): ", list_length(implements));
479 for(mlist=implements;mlist;mlist=mlist->next) {
480 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
485 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
486 syntaxerror("invalid modifier(s)");
488 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
489 syntaxerror("public and internal not supported at the same time.");
491 /* create the class name, together with the proper attributes */
495 if(!(flags&FLAG_PUBLIC) && !state->package) {
496 access = ACCESS_PRIVATE; package = current_filename;
497 } else if(!(flags&FLAG_PUBLIC) && state->package) {
498 access = ACCESS_PACKAGEINTERNAL; package = state->package;
499 } else if(state->package) {
500 access = ACCESS_PACKAGE; package = state->package;
502 syntaxerror("public classes only allowed inside a package");
505 if(registry_findclass(package, classname)) {
506 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
510 /* build info struct */
511 int num_interfaces = (list_length(implements));
512 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
513 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
515 classinfo_list_t*l = implements;
516 for(l=implements;l;l=l->next) {
517 state->cls->info->interfaces[pos++] = l->classinfo;
520 multiname_t*extends2 = sig2mname(extends);
522 MULTINAME(classname2,state->cls->info);
525 state->cls_init = abc_getlocal_0(state->cls_init);
526 state->cls_init = abc_constructsuper(state->cls_init, 0);
529 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
530 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
531 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
533 state->cls->info->flags |= CLASS_INTERFACE;
534 abc_class_interface(state->cls->abc);
537 abc_class_protectedNS(state->cls->abc, classname);
539 for(mlist=implements;mlist;mlist=mlist->next) {
540 MULTINAME(m, mlist->classinfo);
541 abc_class_add_interface(state->cls->abc, &m);
544 /* now write the construction code for this class */
545 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
547 abc_method_body_t*m = global->init->method->body;
548 __ getglobalscope(m);
549 classinfo_t*s = extends;
554 //TODO: take a look at the current scope stack, maybe
555 // we can re-use something
560 multiname_t*s2 = sig2mname(s);
562 multiname_destroy(s2);
564 __ pushscope(m); count++;
565 m->code = m->code->prev->prev; // invert
567 /* continue appending after last op end */
568 while(m->code && m->code->next) m->code = m->code->next;
570 /* TODO: if this is one of *our* classes, we can also
571 do a getglobalscope/getslot <nr> (which references
572 the init function's slots) */
574 __ getlex2(m, extends2);
576 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
577 stack is not the superclass */
578 __ pushscope(m);count++;
581 /* notice: we get a verify error #1107 if the top element on the scope
582 stack is not the global object */
584 __ pushscope(m);count++;
586 __ newclass(m,state->cls->abc);
590 __ setslot(m, slotindex);
592 /* flash.display.MovieClip handling */
593 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
594 if(state->package && state->package[0]) {
595 globalclass = concat3str(state->package, ".", classname);
597 globalclass = strdup(classname);
600 multiname_destroy(extends2);
603 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
605 c = code_append(c, initcode);
606 c = code_append(c, body);
607 /* append return if necessary */
608 if(!c || c->opcode != OPCODE_RETURNVOID &&
609 c->opcode != OPCODE_RETURNVALUE) {
610 c = abc_returnvoid(c);
615 static void endclass()
617 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
619 c = abc_getlocal_0(c);
620 c = abc_constructsuper(c, 0);
621 state->cls->init = code_append(state->cls->init, c);
624 if(state->cls->init) {
625 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
626 m->body->code = wrap_function(0, state->cls->init, m->body->code);
628 if(state->cls->static_init) {
629 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
630 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
632 // handy for scope testing
636 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
642 typedef struct _variable {
647 static int find_variable(char*name, classinfo_t**m)
649 state_list_t* s = state_stack;
653 v = dict_lookup(s->state->vars, name);
664 static int find_variable_safe(char*name, classinfo_t**m)
666 int i = find_variable(name, m);
668 syntaxerror("undefined variable: %s", name);
671 static char variable_exists(char*name)
673 return dict_lookup(state->vars, name)!=0;
675 static int new_variable(char*name, classinfo_t*type)
678 v->index = global->variable_count;
680 dict_put(state->vars, name, v);
681 return global->variable_count++;
683 #define TEMPVARNAME "__as3_temp__"
684 static int gettempvar()
686 int i = find_variable(TEMPVARNAME, 0);
688 i = new_variable(TEMPVARNAME, 0);
693 code_t* killvars(code_t*c)
696 for(t=0;t<state->vars->hashsize;t++) {
697 dictentry_t*e =state->vars->slots[t];
699 variable_t*v = (variable_t*)e->data;
700 //do this always, otherwise register types don't match
701 //in the verifier when doing nested loops
702 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
703 c = abc_kill(c, v->index);
711 static void check_constant_against_type(classinfo_t*t, constant_t*c)
713 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
714 if(TYPE_IS_NUMBER(t)) {
715 xassert(c->type == CONSTANT_FLOAT
716 || c->type == CONSTANT_INT
717 || c->type == CONSTANT_UINT);
718 } else if(TYPE_IS_UINT(t)) {
719 xassert(c->type == CONSTANT_UINT ||
720 (c->type == CONSTANT_INT && c->i>0));
721 } else if(TYPE_IS_INT(t)) {
722 xassert(c->type == CONSTANT_INT);
723 } else if(TYPE_IS_BOOLEAN(t)) {
724 xassert(c->type == CONSTANT_TRUE
725 || c->type == CONSTANT_FALSE);
729 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
731 memberinfo_t*minfo = 0;
732 if(getset != KW_GET && getset != KW_SET) {
733 if(registry_findmember(state->cls->info, name)) {
734 syntaxerror("class already contains a member/method called '%s'", name);
736 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
737 minfo->return_type = return_type;
738 // getslot on a member slot only returns "undefined", so no need
739 // to actually store these
740 //state->minfo->slot = state->method->abc->method->trait->slot_id;
742 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
746 else if(params->list)
747 type = params->list->param->type;
748 if((minfo=registry_findmember(state->cls->info, name))) {
749 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
750 syntaxerror("class already contains a member or method called '%s'", name);
752 syntaxerror("getter/setter for '%s' already defined", name);
753 /* make a setter or getter into a getset */
758 if(type && minfo->type != type)
759 syntaxerror("different type in getter and setter");
761 minfo = memberinfo_register(state->cls->info, name, gs);
764 /* can't assign a slot as getter and setter might have different slots */
765 //minfo->slot = slot;
767 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
768 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
769 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
770 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
771 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
775 static int flags2access(int flags)
778 if(flags&FLAG_PUBLIC) {
779 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
780 access = ACCESS_PACKAGE;
781 } else if(flags&FLAG_PRIVATE) {
782 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
783 access = ACCESS_PRIVATE;
784 } else if(flags&FLAG_PROTECTED) {
785 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
786 access = ACCESS_PROTECTED;
788 access = ACCESS_PACKAGEINTERNAL;
793 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
794 params_t*params, classinfo_t*return_type)
797 syntaxerror("not able to start another method scope");
800 state->method = rfx_calloc(sizeof(methodstate_t));
801 state->method->initcode = 0;
802 state->method->is_constructor = !strcmp(state->cls->info->name,name);
803 state->method->has_super = 0;
805 state->cls->has_constructor |= state->method->is_constructor;
807 global->variable_count = 0;
809 /* state->vars is initialized by state_new */
810 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
812 for(p=params->list;p;p=p->next) {
813 new_variable(p->param->name, p->param->type);
815 if(state->method->is_constructor)
816 name = "__as3_constructor__";
817 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
820 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
821 params_t*params, classinfo_t*return_type, code_t*body)
823 namespace_t mname_ns = {flags2access(flags), ""};
824 multiname_t mname = {QNAME, &mname_ns, 0, name};
828 multiname_t*type2 = sig2mname(return_type);
830 if(state->method->is_constructor) {
831 f = abc_class_getconstructor(state->cls->abc, type2);
833 if(flags&FLAG_STATIC)
834 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
836 f = abc_class_method(state->cls->abc, type2, &mname);
837 slot = f->trait->slot_id;
839 //flash doesn't seem to allow us to access function slots
840 //state->method->info->slot = slot;
842 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
843 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
844 if(params->varargs) f->flags |= METHOD_NEED_REST;
848 for(p=params->list;p;p=p->next) {
849 if(params->varargs && !p->next) {
850 break; //varargs: omit last parameter in function signature
852 multiname_t*m = sig2mname(p->param->type);
853 list_append(f->parameters, m);
854 if(p->param->value) {
855 check_constant_against_type(p->param->type, p->param->value);
856 opt=1;list_append(f->optional_parameters, p->param->value);
858 syntaxerror("non-optional parameter not allowed after optional parameters");
861 f->body->code = body;
868 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
873 void breakjumpsto(code_t*c, code_t*jump)
878 if(c->opcode == OPCODE___BREAK__) {
879 c->opcode = OPCODE_JUMP;
886 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
889 return registry_getanytype();
890 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
891 return registry_getanytype();
894 return registry_getanytype();
896 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
901 return abc_coerce_a(c);
905 // cast an "any" type to a specific type. subject to
906 // runtime exceptions
907 return abc_coerce2(c, &m);
910 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
911 return abc_coerce2(c, &m);
913 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
914 return abc_coerce2(c, &m);
916 /* these are subject to overflow */
917 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
918 return abc_coerce2(c, &m);
920 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
921 return abc_coerce2(c, &m);
924 classinfo_t*supertype = from;
926 if(supertype == to) {
927 // target type is one of from's superclasses
928 return abc_coerce2(c, &m);
931 while(supertype->interfaces[t]) {
932 if(supertype->interfaces[t]==to) {
933 // to type is one of from's interfaces
934 return abc_coerce2(c, &m);
938 supertype = supertype->superclass;
940 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
942 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
944 syntaxerror("can't convert type %s to %s", from->name, to->name);
947 code_t*defaultvalue(code_t*c, classinfo_t*type)
949 if(TYPE_IS_INT(type)) {
950 c = abc_pushbyte(c, 0);
951 } else if(TYPE_IS_UINT(type)) {
952 c = abc_pushuint(c, 0);
953 } else if(TYPE_IS_FLOAT(type)) {
955 } else if(TYPE_IS_BOOLEAN(type)) {
956 c = abc_pushfalse(c);
963 char is_pushundefined(code_t*c)
965 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
968 void parserassert(int b)
970 if(!b) syntaxerror("internal error: assertion failed");
973 static classinfo_t* find_class(char*name)
977 c = registry_findclass(state->package, name);
979 /* try explicit imports */
980 dictentry_t* e = dict_get_slot(state->imports, name);
984 if(!strcmp(e->key, name)) {
985 c = (classinfo_t*)e->data;
990 /* try package.* imports */
991 import_list_t*l = state->wildcard_imports;
995 //printf("does package %s contain a class %s?\n", l->import->package, name);
996 c = registry_findclass(l->import->package, name);
1000 /* try global package */
1002 c = registry_findclass("", name);
1007 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1011 [prefix code] [read instruction]
1015 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1018 if(in && in->opcode == OPCODE_COERCE_A) {
1019 in = code_cutlast(in);
1022 syntaxerror("internal error");
1024 /* chop off read instruction */
1028 prefix = r->prev;r->prev = 0;
1034 char use_temp_var = readbefore;
1036 /* generate the write instruction, and maybe append a dup to the prefix code */
1037 code_t* write = abc_nop(0);
1038 if(r->opcode == OPCODE_GETPROPERTY) {
1039 write->opcode = OPCODE_SETPROPERTY;
1040 multiname_t*m = (multiname_t*)r->data[0];
1041 write->data[0] = multiname_clone(m);
1042 if(m->type == QNAME || m->type == MULTINAME) {
1044 prefix = abc_dup(prefix); // we need the object, too
1047 } else if(m->type == MULTINAMEL) {
1049 /* dupping two values on the stack requires 5 operations and one register-
1050 couldn't adobe just have given us a dup2? */
1051 int temp = gettempvar();
1052 prefix = abc_setlocal(prefix, temp);
1053 prefix = abc_dup(prefix);
1054 prefix = abc_getlocal(prefix, temp);
1055 prefix = abc_swap(prefix);
1056 prefix = abc_getlocal(prefix, temp);
1060 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1062 } else if(r->opcode == OPCODE_GETSLOT) {
1063 write->opcode = OPCODE_SETSLOT;
1064 write->data[0] = r->data[0];
1066 prefix = abc_dup(prefix); // we need the object, too
1069 } else if(r->opcode == OPCODE_GETLOCAL) {
1070 write->opcode = OPCODE_SETLOCAL;
1071 write->data[0] = r->data[0];
1072 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1073 write->opcode = OPCODE_SETLOCAL_0;
1074 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1075 write->opcode = OPCODE_SETLOCAL_1;
1076 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1077 write->opcode = OPCODE_SETLOCAL_2;
1078 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1079 write->opcode = OPCODE_SETLOCAL_3;
1081 code_dump(r, 0, 0, "", stdout);
1082 syntaxerror("illegal lvalue: can't assign a value to this expression");
1089 /* with getproperty/getslot, we have to be extra careful not
1090 to execute the read code twice, as it might have side-effects
1091 (e.g. if the property is in fact a setter/getter combination)
1093 So read the value, modify it, and write it again,
1094 using prefix only once and making sure (by using a temporary
1095 register) that the return value is what we just wrote */
1096 temp = gettempvar();
1097 c = code_append(c, prefix);
1098 c = code_append(c, r);
1101 c = abc_setlocal(c, temp);
1103 c = code_append(c, middlepart);
1106 c = abc_setlocal(c, temp);
1108 c = code_append(c, write);
1109 c = abc_getlocal(c, temp);
1110 c = abc_kill(c, temp);
1112 /* if we're allowed to execute the read code twice *and*
1113 the middlepart doesn't modify the code, things are easier.
1115 code_t* r2 = code_dup(r);
1116 //c = code_append(c, prefix);
1117 parserassert(!prefix);
1118 c = code_append(c, r);
1119 c = code_append(c, middlepart);
1120 c = code_append(c, write);
1121 c = code_append(c, r2);
1124 /* even smaller version: overwrite the value without reading
1128 c = code_append(c, prefix);
1131 c = code_append(c, middlepart);
1132 c = code_append(c, write);
1133 c = code_append(c, r);
1135 temp = gettempvar();
1137 c = code_append(c, prefix);
1140 c = code_append(c, middlepart);
1142 c = abc_setlocal(c, temp);
1143 c = code_append(c, write);
1144 c = abc_getlocal(c, temp);
1151 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1152 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1159 /* ------------ code blocks / statements ---------------- */
1163 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1164 MAYBECODE: {$$=code_new();}
1166 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1167 CODE: CODEPIECE {$$=$1;}
1169 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1170 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1171 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1172 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1173 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1174 CODEPIECE: ';' {$$=code_new();}
1175 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1176 CODEPIECE: VOIDEXPRESSION {$$=$1}
1177 CODEPIECE: FOR {$$=$1}
1178 CODEPIECE: WHILE {$$=$1}
1179 CODEPIECE: BREAK {$$=$1}
1180 CODEPIECE: RETURN {$$=$1}
1181 CODEPIECE: IF {$$=$1}
1182 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1183 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1185 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1186 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1187 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1189 /* ------------ variables --------------------------- */
1191 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1192 | {$$.c=abc_pushundefined(0);
1196 VAR : "const" | "var"
1197 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1199 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1200 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1202 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1204 if(variable_exists($2))
1205 syntaxerror("Variable %s already defined", $2);
1207 if(!is_subtype_of($4.t, $3)) {
1208 syntaxerror("Can't convert %s to %s", $4.t->name,
1212 int index = new_variable($2, $3);
1215 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1217 $$ = converttype($$, $4.t, $3);
1218 $$ = abc_setlocal($$, index);
1220 $$ = defaultvalue(0, $3);
1221 $$ = abc_setlocal($$, index);
1224 /* if this is a typed variable:
1225 push default value for type on stack */
1227 state->method->initcode = defaultvalue(state->method->initcode, $3);
1228 state->method->initcode = abc_setlocal(state->method->initcode, index);
1231 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1233 $$ = abc_coerce_a($$);
1234 $$ = abc_setlocal($$, index);
1240 /* that's the default for a local register, anyway
1242 state->method->initcode = abc_pushundefined(state->method->initcode);
1243 state->method->initcode = abc_setlocal(state->method->initcode, index);
1245 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1248 /* ------------ control flow ------------------------- */
1250 MAYBEELSE: %prec below_else {$$ = code_new();}
1251 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1252 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1254 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1256 $$ = code_append($$, $4.c);
1257 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1259 $$ = code_append($$, $6);
1261 myjmp = $$ = abc_jump($$, 0);
1263 myif->branch = $$ = abc_nop($$);
1265 $$ = code_append($$, $7);
1266 myjmp->branch = $$ = abc_nop($$);
1269 $$ = killvars($$);old_state();
1272 FOR_INIT : {$$=code_new();}
1273 FOR_INIT : VARIABLE_DECLARATION
1274 FOR_INIT : VOIDEXPRESSION
1276 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1278 $$ = code_append($$, $4);
1279 code_t*loopstart = $$ = abc_label($$);
1280 $$ = code_append($$, $6.c);
1281 code_t*myif = $$ = abc_iffalse($$, 0);
1282 $$ = code_append($$, $10);
1283 $$ = code_append($$, $8);
1284 $$ = abc_jump($$, loopstart);
1285 code_t*out = $$ = abc_nop($$);
1286 breakjumpsto($$, out);
1289 $$ = killvars($$);old_state();
1292 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1295 code_t*myjmp = $$ = abc_jump($$, 0);
1296 code_t*loopstart = $$ = abc_label($$);
1297 $$ = code_append($$, $6);
1298 myjmp->branch = $$ = abc_nop($$);
1299 $$ = code_append($$, $4.c);
1300 $$ = abc_iftrue($$, loopstart);
1301 code_t*out = $$ = abc_nop($$);
1302 breakjumpsto($$, out);
1304 $$ = killvars($$);old_state();
1308 $$ = abc___break__(0);
1311 /* ------------ packages and imports ---------------- */
1313 X_IDENTIFIER: T_IDENTIFIER
1314 | "package" {$$="package";}
1316 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1317 PACKAGE: X_IDENTIFIER {$$=$1;}
1319 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1320 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1322 IMPORT : "import" QNAME {
1325 syntaxerror("Couldn't import class\n");
1326 state_has_imports();
1327 dict_put(state->imports, c->name, c);
1330 IMPORT : "import" PACKAGE '.' '*' {
1333 state_has_imports();
1334 list_append(state->wildcard_imports, i);
1338 /* ------------ classes and interfaces (header) -------------- */
1340 MAYBE_MODIFIERS : {$$=0;}
1341 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1342 MODIFIER_LIST : MODIFIER {$$=$1;}
1343 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1345 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1346 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1347 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1348 | KW_STATIC {$$=FLAG_STATIC;}
1349 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1350 | KW_FINAL {$$=FLAG_FINAL;}
1351 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1352 | KW_NATIVE {$$=FLAG_NATIVE;}
1353 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1355 EXTENDS : {$$=registry_getobjectclass();}
1356 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1358 EXTENDS_LIST : {$$=list_new();}
1359 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1361 IMPLEMENTS_LIST : {$$=list_new();}
1362 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1364 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1365 EXTENDS IMPLEMENTS_LIST
1366 '{' {startclass($1,$3,$4,$5, 0);}
1367 MAYBE_DECLARATION_LIST
1370 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1372 '{' {startclass($1,$3,0,$4,1);}
1373 MAYBE_IDECLARATION_LIST
1376 /* ------------ classes and interfaces (body) -------------- */
1378 MAYBE_DECLARATION_LIST :
1379 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1380 DECLARATION_LIST : DECLARATION
1381 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1383 DECLARATION : SLOT_DECLARATION
1384 DECLARATION : FUNCTION_DECLARATION
1386 MAYBE_IDECLARATION_LIST :
1387 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1388 IDECLARATION_LIST : IDECLARATION
1389 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1391 IDECLARATION : "var" T_IDENTIFIER {
1392 syntaxerror("variable declarations not allowed in interfaces");
1394 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1396 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1397 syntaxerror("invalid method modifiers: interface methods always need to be public");
1399 startfunction(0,$1,$3,$4,&$6,$8);
1400 endfunction(0,$1,$3,$4,&$6,$8, 0);
1403 /* ------------ classes and interfaces (body, slots ) ------- */
1405 VARCONST: "var" | "const"
1407 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1409 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1411 info->flags = flags;
1414 namespace_t mname_ns = {flags2access(flags), ""};
1415 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1417 if(!(flags&FLAG_STATIC)) {
1420 t=abc_class_slot(state->cls->abc, &mname, &m);
1422 t=abc_class_slot(state->cls->abc, &mname, 0);
1424 info->slot = t->slot_id;
1428 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1430 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1432 info->slot = t->slot_id;
1434 if($5.c && !is_pushundefined($5.c)) {
1436 c = abc_getlocal_0(c);
1437 c = code_append(c, $5.c);
1438 c = converttype(c, $5.t, $4);
1439 c = abc_setslot(c, t->slot_id);
1440 if(!(flags&FLAG_STATIC))
1441 state->cls->init = code_append(state->cls->init, c);
1443 state->cls->static_init = code_append(state->cls->static_init, c);
1446 t->kind= TRAIT_CONST;
1450 /* ------------ constants -------------------------------------- */
1452 MAYBESTATICCONSTANT: {$$=0;}
1453 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1455 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1456 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1457 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1458 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1459 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1460 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1461 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1462 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1463 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1465 /* ------------ classes and interfaces (body, functions) ------- */
1467 // non-vararg version
1469 memset(&$$,0,sizeof($$));
1471 MAYBE_PARAM_LIST: PARAM_LIST {
1476 MAYBE_PARAM_LIST: "..." PARAM {
1477 memset(&$$,0,sizeof($$));
1479 list_append($$.list, $2);
1481 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1484 list_append($$.list, $4);
1488 PARAM_LIST: PARAM_LIST ',' PARAM {
1490 list_append($$.list, $3);
1493 memset(&$$,0,sizeof($$));
1494 list_append($$.list, $1);
1497 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1498 $$ = malloc(sizeof(param_t));
1503 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1504 $$ = malloc(sizeof(param_t));
1506 $$->type = TYPE_ANY;
1509 GETSET : "get" {$$=$1;}
1513 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1514 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1517 if(state->method->late_binding) {
1518 c = abc_getlocal_0(c);
1519 c = abc_pushscope(c);
1521 if(state->method->is_constructor && !state->method->has_super) {
1522 // call default constructor
1523 c = abc_getlocal_0(c);
1524 c = abc_constructsuper(c, 0);
1526 c = wrap_function(c, state->method->initcode, $11);
1527 endfunction(0,$1,$3,$4,&$6,$8,c);
1530 /* ------------- package + class ids --------------- */
1532 CLASS: T_IDENTIFIER {
1534 /* try current package */
1535 $$ = find_class($1);
1536 if(!$$) syntaxerror("Could not find class %s\n", $1);
1539 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1540 $$ = registry_findclass($1, $3);
1541 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1544 QNAME: PACKAGEANDCLASS
1547 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1548 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1550 TYPE : QNAME {$$=$1;}
1551 | '*' {$$=registry_getanytype();}
1553 | "String" {$$=registry_getstringclass();}
1554 | "int" {$$=registry_getintclass();}
1555 | "uint" {$$=registry_getuintclass();}
1556 | "Boolean" {$$=registry_getbooleanclass();}
1557 | "Number" {$$=registry_getnumberclass();}
1560 MAYBETYPE: ':' TYPE {$$=$2;}
1563 /* ----------function calls, delete, constructor calls ------ */
1565 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1566 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1568 MAYBE_EXPRESSION_LIST : {$$=0;}
1569 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1570 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1571 typedcode_t*t = malloc(sizeof(typedcode_t));
1573 list_append($$, t);}
1574 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1575 typedcode_t*t = malloc(sizeof(typedcode_t));
1577 list_append($$, t);}
1579 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1584 $$.c = abc_getglobalscope($$.c);
1585 $$.c = abc_getslot($$.c, $2->slot);
1587 $$.c = abc_findpropstrict2($$.c, &m);
1590 typedcode_list_t*l = $3;
1593 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1598 $$.c = abc_construct($$.c, len);
1600 $$.c = abc_constructprop2($$.c, &m, len);
1604 /* TODO: use abc_call (for calling local variables),
1605 abc_callstatic (for calling own methods)
1608 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1609 typedcode_list_t*l = $3;
1611 code_t*paramcode = 0;
1613 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1619 if($$.c->opcode == OPCODE_COERCE_A) {
1620 $$.c = code_cutlast($$.c);
1624 multiname_t*name = 0;
1625 if($$.c->opcode == OPCODE_GETPROPERTY) {
1626 name = multiname_clone($$.c->data[0]);
1627 $$.c = code_cutlast($$.c);
1628 $$.c = code_append($$.c, paramcode);
1629 $$.c = abc_callproperty2($$.c, name, len);
1630 } else if($$.c->opcode == OPCODE_GETSLOT) {
1631 int slot = (int)(ptroff_t)$$.c->data[0];
1632 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1633 if(t->kind!=TRAIT_METHOD) {
1634 //ok: flash allows to assign closures to members.
1637 $$.c = code_cutlast($$.c);
1638 $$.c = code_append($$.c, paramcode);
1639 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1640 $$.c = abc_callproperty2($$.c, name, len);
1641 } else if($$.c->opcode == OPCODE_GETSUPER) {
1642 name = multiname_clone($$.c->data[0]);
1643 $$.c = code_cutlast($$.c);
1644 $$.c = code_append($$.c, paramcode);
1645 $$.c = abc_callsuper2($$.c, name, len);
1647 $$.c = abc_getlocal_0($$.c);
1648 $$.c = code_append($$.c, paramcode);
1649 $$.c = abc_call($$.c, len);
1654 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1655 $$.t = $1.t->function->return_type;
1657 $$.c = abc_coerce_a($$.c);
1661 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1662 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1663 if(!state->method) syntaxerror("super() not allowed outside of a function");
1664 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1667 $$.c = abc_getlocal_0($$.c);
1668 typedcode_list_t*l = 0;
1670 for(l=$3;l;l=l->next) {
1671 $$.c = code_append($$.c, l->typedcode->c);len++;
1674 this is dependent on the control path, check this somewhere else
1675 if(state->method->has_super)
1676 syntaxerror("constructor may call super() only once");
1678 state->method->has_super = 1;
1679 $$.c = abc_constructsuper($$.c, len);
1680 $$.c = abc_pushundefined($$.c);
1684 DELETE: "delete" E {
1686 if($$.c->opcode == OPCODE_COERCE_A) {
1687 $$.c = code_cutlast($$.c);
1689 multiname_t*name = 0;
1690 if($$.c->opcode == OPCODE_GETPROPERTY) {
1691 $$.c->opcode = OPCODE_DELETEPROPERTY;
1692 } else if($$.c->opcode == OPCODE_GETSLOT) {
1693 int slot = (int)(ptroff_t)$$.c->data[0];
1694 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1695 $$.c = code_cutlast($$.c);
1696 $$.c = abc_deleteproperty2($$.c, name);
1698 $$.c = abc_getlocal_0($$.c);
1699 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1700 $$.c = abc_deleteproperty2($$.c, &m);
1702 $$.t = TYPE_BOOLEAN;
1705 RETURN: "return" %prec prec_none {
1706 $$ = abc_returnvoid(0);
1708 RETURN: "return" EXPRESSION {
1710 $$ = abc_returnvalue($$);
1713 // ----------------------- expression types -------------------------------------
1715 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1716 EXPRESSION : E %prec below_minus {$$ = $1;}
1717 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1719 $$.c = cut_last_push($$.c);
1720 $$.c = code_append($$.c,$3.c);
1723 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1724 $$=cut_last_push($1.c);
1727 // ----------------------- expression evaluation -------------------------------------
1730 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1732 E : DELETE {$$ = $1;}
1733 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1737 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1738 //MULTINAME(m, registry_getintclass());
1739 //$$.c = abc_coerce2($$.c, &m); // FIXME
1742 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1745 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1748 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1751 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1754 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1757 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1760 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1761 $$.t = TYPE_BOOLEAN;
1763 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1764 $$.t = TYPE_BOOLEAN;
1766 CONSTANT : "null" {$$.c = abc_pushnull(0);
1771 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1772 $$.t = TYPE_BOOLEAN;
1774 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1775 $$.t = TYPE_BOOLEAN;
1777 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1778 $$.t = TYPE_BOOLEAN;
1780 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1781 $$.t = TYPE_BOOLEAN;
1783 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1784 $$.t = TYPE_BOOLEAN;
1786 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1787 $$.t = TYPE_BOOLEAN;
1789 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1790 $$.t = TYPE_BOOLEAN;
1792 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1793 $$.t = TYPE_BOOLEAN;
1796 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1798 $$.c = converttype($$.c, $1.t, $$.t);
1799 $$.c = abc_dup($$.c);
1800 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1801 $$.c = cut_last_push($$.c);
1802 $$.c = code_append($$.c,$3.c);
1803 $$.c = converttype($$.c, $3.t, $$.t);
1804 code_t*label = $$.c = abc_label($$.c);
1805 jmp->branch = label;
1808 $$.t = join_types($1.t, $3.t, 'A');
1809 /*printf("%08x:\n",$1.t);
1810 code_dump($1.c, 0, 0, "", stdout);
1811 printf("%08x:\n",$3.t);
1812 code_dump($3.c, 0, 0, "", stdout);
1813 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1815 $$.c = converttype($$.c, $1.t, $$.t);
1816 $$.c = abc_dup($$.c);
1817 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1818 $$.c = cut_last_push($$.c);
1819 $$.c = code_append($$.c,$3.c);
1820 $$.c = converttype($$.c, $3.t, $$.t);
1821 code_t*label = $$.c = abc_label($$.c);
1822 jmp->branch = label;
1825 E : '!' E {$$.c=$2.c;
1826 $$.c = abc_not($$.c);
1827 $$.t = TYPE_BOOLEAN;
1830 E : '~' E {$$.c=$2.c;
1831 $$.c = abc_bitnot($$.c);
1835 E : E '&' E {$$.c = code_append($1.c,$3.c);
1836 $$.c = abc_bitand($$.c);
1840 E : E '^' E {$$.c = code_append($1.c,$3.c);
1841 $$.c = abc_bitxor($$.c);
1845 E : E '|' E {$$.c = code_append($1.c,$3.c);
1846 $$.c = abc_bitor($$.c);
1850 E : E '-' E {$$.c = code_append($1.c,$3.c);
1851 if(BOTH_INT($1,$3)) {
1852 $$.c = abc_subtract_i($$.c);
1855 $$.c = abc_subtract($$.c);
1859 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1860 $$.c = abc_rshift($$.c);
1863 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1864 $$.c = abc_urshift($$.c);
1867 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1868 $$.c = abc_lshift($$.c);
1872 E : E '/' E {$$.c = code_append($1.c,$3.c);
1873 $$.c = abc_divide($$.c);
1876 E : E '+' E {$$.c = code_append($1.c,$3.c);
1877 $$.c = abc_add($$.c);
1880 E : E '%' E {$$.c = code_append($1.c,$3.c);
1881 $$.c = abc_modulo($$.c);
1884 E : E '*' E {$$.c = code_append($1.c,$3.c);
1885 if(BOTH_INT($1,$3)) {
1886 $$.c = abc_multiply_i($$.c);
1889 $$.c = abc_multiply($$.c);
1894 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1895 if(use_astype && TYPE_IS_CLASS($3.t)) {
1896 MULTINAME(m,$3.t->cls);
1897 $$.c = abc_astype2($1.c, &m);
1900 $$.c = code_append($1.c, $3.c);
1901 $$.c = abc_astypelate($$.c);
1906 E : E "instanceof" E
1907 {$$.c = code_append($1.c, $3.c);
1908 $$.c = abc_instanceof($$.c);
1909 $$.t = TYPE_BOOLEAN;
1912 E : E "is" E {$$.c = code_append($1.c, $3.c);
1913 $$.c = abc_istypelate($$.c);
1914 $$.t = TYPE_BOOLEAN;
1917 E : "typeof" '(' E ')' {
1919 $$.c = abc_typeof($$.c);
1924 $$.c = cut_last_push($2.c);
1925 $$.c = abc_pushundefined($$.c);
1929 E : "void" { $$.c = abc_pushundefined(0);
1933 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
1938 $$.c=abc_negate_i($$.c);
1941 $$.c=abc_negate($$.c);
1948 $$.c = code_append($$.c, $3.c);
1950 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1951 $$.c = abc_getproperty2($$.c, &m);
1952 $$.t = 0; // array elements have unknown type
1957 if(BOTH_INT($1,$3)) {
1958 c=abc_multiply_i(c);
1962 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1963 $$.c = toreadwrite($1.c, c, 0, 0);
1968 code_t*c = abc_modulo($3.c);
1969 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1970 $$.c = toreadwrite($1.c, c, 0, 0);
1974 code_t*c = abc_lshift($3.c);
1975 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1976 $$.c = toreadwrite($1.c, c, 0, 0);
1980 code_t*c = abc_rshift($3.c);
1981 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1982 $$.c = toreadwrite($1.c, c, 0, 0);
1986 code_t*c = abc_urshift($3.c);
1987 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1988 $$.c = toreadwrite($1.c, c, 0, 0);
1992 code_t*c = abc_divide($3.c);
1993 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1994 $$.c = toreadwrite($1.c, c, 0, 0);
1999 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2004 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2006 $$.c = toreadwrite($1.c, c, 0, 0);
2009 E : E "-=" E { code_t*c = $3.c;
2010 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2011 c=abc_subtract_i(c);
2015 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2017 $$.c = toreadwrite($1.c, c, 0, 0);
2020 E : E '=' E { code_t*c = 0;
2021 c = code_append(c, $3.c);
2022 c = converttype(c, $3.t, $1.t);
2023 $$.c = toreadwrite($1.c, c, 1, 0);
2027 E : E '?' E ':' E %prec below_assignment {
2029 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2030 $$.c = code_append($$.c, $3.c);
2031 code_t*j2 = $$.c = abc_jump($$.c, 0);
2032 $$.c = j1->branch = abc_label($$.c);
2033 $$.c = code_append($$.c, $5.c);
2034 $$.c = j2->branch = abc_label($$.c);
2035 $$.t = join_types($3.t,$5.t,'?');
2038 // TODO: use inclocal where appropriate
2039 E : E "++" { code_t*c = 0;
2040 classinfo_t*type = $1.t;
2041 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2042 c=abc_increment_i(c);
2048 c=converttype(c, type, $1.t);
2049 $$.c = toreadwrite($1.c, c, 0, 1);
2052 E : E "--" { code_t*c = 0;
2053 classinfo_t*type = $1.t;
2054 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2055 c=abc_decrement_i(c);
2061 c=converttype(c, type, $1.t);
2062 $$.c = toreadwrite($1.c, c, 0, 1);
2066 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2067 classinfo_t*type = $2.t;
2068 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2069 c=abc_increment_i(c);
2075 c=converttype(c, type, $2.t);
2076 $$.c = toreadwrite($2.c, c, 0, 0);
2080 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2081 classinfo_t*type = $2.t;
2082 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2083 c=abc_decrement_i(c);
2089 c=converttype(c, type, $2.t);
2090 $$.c = toreadwrite($2.c, c, 0, 0);
2094 E : "super" '.' T_IDENTIFIER
2095 { if(!state->cls->info)
2096 syntaxerror("super keyword not allowed outside a class");
2097 classinfo_t*t = state->cls->info->superclass;
2098 if(!t) t = TYPE_OBJECT;
2100 memberinfo_t*f = registry_findmember(t, $3);
2101 namespace_t ns = {flags2access(f->flags), ""};
2102 MEMBER_MULTINAME(m, f, $3);
2104 $$.c = abc_getlocal_0($$.c);
2105 $$.c = abc_getsuper2($$.c, &m);
2106 $$.t = memberinfo_gettype(f);
2109 E : E '.' T_IDENTIFIER
2111 classinfo_t*t = $1.t;
2113 if(TYPE_IS_CLASS(t) && t->cls) {
2118 memberinfo_t*f = registry_findmember(t, $3);
2120 if(f && !is_static != !(f->flags&FLAG_STATIC))
2122 if(f && f->slot && !noslot) {
2123 $$.c = abc_getslot($$.c, f->slot);
2125 MEMBER_MULTINAME(m, f, $3);
2126 $$.c = abc_getproperty2($$.c, &m);
2128 /* determine type */
2129 $$.t = memberinfo_gettype(f);
2131 $$.c = abc_coerce_a($$.c);
2133 /* when resolving a property on an unknown type, we do know the
2134 name of the property (and don't seem to need the package), but
2135 we need to make avm2 try out all access modes */
2136 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2137 $$.c = abc_getproperty2($$.c, &m);
2138 $$.c = abc_coerce_a($$.c);
2139 $$.t = registry_getanytype();
2143 VAR_READ : T_IDENTIFIER {
2150 /* look at variables */
2151 if((i = find_variable($1, &$$.t)) >= 0) {
2152 // $1 is a local variable
2153 $$.c = abc_getlocal($$.c, i);
2155 /* look at current class' members */
2156 } else if((f = registry_findmember(state->cls->info, $1))) {
2157 // $1 is a function in this class
2158 int var_is_static = (f->flags&FLAG_STATIC);
2159 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2160 if(var_is_static != i_am_static) {
2161 /* there doesn't seem to be any "static" way to access
2162 static properties of a class */
2163 state->method->late_binding = 1;
2165 namespace_t ns = {flags2access(f->flags), ""};
2166 multiname_t m = {QNAME, &ns, 0, $1};
2167 $$.c = abc_findpropstrict2($$.c, &m);
2168 $$.c = abc_getproperty2($$.c, &m);
2171 $$.c = abc_getlocal_0($$.c);
2172 $$.c = abc_getslot($$.c, f->slot);
2174 namespace_t ns = {flags2access(f->flags), ""};
2175 multiname_t m = {QNAME, &ns, 0, $1};
2176 $$.c = abc_getlocal_0($$.c);
2177 $$.c = abc_getproperty2($$.c, &m);
2180 if(f->kind == MEMBER_METHOD) {
2181 $$.t = TYPE_FUNCTION(f);
2186 /* look at classes in the current package and imported classes */
2187 } else if((a = find_class($1))) {
2188 if(a->flags & FLAG_METHOD) {
2190 $$.c = abc_findpropstrict2($$.c, &m);
2191 $$.c = abc_getproperty2($$.c, &m);
2192 $$.t = TYPE_FUNCTION(a->function);
2195 $$.c = abc_getglobalscope($$.c);
2196 $$.c = abc_getslot($$.c, a->slot);
2199 $$.c = abc_getlex2($$.c, &m);
2201 $$.t = TYPE_CLASS(a);
2204 /* unknown object, let the avm2 resolve it */
2206 if(strcmp($1,"trace"))
2207 warning("Couldn't resolve '%s', doing late binding", $1);
2208 state->method->late_binding = 1;
2210 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2213 $$.c = abc_findpropstrict2($$.c, &m);
2214 $$.c = abc_getproperty2($$.c, &m);
2219 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2220 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2221 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2223 // ----------------- namespaces -------------------------------------------------
2225 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2226 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2227 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2229 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER