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_IMPORT "import"
91 %token<token> KW_RETURN "return"
92 %token<token> KW_TYPEOF "typeof"
93 %token<token> KW_INTERFACE "interface"
94 %token<token> KW_NULL "null"
95 %token<token> KW_VAR "var"
96 %token<token> KW_DYNAMIC
97 %token<token> KW_OVERRIDE
98 %token<token> KW_FINAL
99 %token<token> KW_GET "get"
100 %token<token> KW_SUPER "super"
101 %token<token> KW_EXTENDS
102 %token<token> KW_FALSE "false"
103 %token<token> KW_TRUE "true"
104 %token<token> KW_BOOLEAN "Boolean"
105 %token<token> KW_UINT "uint"
106 %token<token> KW_INT "int"
107 %token<token> KW_WHILE "while"
108 %token<token> KW_NUMBER "Number"
109 %token<token> KW_STRING "String"
110 %token<token> KW_DELETE "delete"
111 %token<token> KW_IF "if"
112 %token<token> KW_ELSE "else"
113 %token<token> KW_BREAK "break"
114 %token<token> KW_IS "is"
115 %token<token> KW_AS "as"
117 %token<token> T_EQEQ "=="
118 %token<token> T_EQEQEQ "==="
119 %token<token> T_NE "!="
120 %token<token> T_NEE "!=="
121 %token<token> T_LE "<="
122 %token<token> T_GE ">="
123 %token<token> T_DIVBY "/="
124 %token<token> T_MODBY "%="
125 %token<token> T_MULBY "*="
126 %token<token> T_PLUSBY "+="
127 %token<token> T_MINUSBY "-="
128 %token<token> T_SHRBY ">>="
129 %token<token> T_SHLBY "<<="
130 %token<token> T_USHRBY ">>>="
131 %token<token> T_OROR "||"
132 %token<token> T_ANDAND "&&"
133 %token<token> T_COLONCOLON "::"
134 %token<token> T_MINUSMINUS "--"
135 %token<token> T_PLUSPLUS "++"
136 %token<token> T_DOTDOT ".."
137 %token<token> T_DOTDOTDOT "..."
138 %token<token> T_SHL "<<"
139 %token<token> T_USHR ">>>"
140 %token<token> T_SHR ">>"
142 %type <id> X_IDENTIFIER PACKAGE
143 %type <token> VARCONST
145 %type <code> CODEPIECE
146 %type <code> CODEBLOCK MAYBECODE
147 %type <token> PACKAGE_DECLARATION
148 %type <token> FUNCTION_DECLARATION
149 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
150 %type <token> CLASS_DECLARATION
151 %type <token> NAMESPACE_DECLARATION
152 %type <token> INTERFACE_DECLARATION
153 %type <code> VOIDEXPRESSION
154 %type <value> EXPRESSION NONCOMMAEXPRESSION
155 %type <value> MAYBEEXPRESSION
156 %type <value> E DELETE
157 %type <value> CONSTANT
158 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
159 %type <token> USE_NAMESPACE
160 %type <code> FOR_INIT
162 %type <classinfo> MAYBETYPE
165 %type <params> PARAM_LIST
166 %type <params> MAYBE_PARAM_LIST
167 %type <flags> MAYBE_MODIFIERS
168 %type <flags> MODIFIER_LIST
169 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
170 %type <classinfo_list> IMPLEMENTS_LIST
171 %type <classinfo> EXTENDS
172 %type <classinfo_list> EXTENDS_LIST
173 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
174 %type <classinfo_list> QNAME_LIST
175 %type <classinfo> TYPE
177 //%type <token> VARIABLE
178 %type <value> VAR_READ
180 //%type <token> T_IDENTIFIER
181 %type <token> MODIFIER
182 %type <value> FUNCTIONCALL
183 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
185 // precedence: from low to high
189 %left below_semicolon
192 %nonassoc below_assignment // for ?:, contrary to spec
193 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
200 %nonassoc "==" "!=" "===" "!=="
202 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
203 %left "<<" ">>" ">>>"
207 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
209 %left '[' ']' '{' "new" '.' ".." "::"
210 %nonassoc T_IDENTIFIER
215 // needed for "return" precedence:
216 %nonassoc T_STRING T_REGEXP
217 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
218 %nonassoc "false" "true" "null" "undefined" "super"
223 static int yyerror(char*s)
225 syntaxerror("%s", s);
227 static char* concat3str(const char* t1, const char* t2, const char* t3)
232 char*text = malloc(l1+l2+l3+1);
233 memcpy(text , t1, l1);
234 memcpy(text+l1, t2, l2);
235 memcpy(text+l1+l2, t3, l3);
240 typedef struct _import {
244 DECLARE_LIST(import);
246 typedef struct _classstate {
254 typedef struct _methodstate {
259 /* code that needs to be executed at the start of
260 a method (like initializing local registers) */
266 typedef struct _state {
270 import_list_t*wildcard_imports;
272 char has_own_imports;
275 methodstate_t*method;
278 typedef struct _global {
285 static global_t*global = 0;
286 static state_t* state = 0;
290 #define MULTINAME(m,x) \
293 registry_fill_multiname(&m, &m##_ns, x);
295 #define MEMBER_MULTINAME(m,f) \
299 m##_ns.access = flags2access(f->flags); \
303 m.namespace_set = 0; \
306 m.type = MULTINAME; \
308 m.namespace_set = &nopackage_namespace_set; \
312 /* warning: list length of namespace set is undefined */
313 #define MULTINAME_LATE(m, access, package) \
314 namespace_t m##_ns = {access, package}; \
315 namespace_set_t m##_nsset; \
316 namespace_list_t m##_l;m##_l.next = 0; \
317 m##_nsset.namespaces = &m##_l; \
318 m##_nsset = m##_nsset; \
319 m##_l.namespace = &m##_ns; \
320 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
322 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
323 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
324 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
325 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
326 static namespace_list_t nl4 = {&ns4,0};
327 static namespace_list_t nl3 = {&ns3,&nl4};
328 static namespace_list_t nl2 = {&ns2,&nl3};
329 static namespace_list_t nl1 = {&ns1,&nl2};
330 static namespace_set_t nopackage_namespace_set = {&nl1};
332 static state_list_t*state_stack=0;
334 static void init_globals()
336 global = rfx_calloc(sizeof(global_t));
339 static void new_state()
342 NEW(state_list_t, sl);
344 state_t*oldstate = state;
346 memcpy(s, state, sizeof(state_t)); //shallow copy
347 sl->next = state_stack;
350 s->imports = dict_new();
355 state->has_own_imports = 0;
357 static void state_has_imports()
359 state->wildcard_imports = list_clone(state->wildcard_imports);
360 state->imports = dict_clone(state->imports);
361 state->has_own_imports = 1;
364 static void old_state()
366 if(!state_stack || !state_stack->next)
367 syntaxerror("invalid nesting");
368 state_t*oldstate = state;
369 state_list_t*old = state_stack;
370 state_stack = state_stack->next;
372 state = state_stack->state;
373 /*if(state->method->initcode) {
374 printf("residual initcode\n");
375 code_dump(state->method->initcode, 0, 0, "", stdout);
377 if(oldstate->has_own_imports) {
378 list_free(oldstate->wildcard_imports);
379 dict_destroy(oldstate->imports);oldstate->imports=0;
382 state->method->initcode =
383 code_append(state->method->initcode,
384 oldstate->method->initcode);
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);
532 if(interface) abc_class_interface(state->cls->abc);
534 for(mlist=implements;mlist;mlist=mlist->next) {
535 MULTINAME(m, mlist->classinfo);
536 abc_class_add_interface(state->cls->abc, &m);
539 /* now write the construction code for this class */
540 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
542 abc_method_body_t*m = global->init->method->body;
543 __ getglobalscope(m);
544 classinfo_t*s = extends;
549 //TODO: take a look at the current scope stack, maybe
550 // we can re-use something
555 multiname_t*s2 = sig2mname(s);
557 multiname_destroy(s2);
559 __ pushscope(m); count++;
560 m->code = m->code->prev->prev; // invert
562 /* continue appending after last op end */
563 while(m->code && m->code->next) m->code = m->code->next;
565 /* TODO: if this is one of *our* classes, we can also
566 do a getglobalscope/getslot <nr> (which references
567 the init function's slots) */
569 __ getlex2(m, extends2);
571 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
572 stack is not the superclass */
573 __ pushscope(m);count++;
576 /* notice: we get a verify error #1107 if the top element on the scope
577 stack is not the global object */
579 __ pushscope(m);count++;
581 __ newclass(m,state->cls->abc);
585 __ setslot(m, slotindex);
587 /* flash.display.MovieClip handling */
588 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
589 if(state->package && state->package[0]) {
590 globalclass = concat3str(state->package, ".", classname);
592 globalclass = strdup(classname);
595 multiname_destroy(extends2);
598 static void endclass()
600 if(state->cls->init) {
601 if(!state->cls->abc->constructor) {
602 abc_method_t*m = abc_class_constructor(state->cls->abc, 0);
603 m->body->code = code_append(m->body->code, state->cls->init);
604 m->body->code = abc_returnvoid(m->body->code);
606 code_t*c = state->cls->abc->constructor->body->code;
607 c = code_append(state->cls->init, c);
608 state->cls->abc->constructor->body->code = c;
612 if(state->cls->static_init) {
613 if(!state->cls->abc->static_constructor) {
614 abc_method_t*m = abc_class_staticconstructor(state->cls->abc, 0);
615 m->body->code = code_append(m->body->code, state->cls->static_init);
616 m->body->code = abc_returnvoid(m->body->code);
618 state->cls->abc->static_constructor->body->code =
619 code_append(state->cls->static_init, state->cls->abc->static_constructor->body->code);
626 typedef struct _variable {
631 static int find_variable(char*name, classinfo_t**m)
633 state_list_t* s = state_stack;
637 v = dict_lookup(s->state->method->vars, name);
648 static int find_variable_safe(char*name, classinfo_t**m)
650 int i = find_variable(name, m);
652 syntaxerror("undefined variable: %s", name);
655 static char variable_exists(char*name)
657 return dict_lookup(state->method->vars, name)!=0;
659 static int new_variable(char*name, classinfo_t*type)
662 v->index = global->variable_count;
664 dict_put(state->method->vars, name, v);
665 return global->variable_count++;
667 #define TEMPVARNAME "__as3_temp__"
668 static int gettempvar()
670 int i = find_variable(TEMPVARNAME, 0);
672 return new_variable(TEMPVARNAME, 0);
678 code_t* killvars(code_t*c)
681 for(t=0;t<state->method->vars->hashsize;t++) {
682 dictentry_t*e =state->method->vars->slots[t];
684 variable_t*v = (variable_t*)e->data;
685 //do this always, otherwise register types don't match
686 //in the verifier when doing nested loops
687 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
688 c = abc_kill(c, v->index);
696 static void check_constant_against_type(classinfo_t*t, constant_t*c)
698 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
699 if(TYPE_IS_NUMBER(t)) {
700 xassert(c->type == CONSTANT_FLOAT
701 || c->type == CONSTANT_INT
702 || c->type == CONSTANT_UINT);
703 } else if(TYPE_IS_UINT(t)) {
704 xassert(c->type == CONSTANT_UINT ||
705 (c->type == CONSTANT_INT && c->i>0));
706 } else if(TYPE_IS_INT(t)) {
707 xassert(c->type == CONSTANT_INT);
708 } else if(TYPE_IS_BOOLEAN(t)) {
709 xassert(c->type == CONSTANT_TRUE
710 || c->type == CONSTANT_FALSE);
714 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
716 memberinfo_t*minfo = 0;
717 if(getset != KW_GET && getset != KW_SET) {
718 if(registry_findmember(state->cls->info, name)) {
719 syntaxerror("class already contains a member/method called '%s'", name);
721 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
722 minfo->return_type = return_type;
723 // getslot on a member slot only returns "undefined", so no need
724 // to actually store these
725 //state->minfo->slot = state->method->a bc->method->trait->slot_id;
727 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
731 else if(params->list)
732 type = params->list->param->type;
733 if((minfo=registry_findmember(state->cls->info, name))) {
734 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
735 syntaxerror("class already contains a member or method called '%s'", name);
737 syntaxerror("getter/setter for '%s' already defined", name);
738 /* make a setter or getter into a getset */
743 if(type && minfo->type != type)
744 syntaxerror("different type in getter and setter");
746 minfo = memberinfo_register(state->cls->info, name, gs);
749 /* can't assign a slot as getter and setter might have different slots */
750 //minfo->slot = slot;
752 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
753 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
754 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
755 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
756 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
760 static int flags2access(int flags)
763 if(flags&FLAG_PUBLIC) {
764 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
765 access = ACCESS_PACKAGE;
766 } else if(flags&FLAG_PRIVATE) {
767 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
768 access = ACCESS_PRIVATE;
769 } else if(flags&FLAG_PROTECTED) {
770 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
771 access = ACCESS_PROTECTED;
773 access = ACCESS_PACKAGEINTERNAL;
778 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
779 params_t*params, classinfo_t*return_type)
782 syntaxerror("not able to start another method scope");
785 state->method = rfx_calloc(sizeof(methodstate_t));
786 state->method->initcode = 0;
787 state->method->is_constructor = !strcmp(state->cls->info->name,name);
788 state->method->has_super = 0;
790 global->variable_count = 0;
791 state->method->vars = dict_new();
792 /* state->vars is initialized by state_new */
793 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
795 for(p=params->list;p;p=p->next) {
796 new_variable(p->param->name, p->param->type);
798 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
801 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
802 params_t*params, classinfo_t*return_type, code_t*body)
804 namespace_t mname_ns = {flags2access(flags), ""};
805 multiname_t mname = {QNAME, &mname_ns, 0, name};
809 multiname_t*type2 = sig2mname(return_type);
811 if(state->method->is_constructor) {
812 f = abc_class_constructor(state->cls->abc, type2);
813 name = "__as3_constructor__";
815 if(flags&FLAG_STATIC)
816 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
818 f = abc_class_method(state->cls->abc, type2, &mname);
819 slot = f->trait->slot_id;
821 state->method->info->slot = slot;
823 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
824 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
825 if(params->varargs) f->flags |= METHOD_NEED_REST;
829 for(p=params->list;p;p=p->next) {
830 if(params->varargs && !p->next) {
831 break; //varargs: omit last parameter in function signature
833 multiname_t*m = sig2mname(p->param->type);
834 list_append(f->parameters, m);
835 if(p->param->value) {
836 check_constant_against_type(p->param->type, p->param->value);
837 opt=1;list_append(f->optional_parameters, p->param->value);
839 syntaxerror("non-optional parameter not allowed after optional parameters");
842 f->body->code = body;
849 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
854 void breakjumpsto(code_t*c, code_t*jump)
859 if(c->opcode == OPCODE___BREAK__) {
860 c->opcode = OPCODE_JUMP;
867 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
870 return registry_getanytype();
871 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
872 return registry_getanytype();
875 return registry_getanytype();
877 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
882 return abc_coerce_a(c);
886 // cast an "any" type to a specific type. subject to
887 // runtime exceptions
888 return abc_coerce2(c, &m);
891 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
892 return abc_coerce2(c, &m);
894 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
895 return abc_coerce2(c, &m);
897 /* these are subject to overflow */
898 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
899 return abc_coerce2(c, &m);
901 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
902 return abc_coerce2(c, &m);
905 classinfo_t*supertype = from;
907 if(supertype == to) {
908 // target type is one of from's superclasses
909 return abc_coerce2(c, &m);
912 while(supertype->interfaces[t]) {
913 if(supertype->interfaces[t]==to) {
914 // to type is one of from's interfaces
915 return abc_coerce2(c, &m);
919 supertype = supertype->superclass;
921 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
923 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
925 syntaxerror("can't convert type %s to %s", from->name, to->name);
928 code_t*defaultvalue(code_t*c, classinfo_t*type)
930 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
931 c = abc_pushbyte(c, 0);
932 } else if(TYPE_IS_BOOLEAN(type)) {
933 c = abc_pushfalse(c);
940 char is_pushundefined(code_t*c)
942 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
945 void parserassert(int b)
947 if(!b) syntaxerror("internal error: assertion failed");
950 static classinfo_t* find_class(char*name)
954 c = registry_findclass(state->package, name);
956 /* try explicit imports */
957 dictentry_t* e = dict_get_slot(state->imports, name);
961 if(!strcmp(e->key, name)) {
962 c = (classinfo_t*)e->data;
967 /* try package.* imports */
968 import_list_t*l = state->wildcard_imports;
972 //printf("does package %s contain a class %s?\n", l->import->package, name);
973 c = registry_findclass(l->import->package, name);
977 /* try global package */
979 c = registry_findclass("", name);
984 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
988 [prefix code] [read instruction]
992 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
995 if(in && in->opcode == OPCODE_COERCE_A) {
996 in = code_cutlast(in);
999 syntaxerror("internal error");
1001 /* chop off read instruction */
1005 prefix = r->prev;r->prev = 0;
1011 char use_temp_var = readbefore;
1013 /* generate the write instruction, and maybe append a dup to the prefix code */
1014 code_t* write = abc_nop(0);
1015 if(r->opcode == OPCODE_GETPROPERTY) {
1016 write->opcode = OPCODE_SETPROPERTY;
1017 multiname_t*m = (multiname_t*)r->data[0];
1018 write->data[0] = multiname_clone(m);
1019 if(m->type == QNAME || m->type == MULTINAME) {
1021 prefix = abc_dup(prefix); // we need the object, too
1024 } else if(m->type == MULTINAMEL) {
1026 /* dupping two values on the stack requires 5 operations and one register-
1027 couldn't adobe just have given us a dup2? */
1028 int temp = gettempvar();
1029 prefix = abc_setlocal(prefix, temp);
1030 prefix = abc_dup(prefix);
1031 prefix = abc_getlocal(prefix, temp);
1032 prefix = abc_swap(prefix);
1033 prefix = abc_getlocal(prefix, temp);
1037 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1039 } else if(r->opcode == OPCODE_GETSLOT) {
1040 write->opcode = OPCODE_SETSLOT;
1041 write->data[0] = r->data[0];
1043 prefix = abc_dup(prefix); // we need the object, too
1046 } else if(r->opcode == OPCODE_GETLOCAL) {
1047 write->opcode = OPCODE_SETLOCAL;
1048 write->data[0] = r->data[0];
1049 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1050 write->opcode = OPCODE_SETLOCAL_0;
1051 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1052 write->opcode = OPCODE_SETLOCAL_1;
1053 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1054 write->opcode = OPCODE_SETLOCAL_2;
1055 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1056 write->opcode = OPCODE_SETLOCAL_3;
1058 code_dump(r, 0, 0, "", stdout);
1059 syntaxerror("illegal lvalue: can't assign a value to this expression");
1066 /* with getproperty/getslot, we have to be extra careful not
1067 to execute the read code twice, as it might have side-effects
1068 (e.g. if the property is in fact a setter/getter combination)
1070 So read the value, modify it, and write it again,
1071 using prefix only once and making sure (by using a temporary
1072 register) that the return value is what we just wrote */
1073 temp = gettempvar();
1074 c = code_append(c, prefix);
1075 c = code_append(c, r);
1078 c = abc_setlocal(c, temp);
1080 c = code_append(c, middlepart);
1083 c = abc_setlocal(c, temp);
1085 c = code_append(c, write);
1086 c = abc_getlocal(c, temp);
1087 c = abc_kill(c, temp);
1089 /* if we're allowed to execute the read code twice *and*
1090 the middlepart doesn't modify the code, things are easier.
1092 code_t* r2 = code_dup(r);
1093 //c = code_append(c, prefix);
1094 parserassert(!prefix);
1095 c = code_append(c, r);
1096 c = code_append(c, middlepart);
1097 c = code_append(c, write);
1098 c = code_append(c, r2);
1101 /* even smaller version: overwrite the value without reading
1105 c = code_append(c, prefix);
1108 c = code_append(c, middlepart);
1109 c = code_append(c, write);
1110 c = code_append(c, r);
1112 temp = gettempvar();
1114 c = code_append(c, prefix);
1117 c = code_append(c, middlepart);
1119 c = abc_setlocal(c, temp);
1120 c = code_append(c, write);
1121 c = abc_getlocal(c, temp);
1128 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1129 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1136 /* ------------ code blocks / statements ---------------- */
1140 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1141 MAYBECODE: {$$=code_new();}
1143 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1144 CODE: CODEPIECE {$$=$1;}
1146 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1147 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1148 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1149 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1150 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1151 CODEPIECE: ';' {$$=code_new();}
1152 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1153 CODEPIECE: VOIDEXPRESSION {$$=$1}
1154 CODEPIECE: FOR {$$=$1}
1155 CODEPIECE: WHILE {$$=$1}
1156 CODEPIECE: BREAK {$$=$1}
1157 CODEPIECE: RETURN {$$=$1}
1158 CODEPIECE: IF {$$=$1}
1159 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1160 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1162 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1163 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1164 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1166 /* ------------ variables --------------------------- */
1168 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1169 | {$$.c=abc_pushundefined(0);
1173 VAR : "const" | "var"
1174 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1176 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1177 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1179 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1181 if(variable_exists($2))
1182 syntaxerror("Variable %s already defined", $2);
1184 if(!is_subtype_of($4.t, $3)) {
1185 syntaxerror("Can't convert %s to %s", $4.t->name,
1189 int index = new_variable($2, $3);
1192 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1194 $$ = converttype($$, $4.t, $3);
1195 $$ = abc_setlocal($$, index);
1197 $$ = defaultvalue(0, $3);
1198 $$ = abc_setlocal($$, index);
1201 /* if this is a typed variable:
1202 push default value for type on stack */
1204 state->method->initcode = defaultvalue(state->method->initcode, $3);
1205 state->method->initcode = abc_setlocal(state->method->initcode, index);
1208 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1210 $$ = abc_coerce_a($$);
1211 $$ = abc_setlocal($$, index);
1217 /* that's the default for a local register, anyway
1219 state->method->initcode = abc_pushundefined(state->method->initcode);
1220 state->method->initcode = abc_setlocal(state->method->initcode, index);
1222 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1225 /* ------------ control flow ------------------------- */
1227 MAYBEELSE: %prec below_else {$$ = code_new();}
1228 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1229 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1231 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1232 $$ = state->method->initcode;state->method->initcode=0;
1234 $$ = code_append($$, $4.c);
1235 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1237 $$ = code_append($$, $6);
1239 myjmp = $$ = abc_jump($$, 0);
1241 myif->branch = $$ = abc_label($$);
1243 $$ = code_append($$, $7);
1244 myjmp->branch = $$ = abc_label($$);
1247 $$ = killvars($$);old_state();
1250 FOR_INIT : {$$=code_new();}
1251 FOR_INIT : VARIABLE_DECLARATION
1252 FOR_INIT : VOIDEXPRESSION
1254 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1255 $$ = state->method->initcode;state->method->initcode=0;
1257 $$ = code_append($$, $4);
1258 code_t*loopstart = $$ = abc_label($$);
1259 $$ = code_append($$, $6.c);
1260 code_t*myif = $$ = abc_iffalse($$, 0);
1261 $$ = code_append($$, $10);
1262 $$ = code_append($$, $8);
1263 $$ = abc_jump($$, loopstart);
1264 code_t*out = $$ = abc_label($$);
1265 breakjumpsto($$, out);
1268 $$ = killvars($$);old_state();
1271 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1272 $$ = state->method->initcode;state->method->initcode=0;
1274 code_t*myjmp = $$ = abc_jump($$, 0);
1275 code_t*loopstart = $$ = abc_label($$);
1276 $$ = code_append($$, $6);
1277 myjmp->branch = $$ = abc_label($$);
1278 $$ = code_append($$, $4.c);
1279 $$ = abc_iftrue($$, loopstart);
1280 code_t*out = $$ = abc_label($$);
1281 breakjumpsto($$, out);
1283 $$ = killvars($$);old_state();
1287 $$ = abc___break__(0);
1290 /* ------------ packages and imports ---------------- */
1292 X_IDENTIFIER: T_IDENTIFIER
1293 | "package" {$$="package";}
1295 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1296 PACKAGE: X_IDENTIFIER {$$=$1;}
1298 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1299 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1301 IMPORT : "import" QNAME {
1304 syntaxerror("Couldn't import class\n");
1305 state_has_imports();
1306 dict_put(state->imports, c->name, c);
1309 IMPORT : "import" PACKAGE '.' '*' {
1312 state_has_imports();
1313 list_append(state->wildcard_imports, i);
1317 /* ------------ classes and interfaces (header) -------------- */
1319 MAYBE_MODIFIERS : {$$=0;}
1320 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1321 MODIFIER_LIST : MODIFIER {$$=$1;}
1322 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1324 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1325 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1326 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1327 | KW_STATIC {$$=FLAG_STATIC;}
1328 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1329 | KW_FINAL {$$=FLAG_FINAL;}
1330 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1331 | KW_NATIVE {$$=FLAG_NATIVE;}
1332 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1334 EXTENDS : {$$=registry_getobjectclass();}
1335 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1337 EXTENDS_LIST : {$$=list_new();}
1338 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1340 IMPLEMENTS_LIST : {$$=list_new();}
1341 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1343 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1344 EXTENDS IMPLEMENTS_LIST
1345 '{' {startclass($1,$3,$4,$5, 0);}
1346 MAYBE_DECLARATION_LIST
1349 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1351 '{' {startclass($1,$3,0,$4,1);}
1352 MAYBE_IDECLARATION_LIST
1355 /* ------------ classes and interfaces (body) -------------- */
1357 MAYBE_DECLARATION_LIST :
1358 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1359 DECLARATION_LIST : DECLARATION
1360 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1362 DECLARATION : SLOT_DECLARATION
1363 DECLARATION : FUNCTION_DECLARATION
1365 MAYBE_IDECLARATION_LIST :
1366 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1367 IDECLARATION_LIST : IDECLARATION
1368 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1370 IDECLARATION : "var" T_IDENTIFIER {
1371 syntaxerror("variable declarations not allowed in interfaces");
1373 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1375 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1376 syntaxerror("invalid method modifiers: interface methods always need to be public");
1378 startfunction(0,$1,$3,$4,&$6,$8);
1379 endfunction(0,$1,$3,$4,&$6,$8, 0);
1382 /* ------------ classes and interfaces (body, slots ) ------- */
1384 VARCONST: "var" | "const"
1386 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1388 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1390 info->flags = flags;
1393 namespace_t mname_ns = {flags2access(flags), ""};
1394 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1396 if(!(flags&FLAG_STATIC)) {
1399 t=abc_class_slot(state->cls->abc, &mname, &m);
1401 t=abc_class_slot(state->cls->abc, &mname, 0);
1403 info->slot = t->slot_id;
1407 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1409 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1411 info->slot = t->slot_id;
1413 if($5.c && !is_pushundefined($5.c)) {
1415 c = abc_getlocal_0(c);
1416 c = code_append(c, $5.c);
1417 c = converttype(c, $5.t, $4);
1418 c = abc_setslot(c, t->slot_id);
1419 if(!(flags&FLAG_STATIC))
1420 state->cls->init = code_append(state->cls->init, c);
1422 state->cls->static_init = code_append(state->cls->static_init, c);
1425 t->kind= TRAIT_CONST;
1429 /* ------------ constants -------------------------------------- */
1431 MAYBESTATICCONSTANT: {$$=0;}
1432 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1434 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1435 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1436 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1437 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1438 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1439 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1440 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1441 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1442 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1444 /* ------------ classes and interfaces (body, functions) ------- */
1446 // non-vararg version
1448 memset(&$$,0,sizeof($$));
1450 MAYBE_PARAM_LIST: PARAM_LIST {
1455 MAYBE_PARAM_LIST: "..." PARAM {
1456 memset(&$$,0,sizeof($$));
1458 list_append($$.list, $2);
1460 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1463 list_append($$.list, $4);
1467 PARAM_LIST: PARAM_LIST ',' PARAM {
1469 list_append($$.list, $3);
1472 memset(&$$,0,sizeof($$));
1473 list_append($$.list, $1);
1476 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1477 $$ = malloc(sizeof(param_t));
1482 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1483 $$ = malloc(sizeof(param_t));
1485 $$->type = TYPE_ANY;
1488 GETSET : "get" {$$=$1;}
1492 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1493 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1496 if(state->method->late_binding) {
1497 c = abc_getlocal_0(c);
1498 c = abc_pushscope(c);
1500 if(state->method->is_constructor && !state->method->has_super) {
1501 // generate default constructor
1502 c = abc_getlocal_0(c);
1503 c = abc_constructsuper(c, 0);
1506 c = code_append(c, state->method->initcode);
1507 c = code_append(c, $11);
1509 /* append return if necessary */
1510 if(!c || c->opcode != OPCODE_RETURNVOID &&
1511 c->opcode != OPCODE_RETURNVALUE) {
1512 c = abc_returnvoid(c);
1514 endfunction(0,$1,$3,$4,&$6,$8,c);
1517 /* ------------- package + class ids --------------- */
1519 CLASS: T_IDENTIFIER {
1521 /* try current package */
1522 $$ = find_class($1);
1523 if(!$$) syntaxerror("Could not find class %s\n", $1);
1526 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1527 $$ = registry_findclass($1, $3);
1528 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1531 QNAME: PACKAGEANDCLASS
1534 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1535 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1537 TYPE : QNAME {$$=$1;}
1538 | '*' {$$=registry_getanytype();}
1540 | "String" {$$=registry_getstringclass();}
1541 | "int" {$$=registry_getintclass();}
1542 | "uint" {$$=registry_getuintclass();}
1543 | "Boolean" {$$=registry_getbooleanclass();}
1544 | "Number" {$$=registry_getnumberclass();}
1547 MAYBETYPE: ':' TYPE {$$=$2;}
1550 /* ----------function calls, delete, constructor calls ------ */
1552 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1553 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1555 MAYBE_EXPRESSION_LIST : {$$=0;}
1556 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1557 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1558 typedcode_t*t = malloc(sizeof(typedcode_t));
1560 list_append($$, t);}
1561 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1562 typedcode_t*t = malloc(sizeof(typedcode_t));
1564 list_append($$, t);}
1566 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1571 $$.c = abc_getglobalscope($$.c);
1572 $$.c = abc_getslot($$.c, $2->slot);
1574 $$.c = abc_findpropstrict2($$.c, &m);
1577 typedcode_list_t*l = $3;
1580 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1585 $$.c = abc_construct($$.c, len);
1587 $$.c = abc_constructprop2($$.c, &m, len);
1591 /* TODO: use abc_call (for calling local variables),
1592 abc_callstatic (for calling own methods)
1595 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1596 typedcode_list_t*l = $3;
1598 code_t*paramcode = 0;
1600 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1606 if($$.c->opcode == OPCODE_COERCE_A) {
1607 $$.c = code_cutlast($$.c);
1611 multiname_t*name = 0;
1612 if($$.c->opcode == OPCODE_GETPROPERTY) {
1613 name = multiname_clone($$.c->data[0]);
1614 $$.c = code_cutlast($$.c);
1615 $$.c = code_append($$.c, paramcode);
1616 $$.c = abc_callproperty2($$.c, name, len);
1617 } else if($$.c->opcode == OPCODE_GETSLOT) {
1618 int slot = (int)(ptroff_t)$$.c->data[0];
1619 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1620 if(t->kind!=TRAIT_METHOD) {
1621 //flash allows to assign closures to members.
1622 //syntaxerror("not a function");
1625 $$.c = code_cutlast($$.c);
1626 $$.c = code_append($$.c, paramcode);
1627 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1628 $$.c = abc_callproperty2($$.c, name, len);
1629 } else if($$.c->opcode == OPCODE_GETSUPER) {
1630 name = multiname_clone($$.c->data[0]);
1631 $$.c = code_cutlast($$.c);
1632 $$.c = code_append($$.c, paramcode);
1633 $$.c = abc_callsuper2($$.c, name, len);
1635 $$.c = abc_getlocal_0($$.c);
1636 $$.c = code_append($$.c, paramcode);
1637 $$.c = abc_call($$.c, len);
1642 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1643 $$.t = $1.t->function->return_type;
1645 $$.c = abc_coerce_a($$.c);
1649 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1650 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1651 if(!state->method) syntaxerror("super() not allowed outside of a function");
1652 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1655 $$.c = abc_getlocal_0($$.c);
1656 typedcode_list_t*l = 0;
1658 for(l=$3;l;l=l->next) {
1659 $$.c = code_append($$.c, l->typedcode->c);len++;
1661 state->method->has_super = 1;
1662 $$.c = abc_constructsuper($$.c, len);
1663 $$.c = abc_pushundefined($$.c);
1667 DELETE: "delete" E {
1669 if($$.c->opcode == OPCODE_COERCE_A) {
1670 $$.c = code_cutlast($$.c);
1672 multiname_t*name = 0;
1673 if($$.c->opcode == OPCODE_GETPROPERTY) {
1674 $$.c->opcode = OPCODE_DELETEPROPERTY;
1675 } else if($$.c->opcode == OPCODE_GETSLOT) {
1676 int slot = (int)(ptroff_t)$$.c->data[0];
1677 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1678 $$.c = code_cutlast($$.c);
1679 $$.c = abc_deleteproperty2($$.c, name);
1681 $$.c = abc_getlocal_0($$.c);
1682 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1683 $$.c = abc_deleteproperty2($$.c, &m);
1685 $$.t = TYPE_BOOLEAN;
1688 RETURN: "return" %prec prec_none {
1689 $$ = abc_returnvoid(0);
1691 RETURN: "return" EXPRESSION {
1693 $$ = abc_returnvalue($$);
1696 // ----------------------- expression types -------------------------------------
1698 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1699 EXPRESSION : E %prec below_minus {$$ = $1;}
1700 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1702 $$.c = cut_last_push($$.c);
1703 $$.c = code_append($$.c,$3.c);
1706 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1707 $$=cut_last_push($1.c);
1710 // ----------------------- expression evaluation -------------------------------------
1713 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1715 E : DELETE {$$ = $1;}
1716 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1720 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1721 //MULTINAME(m, registry_getintclass());
1722 //$$.c = abc_coerce2($$.c, &m); // FIXME
1725 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1728 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1731 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1734 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1737 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1740 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1743 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1744 $$.t = TYPE_BOOLEAN;
1746 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1747 $$.t = TYPE_BOOLEAN;
1749 CONSTANT : "null" {$$.c = abc_pushnull(0);
1754 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1755 $$.t = TYPE_BOOLEAN;
1757 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1758 $$.t = TYPE_BOOLEAN;
1760 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1761 $$.t = TYPE_BOOLEAN;
1763 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1764 $$.t = TYPE_BOOLEAN;
1766 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1767 $$.t = TYPE_BOOLEAN;
1769 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1770 $$.t = TYPE_BOOLEAN;
1772 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1773 $$.t = TYPE_BOOLEAN;
1775 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1776 $$.t = TYPE_BOOLEAN;
1779 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1781 $$.c = converttype($$.c, $1.t, $$.t);
1782 $$.c = abc_dup($$.c);
1783 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1784 $$.c = cut_last_push($$.c);
1785 $$.c = code_append($$.c,$3.c);
1786 $$.c = converttype($$.c, $3.t, $$.t);
1787 code_t*label = $$.c = abc_label($$.c);
1788 jmp->branch = label;
1791 $$.t = join_types($1.t, $3.t, 'A');
1792 /*printf("%08x:\n",$1.t);
1793 code_dump($1.c, 0, 0, "", stdout);
1794 printf("%08x:\n",$3.t);
1795 code_dump($3.c, 0, 0, "", stdout);
1796 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1798 $$.c = converttype($$.c, $1.t, $$.t);
1799 $$.c = abc_dup($$.c);
1800 code_t*jmp = $$.c = abc_iffalse($$.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 E : '!' E {$$.c=$2.c;
1809 $$.c = abc_not($$.c);
1810 $$.t = TYPE_BOOLEAN;
1813 E : '~' E {$$.c=$2.c;
1814 $$.c = abc_bitnot($$.c);
1818 E : E '&' E {$$.c = code_append($1.c,$3.c);
1819 $$.c = abc_bitand($$.c);
1823 E : E '^' E {$$.c = code_append($1.c,$3.c);
1824 $$.c = abc_bitxor($$.c);
1828 E : E '|' E {$$.c = code_append($1.c,$3.c);
1829 $$.c = abc_bitor($$.c);
1833 E : E '-' E {$$.c = code_append($1.c,$3.c);
1834 if(BOTH_INT($1,$3)) {
1835 $$.c = abc_subtract_i($$.c);
1838 $$.c = abc_subtract($$.c);
1842 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1843 $$.c = abc_rshift($$.c);
1846 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1847 $$.c = abc_urshift($$.c);
1850 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1851 $$.c = abc_lshift($$.c);
1855 E : E '/' E {$$.c = code_append($1.c,$3.c);
1856 $$.c = abc_divide($$.c);
1859 E : E '+' E {$$.c = code_append($1.c,$3.c);
1860 $$.c = abc_add($$.c);
1863 E : E '%' E {$$.c = code_append($1.c,$3.c);
1864 $$.c = abc_modulo($$.c);
1867 E : E '*' E {$$.c = code_append($1.c,$3.c);
1868 if(BOTH_INT($1,$3)) {
1869 $$.c = abc_multiply_i($$.c);
1872 $$.c = abc_multiply($$.c);
1877 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1878 if(use_astype && TYPE_IS_CLASS($3.t)) {
1879 MULTINAME(m,$3.t->cls);
1880 $$.c = abc_astype2($1.c, &m);
1883 $$.c = code_append($1.c, $3.c);
1884 $$.c = abc_astypelate($$.c);
1889 E : E "is" E {$$.c = code_append($1.c, $3.c);
1890 $$.c = abc_istypelate($$.c);
1891 $$.t = TYPE_BOOLEAN;
1894 E : "typeof" '(' E ')' {
1896 $$.c = abc_typeof($$.c);
1901 $$.c = cut_last_push($2.c);
1902 $$.c = abc_pushundefined($$.c);
1906 E : "void" { $$.c = abc_pushundefined(0);
1910 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
1915 $$.c=abc_negate_i($$.c);
1918 $$.c=abc_negate($$.c);
1925 $$.c = code_append($$.c, $3.c);
1927 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1928 $$.c = abc_getproperty2($$.c, &m);
1929 $$.t = 0; // array elements have unknown type
1934 if(BOTH_INT($1,$3)) {
1935 c=abc_multiply_i(c);
1939 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1940 $$.c = toreadwrite($1.c, c, 0, 0);
1945 code_t*c = abc_modulo($3.c);
1946 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1947 $$.c = toreadwrite($1.c, c, 0, 0);
1951 code_t*c = abc_lshift($3.c);
1952 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1953 $$.c = toreadwrite($1.c, c, 0, 0);
1957 code_t*c = abc_rshift($3.c);
1958 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1959 $$.c = toreadwrite($1.c, c, 0, 0);
1963 code_t*c = abc_urshift($3.c);
1964 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1965 $$.c = toreadwrite($1.c, c, 0, 0);
1969 code_t*c = abc_divide($3.c);
1970 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1971 $$.c = toreadwrite($1.c, c, 0, 0);
1976 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1981 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1983 $$.c = toreadwrite($1.c, c, 0, 0);
1986 E : E "-=" E { code_t*c = $3.c;
1987 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1988 c=abc_subtract_i(c);
1992 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1994 $$.c = toreadwrite($1.c, c, 0, 0);
1997 E : E '=' E { code_t*c = 0;
1998 c = code_append(c, $3.c);
1999 c = converttype(c, $3.t, $1.t);
2000 $$.c = toreadwrite($1.c, c, 1, 0);
2004 E : E '?' E ':' E %prec below_assignment {
2006 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2007 $$.c = code_append($$.c, $3.c);
2008 code_t*j2 = $$.c = abc_jump($$.c, 0);
2009 $$.c = j1->branch = abc_label($$.c);
2010 $$.c = code_append($$.c, $5.c);
2011 $$.c = j2->branch = abc_label($$.c);
2012 $$.t = join_types($3.t,$5.t,'?');
2015 // TODO: use inclocal where appropriate
2016 E : E "++" { code_t*c = 0;
2017 classinfo_t*type = $1.t;
2018 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2019 c=abc_increment_i(c);
2025 c=converttype(c, type, $1.t);
2026 $$.c = toreadwrite($1.c, c, 0, 1);
2029 E : E "--" { code_t*c = 0;
2030 classinfo_t*type = $1.t;
2031 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2032 c=abc_decrement_i(c);
2038 c=converttype(c, type, $1.t);
2039 $$.c = toreadwrite($1.c, c, 0, 1);
2043 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2044 classinfo_t*type = $2.t;
2045 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2046 c=abc_increment_i(c);
2052 c=converttype(c, type, $2.t);
2053 $$.c = toreadwrite($2.c, c, 0, 0);
2057 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2058 classinfo_t*type = $2.t;
2059 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2060 c=abc_decrement_i(c);
2066 c=converttype(c, type, $2.t);
2067 $$.c = toreadwrite($2.c, c, 0, 0);
2071 E : "super" '.' T_IDENTIFIER
2072 { if(!state->cls->info)
2073 syntaxerror("super keyword not allowed outside a class");
2074 classinfo_t*t = state->cls->info->superclass;
2075 if(!t) t = TYPE_OBJECT;
2077 memberinfo_t*f = registry_findmember(t, $3);
2078 namespace_t ns = {flags2access(f->flags), ""};
2079 MEMBER_MULTINAME(m, f);
2081 $$.c = abc_getlocal_0($$.c);
2082 $$.c = abc_getsuper2($$.c, &m);
2083 $$.t = memberinfo_gettype(f);
2086 E : E '.' T_IDENTIFIER
2088 classinfo_t*t = $1.t;
2090 if(TYPE_IS_CLASS(t) && t->cls) {
2095 memberinfo_t*f = registry_findmember(t, $3);
2097 if(f && !is_static != !(f->flags&FLAG_STATIC))
2099 if(f && f->slot && !noslot) {
2100 $$.c = abc_getslot($$.c, f->slot);
2102 MEMBER_MULTINAME(m, f);
2103 $$.c = abc_getproperty2($$.c, &m);
2105 /* determine type */
2106 $$.t = memberinfo_gettype(f);
2108 $$.c = abc_coerce_a($$.c);
2110 /* when resolving a property on an unknown type, we do know the
2111 name of the property (and don't seem to need the package), but
2112 we need to make avm2 try out all access modes */
2113 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2114 $$.c = abc_getproperty2($$.c, &m);
2115 $$.c = abc_coerce_a($$.c);
2116 $$.t = registry_getanytype();
2120 VAR_READ : T_IDENTIFIER {
2127 /* look at variables */
2128 if((i = find_variable($1, &$$.t)) >= 0) {
2129 // $1 is a local variable
2130 $$.c = abc_getlocal($$.c, i);
2132 /* look at current class' members */
2133 } else if((f = registry_findmember(state->cls->info, $1))) {
2134 // $1 is a function in this class
2135 int var_is_static = (f->flags&FLAG_STATIC);
2136 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2137 if(var_is_static != i_am_static) {
2138 /* there doesn't seem to be any "static" way to access
2139 static properties of a class */
2140 state->method->late_binding = 1;
2142 namespace_t ns = {flags2access(f->flags), ""};
2143 multiname_t m = {QNAME, &ns, 0, $1};
2144 $$.c = abc_findpropstrict2($$.c, &m);
2145 $$.c = abc_getproperty2($$.c, &m);
2148 $$.c = abc_getlocal_0($$.c);
2149 $$.c = abc_getslot($$.c, f->slot);
2151 namespace_t ns = {flags2access(f->flags), ""};
2152 multiname_t m = {QNAME, &ns, 0, $1};
2153 $$.c = abc_getlocal_0($$.c);
2154 $$.c = abc_getproperty2($$.c, &m);
2157 if(f->kind == MEMBER_METHOD) {
2158 $$.t = TYPE_FUNCTION(f);
2163 /* look at classes in the current package and imported classes */
2164 } else if((a = find_class($1))) {
2166 $$.c = abc_getglobalscope($$.c);
2167 $$.c = abc_getslot($$.c, a->slot);
2170 $$.c = abc_getlex2($$.c, &m);
2172 $$.t = TYPE_CLASS(a);
2174 /* unknown object, let the avm2 resolve it */
2176 if(strcmp($1,"trace"))
2177 warning("Couldn't resolve '%s', doing late binding", $1);
2178 state->method->late_binding = 1;
2180 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2183 $$.c = abc_findpropstrict2($$.c, &m);
2184 $$.c = abc_getproperty2($$.c, &m);
2189 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2190 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2191 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2193 // ----------------- namespaces -------------------------------------------------
2195 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2196 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2197 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2199 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER