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 {
258 /* code that needs to be executed at the start of
259 a method (like initializing local registers) */
265 typedef struct _state {
269 import_list_t*wildcard_imports;
271 char has_own_imports;
274 methodstate_t*method;
279 typedef struct _global {
286 static global_t*global = 0;
287 static state_t* state = 0;
291 #define MULTINAME(m,x) \
294 registry_fill_multiname(&m, &m##_ns, x);
296 #define MEMBER_MULTINAME(m,f) \
300 m##_ns.access = flags2access(f->flags); \
304 m.namespace_set = 0; \
307 m.type = MULTINAME; \
309 m.namespace_set = &nopackage_namespace_set; \
313 /* warning: list length of namespace set is undefined */
314 #define MULTINAME_LATE(m, access, package) \
315 namespace_t m##_ns = {access, package}; \
316 namespace_set_t m##_nsset; \
317 namespace_list_t m##_l;m##_l.next = 0; \
318 m##_nsset.namespaces = &m##_l; \
319 m##_nsset = m##_nsset; \
320 m##_l.namespace = &m##_ns; \
321 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
323 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
324 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
325 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
326 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
327 static namespace_list_t nl4 = {&ns4,0};
328 static namespace_list_t nl3 = {&ns3,&nl4};
329 static namespace_list_t nl2 = {&ns2,&nl3};
330 static namespace_list_t nl1 = {&ns1,&nl2};
331 static namespace_set_t nopackage_namespace_set = {&nl1};
333 static state_list_t*state_stack=0;
335 static void init_globals()
337 global = rfx_calloc(sizeof(global_t));
340 static void new_state()
343 NEW(state_list_t, sl);
345 state_t*oldstate = state;
347 memcpy(s, state, sizeof(state_t)); //shallow copy
348 sl->next = state_stack;
351 s->imports = dict_new();
356 state->has_own_imports = 0;
357 state->vars = dict_new();
359 static void state_has_imports()
361 state->wildcard_imports = list_clone(state->wildcard_imports);
362 state->imports = dict_clone(state->imports);
363 state->has_own_imports = 1;
366 static void old_state()
368 if(!state_stack || !state_stack->next)
369 syntaxerror("invalid nesting");
370 state_t*oldstate = state;
371 state_list_t*old = state_stack;
372 state_stack = state_stack->next;
374 state = state_stack->state;
375 /*if(state->method->initcode) {
376 printf("residual initcode\n");
377 code_dump(state->method->initcode, 0, 0, "", stdout);
379 if(oldstate->has_own_imports) {
380 list_free(oldstate->wildcard_imports);
381 dict_destroy(oldstate->imports);oldstate->imports=0;
384 void initialize_state()
389 global->file = abc_file_new();
390 global->file->flags &= ~ABCFILE_LAZY;
392 global->init = abc_initscript(global->file, 0);
393 code_t*c = global->init->method->body->code;
395 c = abc_getlocal_0(c);
396 c = abc_pushscope(c);
398 /* findpropstrict doesn't just return a scope object- it
399 also makes it "active" somehow. Push local_0 on the
400 scope stack and read it back with findpropstrict, it'll
401 contain properties like "trace". Trying to find the same
402 property on a "vanilla" local_0 yields only a "undefined" */
403 //c = abc_findpropstrict(c, "[package]::trace");
405 /*c = abc_getlocal_0(c);
406 c = abc_findpropstrict(c, "[package]::trace");
408 c = abc_setlocal_1(c);
410 c = abc_pushbyte(c, 0);
411 c = abc_setlocal_2(c);
413 code_t*xx = c = abc_label(c);
414 c = abc_findpropstrict(c, "[package]::trace");
415 c = abc_pushstring(c, "prop:");
416 c = abc_hasnext2(c, 1, 2);
418 c = abc_setlocal_3(c);
419 c = abc_callpropvoid(c, "[package]::trace", 2);
420 c = abc_getlocal_3(c);
422 c = abc_iftrue(c,xx);*/
424 c = abc_findpropstrict(c, "[package]::trace");
425 c = abc_pushstring(c, "[entering global init function]");
426 c = abc_callpropvoid(c, "[package]::trace", 1);
428 global->init->method->body->code = c;
430 void* finalize_state()
432 if(state->level!=1) {
433 syntaxerror("unexpected end of file");
435 abc_method_body_t*m = global->init->method->body;
438 __ findpropstrict(m, "[package]::trace");
439 __ pushstring(m, "[leaving global init function]");
440 __ callpropvoid(m, "[package]::trace", 1);
446 static void startpackage(char*name)
449 syntaxerror("Packages can not be nested.");
452 /*printf("entering package \"%s\"\n", name);*/
453 state->package = name;
455 static void endpackage()
457 /*printf("leaving package \"%s\"\n", state->package);*/
462 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
465 syntaxerror("inner classes now allowed");
468 state->cls = rfx_calloc(sizeof(classstate_t));
471 classinfo_list_t*mlist=0;
472 /*printf("entering class %s\n", name);
473 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
475 printf(" extends: %s.%s\n", extends->package, extends->name);
476 printf(" implements (%d): ", list_length(implements));
477 for(mlist=implements;mlist;mlist=mlist->next) {
478 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
483 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
484 syntaxerror("invalid modifier(s)");
486 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
487 syntaxerror("public and internal not supported at the same time.");
489 /* create the class name, together with the proper attributes */
493 if(!(flags&FLAG_PUBLIC) && !state->package) {
494 access = ACCESS_PRIVATE; package = current_filename;
495 } else if(!(flags&FLAG_PUBLIC) && state->package) {
496 access = ACCESS_PACKAGEINTERNAL; package = state->package;
497 } else if(state->package) {
498 access = ACCESS_PACKAGE; package = state->package;
500 syntaxerror("public classes only allowed inside a package");
503 if(registry_findclass(package, classname)) {
504 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
508 /* build info struct */
509 int num_interfaces = (list_length(implements));
510 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
511 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
513 classinfo_list_t*l = implements;
514 for(l=implements;l;l=l->next) {
515 state->cls->info->interfaces[pos++] = l->classinfo;
518 multiname_t*extends2 = sig2mname(extends);
520 MULTINAME(classname2,state->cls->info);
523 state->cls_init = abc_getlocal_0(state->cls_init);
524 state->cls_init = abc_constructsuper(state->cls_init, 0);
527 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
528 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
529 if(flags&FLAG_DYNAMIC) abc_class_sealed(state->cls->abc);
530 if(interface) abc_class_interface(state->cls->abc);
532 for(mlist=implements;mlist;mlist=mlist->next) {
533 MULTINAME(m, mlist->classinfo);
534 abc_class_add_interface(state->cls->abc, &m);
537 /* now write the construction code for this class */
538 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
540 abc_method_body_t*m = global->init->method->body;
541 __ getglobalscope(m);
542 classinfo_t*s = extends;
547 //TODO: take a look at the current scope stack, maybe
548 // we can re-use something
553 multiname_t*s2 = sig2mname(s);
555 multiname_destroy(s2);
557 __ pushscope(m); count++;
558 m->code = m->code->prev->prev; // invert
560 /* continue appending after last op end */
561 while(m->code && m->code->next) m->code = m->code->next;
563 /* TODO: if this is one of *our* classes, we can also
564 do a getglobalscope/getslot <nr> (which references
565 the init function's slots) */
567 __ getlex2(m, extends2);
569 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
570 stack is not the superclass */
571 __ pushscope(m);count++;
574 /* notice: we get a verify error #1107 if the top element on the scope
575 stack is not the global object */
577 __ pushscope(m);count++;
579 __ newclass(m,state->cls->abc);
583 __ setslot(m, slotindex);
585 /* flash.display.MovieClip handling */
586 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
587 if(state->package && state->package[0]) {
588 globalclass = concat3str(state->package, ".", classname);
590 globalclass = strdup(classname);
593 multiname_destroy(extends2);
596 static void endclass()
598 if(state->cls->init) {
599 if(!state->cls->abc->constructor) {
600 abc_method_t*m = abc_class_constructor(state->cls->abc, 0);
601 m->body->code = code_append(m->body->code, state->cls->init);
602 m->body->code = abc_returnvoid(m->body->code);
604 code_t*c = state->cls->abc->constructor->body->code;
605 c = code_append(state->cls->init, c);
606 state->cls->abc->constructor->body->code = c;
610 if(state->cls->static_init) {
611 if(!state->cls->abc->static_constructor) {
612 abc_method_t*m = abc_class_staticconstructor(state->cls->abc, 0);
613 m->body->code = code_append(m->body->code, state->cls->static_init);
614 m->body->code = abc_returnvoid(m->body->code);
616 state->cls->abc->static_constructor->body->code =
617 code_append(state->cls->static_init, state->cls->abc->static_constructor->body->code);
624 typedef struct _variable {
629 static int find_variable(char*name, classinfo_t**m)
631 state_list_t* s = state_stack;
635 v = dict_lookup(s->state->vars, name);
646 static int find_variable_safe(char*name, classinfo_t**m)
648 int i = find_variable(name, m);
650 syntaxerror("undefined variable: %s", name);
653 static char variable_exists(char*name)
655 return dict_lookup(state->vars, name)!=0;
657 static int new_variable(char*name, classinfo_t*type)
660 v->index = global->variable_count;
662 dict_put(state->vars, name, v);
663 return global->variable_count++;
665 #define TEMPVARNAME "__as3_temp__"
666 static int gettempvar()
668 int i = find_variable(TEMPVARNAME, 0);
670 i = new_variable(TEMPVARNAME, 0);
675 code_t* killvars(code_t*c)
678 for(t=0;t<state->vars->hashsize;t++) {
679 dictentry_t*e =state->vars->slots[t];
681 variable_t*v = (variable_t*)e->data;
682 //do this always, otherwise register types don't match
683 //in the verifier when doing nested loops
684 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
685 c = abc_kill(c, v->index);
693 static void check_constant_against_type(classinfo_t*t, constant_t*c)
695 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
696 if(TYPE_IS_NUMBER(t)) {
697 xassert(c->type == CONSTANT_FLOAT
698 || c->type == CONSTANT_INT
699 || c->type == CONSTANT_UINT);
700 } else if(TYPE_IS_UINT(t)) {
701 xassert(c->type == CONSTANT_UINT ||
702 (c->type == CONSTANT_INT && c->i>0));
703 } else if(TYPE_IS_INT(t)) {
704 xassert(c->type == CONSTANT_INT);
705 } else if(TYPE_IS_BOOLEAN(t)) {
706 xassert(c->type == CONSTANT_TRUE
707 || c->type == CONSTANT_FALSE);
711 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
713 memberinfo_t*minfo = 0;
714 if(getset != KW_GET && getset != KW_SET) {
715 if(registry_findmember(state->cls->info, name)) {
716 syntaxerror("class already contains a member/method called '%s'", name);
718 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
719 minfo->return_type = return_type;
720 // getslot on a member slot only returns "undefined", so no need
721 // to actually store these
722 //state->minfo->slot = state->method->abc->method->trait->slot_id;
724 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
728 else if(params->list)
729 type = params->list->param->type;
730 if((minfo=registry_findmember(state->cls->info, name))) {
731 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
732 syntaxerror("class already contains a member or method called '%s'", name);
734 syntaxerror("getter/setter for '%s' already defined", name);
735 /* make a setter or getter into a getset */
740 if(type && minfo->type != type)
741 syntaxerror("different type in getter and setter");
743 minfo = memberinfo_register(state->cls->info, name, gs);
746 /* can't assign a slot as getter and setter might have different slots */
747 //minfo->slot = slot;
749 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
750 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
751 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
752 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
753 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
757 static int flags2access(int flags)
760 if(flags&FLAG_PUBLIC) {
761 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
762 access = ACCESS_PACKAGE;
763 } else if(flags&FLAG_PRIVATE) {
764 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
765 access = ACCESS_PRIVATE;
766 } else if(flags&FLAG_PROTECTED) {
767 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
768 access = ACCESS_PROTECTED;
770 access = ACCESS_PACKAGEINTERNAL;
775 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
776 params_t*params, classinfo_t*return_type)
779 syntaxerror("not able to start another method scope");
782 state->method = rfx_calloc(sizeof(methodstate_t));
783 state->method->initcode = 0;
784 state->method->is_constructor = !strcmp(state->cls->info->name,name);
785 state->method->has_super = 0;
787 global->variable_count = 0;
789 /* state->vars is initialized by state_new */
790 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
792 for(p=params->list;p;p=p->next) {
793 new_variable(p->param->name, p->param->type);
795 if(state->method->is_constructor)
796 name = "__as3_constructor__";
797 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
800 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
801 params_t*params, classinfo_t*return_type, code_t*body)
803 namespace_t mname_ns = {flags2access(flags), ""};
804 multiname_t mname = {QNAME, &mname_ns, 0, name};
808 multiname_t*type2 = sig2mname(return_type);
810 if(state->method->is_constructor) {
811 f = abc_class_constructor(state->cls->abc, type2);
813 if(flags&FLAG_STATIC)
814 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
816 f = abc_class_method(state->cls->abc, type2, &mname);
817 slot = f->trait->slot_id;
819 //flash doesn't seem to allow us to access function slots
820 //state->method->info->slot = slot;
822 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
823 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
824 if(params->varargs) f->flags |= METHOD_NEED_REST;
828 for(p=params->list;p;p=p->next) {
829 if(params->varargs && !p->next) {
830 break; //varargs: omit last parameter in function signature
832 multiname_t*m = sig2mname(p->param->type);
833 list_append(f->parameters, m);
834 if(p->param->value) {
835 check_constant_against_type(p->param->type, p->param->value);
836 opt=1;list_append(f->optional_parameters, p->param->value);
838 syntaxerror("non-optional parameter not allowed after optional parameters");
841 f->body->code = body;
848 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
853 void breakjumpsto(code_t*c, code_t*jump)
858 if(c->opcode == OPCODE___BREAK__) {
859 c->opcode = OPCODE_JUMP;
866 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
869 return registry_getanytype();
870 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
871 return registry_getanytype();
874 return registry_getanytype();
876 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
881 return abc_coerce_a(c);
885 // cast an "any" type to a specific type. subject to
886 // runtime exceptions
887 return abc_coerce2(c, &m);
890 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
891 return abc_coerce2(c, &m);
893 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
894 return abc_coerce2(c, &m);
896 /* these are subject to overflow */
897 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
898 return abc_coerce2(c, &m);
900 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
901 return abc_coerce2(c, &m);
904 classinfo_t*supertype = from;
906 if(supertype == to) {
907 // target type is one of from's superclasses
908 return abc_coerce2(c, &m);
911 while(supertype->interfaces[t]) {
912 if(supertype->interfaces[t]==to) {
913 // to type is one of from's interfaces
914 return abc_coerce2(c, &m);
918 supertype = supertype->superclass;
920 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
922 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
924 syntaxerror("can't convert type %s to %s", from->name, to->name);
927 code_t*defaultvalue(code_t*c, classinfo_t*type)
929 if(TYPE_IS_INT(type)) {
930 c = abc_pushbyte(c, 0);
931 } else if(TYPE_IS_UINT(type)) {
932 c = abc_pushuint(c, 0);
933 } else if(TYPE_IS_FLOAT(type)) {
935 } else if(TYPE_IS_BOOLEAN(type)) {
936 c = abc_pushfalse(c);
943 char is_pushundefined(code_t*c)
945 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
948 void parserassert(int b)
950 if(!b) syntaxerror("internal error: assertion failed");
953 static classinfo_t* find_class(char*name)
957 c = registry_findclass(state->package, name);
959 /* try explicit imports */
960 dictentry_t* e = dict_get_slot(state->imports, name);
964 if(!strcmp(e->key, name)) {
965 c = (classinfo_t*)e->data;
970 /* try package.* imports */
971 import_list_t*l = state->wildcard_imports;
975 //printf("does package %s contain a class %s?\n", l->import->package, name);
976 c = registry_findclass(l->import->package, name);
980 /* try global package */
982 c = registry_findclass("", name);
987 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
991 [prefix code] [read instruction]
995 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
998 if(in && in->opcode == OPCODE_COERCE_A) {
999 in = code_cutlast(in);
1002 syntaxerror("internal error");
1004 /* chop off read instruction */
1008 prefix = r->prev;r->prev = 0;
1014 char use_temp_var = readbefore;
1016 /* generate the write instruction, and maybe append a dup to the prefix code */
1017 code_t* write = abc_nop(0);
1018 if(r->opcode == OPCODE_GETPROPERTY) {
1019 write->opcode = OPCODE_SETPROPERTY;
1020 multiname_t*m = (multiname_t*)r->data[0];
1021 write->data[0] = multiname_clone(m);
1022 if(m->type == QNAME || m->type == MULTINAME) {
1024 prefix = abc_dup(prefix); // we need the object, too
1027 } else if(m->type == MULTINAMEL) {
1029 /* dupping two values on the stack requires 5 operations and one register-
1030 couldn't adobe just have given us a dup2? */
1031 int temp = gettempvar();
1032 prefix = abc_setlocal(prefix, temp);
1033 prefix = abc_dup(prefix);
1034 prefix = abc_getlocal(prefix, temp);
1035 prefix = abc_swap(prefix);
1036 prefix = abc_getlocal(prefix, temp);
1040 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1042 } else if(r->opcode == OPCODE_GETSLOT) {
1043 write->opcode = OPCODE_SETSLOT;
1044 write->data[0] = r->data[0];
1046 prefix = abc_dup(prefix); // we need the object, too
1049 } else if(r->opcode == OPCODE_GETLOCAL) {
1050 write->opcode = OPCODE_SETLOCAL;
1051 write->data[0] = r->data[0];
1052 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1053 write->opcode = OPCODE_SETLOCAL_0;
1054 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1055 write->opcode = OPCODE_SETLOCAL_1;
1056 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1057 write->opcode = OPCODE_SETLOCAL_2;
1058 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1059 write->opcode = OPCODE_SETLOCAL_3;
1061 code_dump(r, 0, 0, "", stdout);
1062 syntaxerror("illegal lvalue: can't assign a value to this expression");
1069 /* with getproperty/getslot, we have to be extra careful not
1070 to execute the read code twice, as it might have side-effects
1071 (e.g. if the property is in fact a setter/getter combination)
1073 So read the value, modify it, and write it again,
1074 using prefix only once and making sure (by using a temporary
1075 register) that the return value is what we just wrote */
1076 temp = gettempvar();
1077 c = code_append(c, prefix);
1078 c = code_append(c, r);
1081 c = abc_setlocal(c, temp);
1083 c = code_append(c, middlepart);
1086 c = abc_setlocal(c, temp);
1088 c = code_append(c, write);
1089 c = abc_getlocal(c, temp);
1090 c = abc_kill(c, temp);
1092 /* if we're allowed to execute the read code twice *and*
1093 the middlepart doesn't modify the code, things are easier.
1095 code_t* r2 = code_dup(r);
1096 //c = code_append(c, prefix);
1097 parserassert(!prefix);
1098 c = code_append(c, r);
1099 c = code_append(c, middlepart);
1100 c = code_append(c, write);
1101 c = code_append(c, r2);
1104 /* even smaller version: overwrite the value without reading
1108 c = code_append(c, prefix);
1111 c = code_append(c, middlepart);
1112 c = code_append(c, write);
1113 c = code_append(c, r);
1115 temp = gettempvar();
1117 c = code_append(c, prefix);
1120 c = code_append(c, middlepart);
1122 c = abc_setlocal(c, temp);
1123 c = code_append(c, write);
1124 c = abc_getlocal(c, temp);
1131 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1132 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1139 /* ------------ code blocks / statements ---------------- */
1143 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1144 MAYBECODE: {$$=code_new();}
1146 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1147 CODE: CODEPIECE {$$=$1;}
1149 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1150 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1151 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1152 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1153 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1154 CODEPIECE: ';' {$$=code_new();}
1155 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1156 CODEPIECE: VOIDEXPRESSION {$$=$1}
1157 CODEPIECE: FOR {$$=$1}
1158 CODEPIECE: WHILE {$$=$1}
1159 CODEPIECE: BREAK {$$=$1}
1160 CODEPIECE: RETURN {$$=$1}
1161 CODEPIECE: IF {$$=$1}
1162 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1163 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1165 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1166 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1167 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1169 /* ------------ variables --------------------------- */
1171 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1172 | {$$.c=abc_pushundefined(0);
1176 VAR : "const" | "var"
1177 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1179 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1180 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1182 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1184 if(variable_exists($2))
1185 syntaxerror("Variable %s already defined", $2);
1187 if(!is_subtype_of($4.t, $3)) {
1188 syntaxerror("Can't convert %s to %s", $4.t->name,
1192 int index = new_variable($2, $3);
1195 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1197 $$ = converttype($$, $4.t, $3);
1198 $$ = abc_setlocal($$, index);
1200 $$ = defaultvalue(0, $3);
1201 $$ = abc_setlocal($$, index);
1204 /* if this is a typed variable:
1205 push default value for type on stack */
1207 state->method->initcode = defaultvalue(state->method->initcode, $3);
1208 state->method->initcode = abc_setlocal(state->method->initcode, index);
1211 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1213 $$ = abc_coerce_a($$);
1214 $$ = abc_setlocal($$, index);
1220 /* that's the default for a local register, anyway
1222 state->method->initcode = abc_pushundefined(state->method->initcode);
1223 state->method->initcode = abc_setlocal(state->method->initcode, index);
1225 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1228 /* ------------ control flow ------------------------- */
1230 MAYBEELSE: %prec below_else {$$ = code_new();}
1231 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1232 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1234 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1236 $$ = code_append($$, $4.c);
1237 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1239 $$ = code_append($$, $6);
1241 myjmp = $$ = abc_jump($$, 0);
1243 myif->branch = $$ = abc_label($$);
1245 $$ = code_append($$, $7);
1246 myjmp->branch = $$ = abc_label($$);
1249 $$ = killvars($$);old_state();
1252 FOR_INIT : {$$=code_new();}
1253 FOR_INIT : VARIABLE_DECLARATION
1254 FOR_INIT : VOIDEXPRESSION
1256 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1258 $$ = code_append($$, $4);
1259 code_t*loopstart = $$ = abc_label($$);
1260 $$ = code_append($$, $6.c);
1261 code_t*myif = $$ = abc_iffalse($$, 0);
1262 $$ = code_append($$, $10);
1263 $$ = code_append($$, $8);
1264 $$ = abc_jump($$, loopstart);
1265 code_t*out = $$ = abc_label($$);
1266 breakjumpsto($$, out);
1269 $$ = killvars($$);old_state();
1272 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
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++;
1662 this is dependent on the control path, check this somewhere else
1663 if(state->method->has_super)
1664 syntaxerror("constructor may call super() only once");
1666 state->method->has_super = 1;
1667 $$.c = abc_constructsuper($$.c, len);
1668 $$.c = abc_pushundefined($$.c);
1672 DELETE: "delete" E {
1674 if($$.c->opcode == OPCODE_COERCE_A) {
1675 $$.c = code_cutlast($$.c);
1677 multiname_t*name = 0;
1678 if($$.c->opcode == OPCODE_GETPROPERTY) {
1679 $$.c->opcode = OPCODE_DELETEPROPERTY;
1680 } else if($$.c->opcode == OPCODE_GETSLOT) {
1681 int slot = (int)(ptroff_t)$$.c->data[0];
1682 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1683 $$.c = code_cutlast($$.c);
1684 $$.c = abc_deleteproperty2($$.c, name);
1686 $$.c = abc_getlocal_0($$.c);
1687 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1688 $$.c = abc_deleteproperty2($$.c, &m);
1690 $$.t = TYPE_BOOLEAN;
1693 RETURN: "return" %prec prec_none {
1694 $$ = abc_returnvoid(0);
1696 RETURN: "return" EXPRESSION {
1698 $$ = abc_returnvalue($$);
1701 // ----------------------- expression types -------------------------------------
1703 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1704 EXPRESSION : E %prec below_minus {$$ = $1;}
1705 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1707 $$.c = cut_last_push($$.c);
1708 $$.c = code_append($$.c,$3.c);
1711 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1712 $$=cut_last_push($1.c);
1715 // ----------------------- expression evaluation -------------------------------------
1718 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1720 E : DELETE {$$ = $1;}
1721 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1725 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1726 //MULTINAME(m, registry_getintclass());
1727 //$$.c = abc_coerce2($$.c, &m); // FIXME
1730 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1733 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1736 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1739 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1742 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1745 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1748 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1749 $$.t = TYPE_BOOLEAN;
1751 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1752 $$.t = TYPE_BOOLEAN;
1754 CONSTANT : "null" {$$.c = abc_pushnull(0);
1759 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1760 $$.t = TYPE_BOOLEAN;
1762 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1763 $$.t = TYPE_BOOLEAN;
1765 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1766 $$.t = TYPE_BOOLEAN;
1768 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1769 $$.t = TYPE_BOOLEAN;
1771 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1772 $$.t = TYPE_BOOLEAN;
1774 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1775 $$.t = TYPE_BOOLEAN;
1777 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1778 $$.t = TYPE_BOOLEAN;
1780 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1781 $$.t = TYPE_BOOLEAN;
1784 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1786 $$.c = converttype($$.c, $1.t, $$.t);
1787 $$.c = abc_dup($$.c);
1788 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1789 $$.c = cut_last_push($$.c);
1790 $$.c = code_append($$.c,$3.c);
1791 $$.c = converttype($$.c, $3.t, $$.t);
1792 code_t*label = $$.c = abc_label($$.c);
1793 jmp->branch = label;
1796 $$.t = join_types($1.t, $3.t, 'A');
1797 /*printf("%08x:\n",$1.t);
1798 code_dump($1.c, 0, 0, "", stdout);
1799 printf("%08x:\n",$3.t);
1800 code_dump($3.c, 0, 0, "", stdout);
1801 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1803 $$.c = converttype($$.c, $1.t, $$.t);
1804 $$.c = abc_dup($$.c);
1805 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1806 $$.c = cut_last_push($$.c);
1807 $$.c = code_append($$.c,$3.c);
1808 $$.c = converttype($$.c, $3.t, $$.t);
1809 code_t*label = $$.c = abc_label($$.c);
1810 jmp->branch = label;
1813 E : '!' E {$$.c=$2.c;
1814 $$.c = abc_not($$.c);
1815 $$.t = TYPE_BOOLEAN;
1818 E : '~' E {$$.c=$2.c;
1819 $$.c = abc_bitnot($$.c);
1823 E : E '&' E {$$.c = code_append($1.c,$3.c);
1824 $$.c = abc_bitand($$.c);
1828 E : E '^' E {$$.c = code_append($1.c,$3.c);
1829 $$.c = abc_bitxor($$.c);
1833 E : E '|' E {$$.c = code_append($1.c,$3.c);
1834 $$.c = abc_bitor($$.c);
1838 E : E '-' E {$$.c = code_append($1.c,$3.c);
1839 if(BOTH_INT($1,$3)) {
1840 $$.c = abc_subtract_i($$.c);
1843 $$.c = abc_subtract($$.c);
1847 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1848 $$.c = abc_rshift($$.c);
1851 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1852 $$.c = abc_urshift($$.c);
1855 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1856 $$.c = abc_lshift($$.c);
1860 E : E '/' E {$$.c = code_append($1.c,$3.c);
1861 $$.c = abc_divide($$.c);
1864 E : E '+' E {$$.c = code_append($1.c,$3.c);
1865 $$.c = abc_add($$.c);
1868 E : E '%' E {$$.c = code_append($1.c,$3.c);
1869 $$.c = abc_modulo($$.c);
1872 E : E '*' E {$$.c = code_append($1.c,$3.c);
1873 if(BOTH_INT($1,$3)) {
1874 $$.c = abc_multiply_i($$.c);
1877 $$.c = abc_multiply($$.c);
1882 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1883 if(use_astype && TYPE_IS_CLASS($3.t)) {
1884 MULTINAME(m,$3.t->cls);
1885 $$.c = abc_astype2($1.c, &m);
1888 $$.c = code_append($1.c, $3.c);
1889 $$.c = abc_astypelate($$.c);
1894 E : E "is" E {$$.c = code_append($1.c, $3.c);
1895 $$.c = abc_istypelate($$.c);
1896 $$.t = TYPE_BOOLEAN;
1899 E : "typeof" '(' E ')' {
1901 $$.c = abc_typeof($$.c);
1906 $$.c = cut_last_push($2.c);
1907 $$.c = abc_pushundefined($$.c);
1911 E : "void" { $$.c = abc_pushundefined(0);
1915 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
1920 $$.c=abc_negate_i($$.c);
1923 $$.c=abc_negate($$.c);
1930 $$.c = code_append($$.c, $3.c);
1932 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1933 $$.c = abc_getproperty2($$.c, &m);
1934 $$.t = 0; // array elements have unknown type
1939 if(BOTH_INT($1,$3)) {
1940 c=abc_multiply_i(c);
1944 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1945 $$.c = toreadwrite($1.c, c, 0, 0);
1950 code_t*c = abc_modulo($3.c);
1951 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1952 $$.c = toreadwrite($1.c, c, 0, 0);
1956 code_t*c = abc_lshift($3.c);
1957 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1958 $$.c = toreadwrite($1.c, c, 0, 0);
1962 code_t*c = abc_rshift($3.c);
1963 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1964 $$.c = toreadwrite($1.c, c, 0, 0);
1968 code_t*c = abc_urshift($3.c);
1969 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1970 $$.c = toreadwrite($1.c, c, 0, 0);
1974 code_t*c = abc_divide($3.c);
1975 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1976 $$.c = toreadwrite($1.c, c, 0, 0);
1981 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1986 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1988 $$.c = toreadwrite($1.c, c, 0, 0);
1991 E : E "-=" E { code_t*c = $3.c;
1992 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1993 c=abc_subtract_i(c);
1997 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1999 $$.c = toreadwrite($1.c, c, 0, 0);
2002 E : E '=' E { code_t*c = 0;
2003 c = code_append(c, $3.c);
2004 c = converttype(c, $3.t, $1.t);
2005 $$.c = toreadwrite($1.c, c, 1, 0);
2009 E : E '?' E ':' E %prec below_assignment {
2011 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2012 $$.c = code_append($$.c, $3.c);
2013 code_t*j2 = $$.c = abc_jump($$.c, 0);
2014 $$.c = j1->branch = abc_label($$.c);
2015 $$.c = code_append($$.c, $5.c);
2016 $$.c = j2->branch = abc_label($$.c);
2017 $$.t = join_types($3.t,$5.t,'?');
2020 // TODO: use inclocal where appropriate
2021 E : E "++" { code_t*c = 0;
2022 classinfo_t*type = $1.t;
2023 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2024 c=abc_increment_i(c);
2030 c=converttype(c, type, $1.t);
2031 $$.c = toreadwrite($1.c, c, 0, 1);
2034 E : E "--" { code_t*c = 0;
2035 classinfo_t*type = $1.t;
2036 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2037 c=abc_decrement_i(c);
2043 c=converttype(c, type, $1.t);
2044 $$.c = toreadwrite($1.c, c, 0, 1);
2048 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2049 classinfo_t*type = $2.t;
2050 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2051 c=abc_increment_i(c);
2057 c=converttype(c, type, $2.t);
2058 $$.c = toreadwrite($2.c, c, 0, 0);
2062 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2063 classinfo_t*type = $2.t;
2064 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2065 c=abc_decrement_i(c);
2071 c=converttype(c, type, $2.t);
2072 $$.c = toreadwrite($2.c, c, 0, 0);
2076 E : "super" '.' T_IDENTIFIER
2077 { if(!state->cls->info)
2078 syntaxerror("super keyword not allowed outside a class");
2079 classinfo_t*t = state->cls->info->superclass;
2080 if(!t) t = TYPE_OBJECT;
2082 memberinfo_t*f = registry_findmember(t, $3);
2083 namespace_t ns = {flags2access(f->flags), ""};
2084 MEMBER_MULTINAME(m, f);
2086 $$.c = abc_getlocal_0($$.c);
2087 $$.c = abc_getsuper2($$.c, &m);
2088 $$.t = memberinfo_gettype(f);
2091 E : E '.' T_IDENTIFIER
2093 classinfo_t*t = $1.t;
2095 if(TYPE_IS_CLASS(t) && t->cls) {
2100 memberinfo_t*f = registry_findmember(t, $3);
2102 if(f && !is_static != !(f->flags&FLAG_STATIC))
2104 if(f && f->slot && !noslot) {
2105 $$.c = abc_getslot($$.c, f->slot);
2107 MEMBER_MULTINAME(m, f);
2108 $$.c = abc_getproperty2($$.c, &m);
2110 /* determine type */
2111 $$.t = memberinfo_gettype(f);
2113 $$.c = abc_coerce_a($$.c);
2115 /* when resolving a property on an unknown type, we do know the
2116 name of the property (and don't seem to need the package), but
2117 we need to make avm2 try out all access modes */
2118 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2119 $$.c = abc_getproperty2($$.c, &m);
2120 $$.c = abc_coerce_a($$.c);
2121 $$.t = registry_getanytype();
2125 VAR_READ : T_IDENTIFIER {
2132 /* look at variables */
2133 if((i = find_variable($1, &$$.t)) >= 0) {
2134 // $1 is a local variable
2135 $$.c = abc_getlocal($$.c, i);
2137 /* look at current class' members */
2138 } else if((f = registry_findmember(state->cls->info, $1))) {
2139 // $1 is a function in this class
2140 int var_is_static = (f->flags&FLAG_STATIC);
2141 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2142 if(var_is_static != i_am_static) {
2143 /* there doesn't seem to be any "static" way to access
2144 static properties of a class */
2145 state->method->late_binding = 1;
2147 namespace_t ns = {flags2access(f->flags), ""};
2148 multiname_t m = {QNAME, &ns, 0, $1};
2149 $$.c = abc_findpropstrict2($$.c, &m);
2150 $$.c = abc_getproperty2($$.c, &m);
2153 $$.c = abc_getlocal_0($$.c);
2154 $$.c = abc_getslot($$.c, f->slot);
2156 namespace_t ns = {flags2access(f->flags), ""};
2157 multiname_t m = {QNAME, &ns, 0, $1};
2158 $$.c = abc_getlocal_0($$.c);
2159 $$.c = abc_getproperty2($$.c, &m);
2162 if(f->kind == MEMBER_METHOD) {
2163 $$.t = TYPE_FUNCTION(f);
2168 /* look at classes in the current package and imported classes */
2169 } else if((a = find_class($1))) {
2171 $$.c = abc_getglobalscope($$.c);
2172 $$.c = abc_getslot($$.c, a->slot);
2175 $$.c = abc_getlex2($$.c, &m);
2177 $$.t = TYPE_CLASS(a);
2179 /* unknown object, let the avm2 resolve it */
2181 if(strcmp($1,"trace"))
2182 warning("Couldn't resolve '%s', doing late binding", $1);
2183 state->method->late_binding = 1;
2185 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2188 $$.c = abc_findpropstrict2($$.c, &m);
2189 $$.c = abc_getproperty2($$.c, &m);
2194 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2195 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2196 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2198 // ----------------- namespaces -------------------------------------------------
2200 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2201 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2202 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2204 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER