3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
30 #include "tokenizer.h"
42 enum yytokentype token;
45 classinfo_t*classinfo;
46 classinfo_list_t*classinfo_list;
49 unsigned int number_uint;
53 typedcode_list_t*value_list;
62 %token<id> T_IDENTIFIER
64 %token<token> T_REGEXP
66 %token<number_int> T_INT
67 %token<number_uint> T_UINT
68 %token<number_uint> T_BYTE
69 %token<number_uint> T_SHORT
70 %token<number_float> T_FLOAT
72 %token<token> KW_IMPLEMENTS
73 %token<token> KW_NAMESPACE "namespace"
74 %token<token> KW_PACKAGE "package"
75 %token<token> KW_PROTECTED
76 %token<token> KW_PUBLIC
77 %token<token> KW_PRIVATE
78 %token<token> KW_USE "use"
79 %token<token> KW_INTERNAL
80 %token<token> KW_NEW "new"
81 %token<token> KW_NATIVE
82 %token<token> KW_FUNCTION "function"
83 %token<token> KW_UNDEFINED "undefined"
84 %token<token> KW_FOR "for"
85 %token<token> KW_CLASS "class"
86 %token<token> KW_CONST "const"
87 %token<token> KW_SET "set"
88 %token<token> KW_VOID "void"
89 %token<token> KW_STATIC
90 %token<token> KW_INSTANCEOF "instanceof"
91 %token<token> KW_IMPORT "import"
92 %token<token> KW_RETURN "return"
93 %token<token> KW_TYPEOF "typeof"
94 %token<token> KW_INTERFACE "interface"
95 %token<token> KW_NULL "null"
96 %token<token> KW_VAR "var"
97 %token<token> KW_DYNAMIC
98 %token<token> KW_OVERRIDE
99 %token<token> KW_FINAL
100 %token<token> KW_GET "get"
101 %token<token> KW_SUPER "super"
102 %token<token> KW_EXTENDS
103 %token<token> KW_FALSE "false"
104 %token<token> KW_TRUE "true"
105 %token<token> KW_BOOLEAN "Boolean"
106 %token<token> KW_UINT "uint"
107 %token<token> KW_INT "int"
108 %token<token> KW_WHILE "while"
109 %token<token> KW_NUMBER "Number"
110 %token<token> KW_STRING "String"
111 %token<token> KW_DELETE "delete"
112 %token<token> KW_IF "if"
113 %token<token> KW_ELSE "else"
114 %token<token> KW_BREAK "break"
115 %token<token> KW_IS "is"
116 %token<token> KW_AS "as"
118 %token<token> T_EQEQ "=="
119 %token<token> T_EQEQEQ "==="
120 %token<token> T_NE "!="
121 %token<token> T_NEE "!=="
122 %token<token> T_LE "<="
123 %token<token> T_GE ">="
124 %token<token> T_DIVBY "/="
125 %token<token> T_MODBY "%="
126 %token<token> T_MULBY "*="
127 %token<token> T_PLUSBY "+="
128 %token<token> T_MINUSBY "-="
129 %token<token> T_SHRBY ">>="
130 %token<token> T_SHLBY "<<="
131 %token<token> T_USHRBY ">>>="
132 %token<token> T_OROR "||"
133 %token<token> T_ANDAND "&&"
134 %token<token> T_COLONCOLON "::"
135 %token<token> T_MINUSMINUS "--"
136 %token<token> T_PLUSPLUS "++"
137 %token<token> T_DOTDOT ".."
138 %token<token> T_DOTDOTDOT "..."
139 %token<token> T_SHL "<<"
140 %token<token> T_USHR ">>>"
141 %token<token> T_SHR ">>"
143 %type <id> X_IDENTIFIER PACKAGE
144 %type <token> VARCONST
146 %type <code> CODEPIECE
147 %type <code> CODEBLOCK MAYBECODE
148 %type <token> PACKAGE_DECLARATION
149 %type <token> FUNCTION_DECLARATION
150 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
151 %type <token> CLASS_DECLARATION
152 %type <token> NAMESPACE_DECLARATION
153 %type <token> INTERFACE_DECLARATION
154 %type <code> VOIDEXPRESSION
155 %type <value> EXPRESSION NONCOMMAEXPRESSION
156 %type <value> MAYBEEXPRESSION
157 %type <value> E DELETE
158 %type <value> CONSTANT
159 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
160 %type <token> USE_NAMESPACE
161 %type <code> FOR_INIT
163 %type <classinfo> MAYBETYPE
166 %type <params> PARAM_LIST
167 %type <params> MAYBE_PARAM_LIST
168 %type <flags> MAYBE_MODIFIERS
169 %type <flags> MODIFIER_LIST
170 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
171 %type <classinfo_list> IMPLEMENTS_LIST
172 %type <classinfo> EXTENDS
173 %type <classinfo_list> EXTENDS_LIST
174 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
175 %type <classinfo_list> QNAME_LIST
176 %type <classinfo> TYPE
178 //%type <token> VARIABLE
179 %type <value> VAR_READ
181 //%type <token> T_IDENTIFIER
182 %type <token> MODIFIER
183 %type <value> FUNCTIONCALL
184 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
186 // precedence: from low to high
190 %left below_semicolon
193 %nonassoc below_assignment // for ?:, contrary to spec
194 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
201 %nonassoc "==" "!=" "===" "!=="
203 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
204 %left "<<" ">>" ">>>"
208 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
210 %left '[' ']' '{' "new" '.' ".." "::"
211 %nonassoc T_IDENTIFIER
216 // needed for "return" precedence:
217 %nonassoc T_STRING T_REGEXP
218 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
219 %nonassoc "false" "true" "null" "undefined" "super"
224 static int yyerror(char*s)
226 syntaxerror("%s", s);
228 static char* concat3str(const char* t1, const char* t2, const char* t3)
233 char*text = malloc(l1+l2+l3+1);
234 memcpy(text , t1, l1);
235 memcpy(text+l1, t2, l2);
236 memcpy(text+l1+l2, t3, l3);
241 typedef struct _import {
245 DECLARE_LIST(import);
247 typedef struct _classstate {
255 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;
280 typedef struct _global {
287 static global_t*global = 0;
288 static state_t* state = 0;
292 #define MULTINAME(m,x) \
295 registry_fill_multiname(&m, &m##_ns, x);
297 #define MEMBER_MULTINAME(m,f,n) \
301 m##_ns.access = flags2access(f->flags); \
305 m.namespace_set = 0; \
308 m.type = MULTINAME; \
310 m.namespace_set = &nopackage_namespace_set; \
314 /* warning: list length of namespace set is undefined */
315 #define MULTINAME_LATE(m, access, package) \
316 namespace_t m##_ns = {access, package}; \
317 namespace_set_t m##_nsset; \
318 namespace_list_t m##_l;m##_l.next = 0; \
319 m##_nsset.namespaces = &m##_l; \
320 m##_nsset = m##_nsset; \
321 m##_l.namespace = &m##_ns; \
322 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
324 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
325 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
326 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
327 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
328 static namespace_list_t nl4 = {&ns4,0};
329 static namespace_list_t nl3 = {&ns3,&nl4};
330 static namespace_list_t nl2 = {&ns2,&nl3};
331 static namespace_list_t nl1 = {&ns1,&nl2};
332 static namespace_set_t nopackage_namespace_set = {&nl1};
334 static state_list_t*state_stack=0;
336 static void init_globals()
338 global = rfx_calloc(sizeof(global_t));
341 static void new_state()
344 NEW(state_list_t, sl);
346 state_t*oldstate = state;
348 memcpy(s, state, sizeof(state_t)); //shallow copy
349 sl->next = state_stack;
352 s->imports = dict_new();
357 state->has_own_imports = 0;
358 state->vars = dict_new();
360 static void state_has_imports()
362 state->wildcard_imports = list_clone(state->wildcard_imports);
363 state->imports = dict_clone(state->imports);
364 state->has_own_imports = 1;
367 static void old_state()
369 if(!state_stack || !state_stack->next)
370 syntaxerror("invalid nesting");
371 state_t*oldstate = state;
372 state_list_t*old = state_stack;
373 state_stack = state_stack->next;
375 state = state_stack->state;
376 /*if(state->method->initcode) {
377 printf("residual initcode\n");
378 code_dump(state->method->initcode, 0, 0, "", stdout);
380 if(oldstate->has_own_imports) {
381 list_free(oldstate->wildcard_imports);
382 dict_destroy(oldstate->imports);oldstate->imports=0;
385 void initialize_state()
390 global->file = abc_file_new();
391 global->file->flags &= ~ABCFILE_LAZY;
393 global->init = abc_initscript(global->file, 0);
394 code_t*c = global->init->method->body->code;
396 c = abc_getlocal_0(c);
397 c = abc_pushscope(c);
399 /* findpropstrict doesn't just return a scope object- it
400 also makes it "active" somehow. Push local_0 on the
401 scope stack and read it back with findpropstrict, it'll
402 contain properties like "trace". Trying to find the same
403 property on a "vanilla" local_0 yields only a "undefined" */
404 //c = abc_findpropstrict(c, "[package]::trace");
406 /*c = abc_getlocal_0(c);
407 c = abc_findpropstrict(c, "[package]::trace");
409 c = abc_setlocal_1(c);
411 c = abc_pushbyte(c, 0);
412 c = abc_setlocal_2(c);
414 code_t*xx = c = abc_label(c);
415 c = abc_findpropstrict(c, "[package]::trace");
416 c = abc_pushstring(c, "prop:");
417 c = abc_hasnext2(c, 1, 2);
419 c = abc_setlocal_3(c);
420 c = abc_callpropvoid(c, "[package]::trace", 2);
421 c = abc_getlocal_3(c);
423 c = abc_iftrue(c,xx);*/
425 c = abc_findpropstrict(c, "[package]::trace");
426 c = abc_pushstring(c, "[entering global init function]");
427 c = abc_callpropvoid(c, "[package]::trace", 1);
429 global->init->method->body->code = c;
431 void* finalize_state()
433 if(state->level!=1) {
434 syntaxerror("unexpected end of file");
436 abc_method_body_t*m = global->init->method->body;
439 __ findpropstrict(m, "[package]::trace");
440 __ pushstring(m, "[leaving global init function]");
441 __ callpropvoid(m, "[package]::trace", 1);
447 static void startpackage(char*name)
450 syntaxerror("Packages can not be nested.");
453 /*printf("entering package \"%s\"\n", name);*/
454 state->package = name;
456 static void endpackage()
458 /*printf("leaving package \"%s\"\n", state->package);*/
463 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
466 syntaxerror("inner classes now allowed");
469 state->cls = rfx_calloc(sizeof(classstate_t));
472 classinfo_list_t*mlist=0;
473 /*printf("entering class %s\n", name);
474 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
476 printf(" extends: %s.%s\n", extends->package, extends->name);
477 printf(" implements (%d): ", list_length(implements));
478 for(mlist=implements;mlist;mlist=mlist->next) {
479 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
484 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
485 syntaxerror("invalid modifier(s)");
487 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
488 syntaxerror("public and internal not supported at the same time.");
490 /* create the class name, together with the proper attributes */
494 if(!(flags&FLAG_PUBLIC) && !state->package) {
495 access = ACCESS_PRIVATE; package = current_filename;
496 } else if(!(flags&FLAG_PUBLIC) && state->package) {
497 access = ACCESS_PACKAGEINTERNAL; package = state->package;
498 } else if(state->package) {
499 access = ACCESS_PACKAGE; package = state->package;
501 syntaxerror("public classes only allowed inside a package");
504 if(registry_findclass(package, classname)) {
505 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
509 /* build info struct */
510 int num_interfaces = (list_length(implements));
511 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
512 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
514 classinfo_list_t*l = implements;
515 for(l=implements;l;l=l->next) {
516 state->cls->info->interfaces[pos++] = l->classinfo;
519 multiname_t*extends2 = sig2mname(extends);
521 MULTINAME(classname2,state->cls->info);
524 state->cls_init = abc_getlocal_0(state->cls_init);
525 state->cls_init = abc_constructsuper(state->cls_init, 0);
528 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
529 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
530 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
531 if(interface) abc_class_interface(state->cls->abc);
532 abc_class_protectedNS(state->cls->abc, classname);
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 code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
600 c = code_append(c, initcode);
601 c = code_append(c, body);
602 /* append return if necessary */
603 if(!c || c->opcode != OPCODE_RETURNVOID &&
604 c->opcode != OPCODE_RETURNVALUE) {
605 c = abc_returnvoid(c);
610 static void endclass()
612 if(state->cls->init) {
613 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
614 m->body->code = wrap_function(0, state->cls->init, m->body->code);
616 if(state->cls->static_init) {
617 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
618 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
620 // handy for scope testing
624 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
630 typedef struct _variable {
635 static int find_variable(char*name, classinfo_t**m)
637 state_list_t* s = state_stack;
641 v = dict_lookup(s->state->vars, name);
652 static int find_variable_safe(char*name, classinfo_t**m)
654 int i = find_variable(name, m);
656 syntaxerror("undefined variable: %s", name);
659 static char variable_exists(char*name)
661 return dict_lookup(state->vars, name)!=0;
663 static int new_variable(char*name, classinfo_t*type)
666 v->index = global->variable_count;
668 dict_put(state->vars, name, v);
669 return global->variable_count++;
671 #define TEMPVARNAME "__as3_temp__"
672 static int gettempvar()
674 int i = find_variable(TEMPVARNAME, 0);
676 i = new_variable(TEMPVARNAME, 0);
681 code_t* killvars(code_t*c)
684 for(t=0;t<state->vars->hashsize;t++) {
685 dictentry_t*e =state->vars->slots[t];
687 variable_t*v = (variable_t*)e->data;
688 //do this always, otherwise register types don't match
689 //in the verifier when doing nested loops
690 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
691 c = abc_kill(c, v->index);
699 static void check_constant_against_type(classinfo_t*t, constant_t*c)
701 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
702 if(TYPE_IS_NUMBER(t)) {
703 xassert(c->type == CONSTANT_FLOAT
704 || c->type == CONSTANT_INT
705 || c->type == CONSTANT_UINT);
706 } else if(TYPE_IS_UINT(t)) {
707 xassert(c->type == CONSTANT_UINT ||
708 (c->type == CONSTANT_INT && c->i>0));
709 } else if(TYPE_IS_INT(t)) {
710 xassert(c->type == CONSTANT_INT);
711 } else if(TYPE_IS_BOOLEAN(t)) {
712 xassert(c->type == CONSTANT_TRUE
713 || c->type == CONSTANT_FALSE);
717 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
719 memberinfo_t*minfo = 0;
720 if(getset != KW_GET && getset != KW_SET) {
721 if(registry_findmember(state->cls->info, name)) {
722 syntaxerror("class already contains a member/method called '%s'", name);
724 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
725 minfo->return_type = return_type;
726 // getslot on a member slot only returns "undefined", so no need
727 // to actually store these
728 //state->minfo->slot = state->method->abc->method->trait->slot_id;
730 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
734 else if(params->list)
735 type = params->list->param->type;
736 if((minfo=registry_findmember(state->cls->info, name))) {
737 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
738 syntaxerror("class already contains a member or method called '%s'", name);
740 syntaxerror("getter/setter for '%s' already defined", name);
741 /* make a setter or getter into a getset */
746 if(type && minfo->type != type)
747 syntaxerror("different type in getter and setter");
749 minfo = memberinfo_register(state->cls->info, name, gs);
752 /* can't assign a slot as getter and setter might have different slots */
753 //minfo->slot = slot;
755 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
756 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
757 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
758 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
759 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
763 static int flags2access(int flags)
766 if(flags&FLAG_PUBLIC) {
767 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
768 access = ACCESS_PACKAGE;
769 } else if(flags&FLAG_PRIVATE) {
770 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
771 access = ACCESS_PRIVATE;
772 } else if(flags&FLAG_PROTECTED) {
773 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
774 access = ACCESS_PROTECTED;
776 access = ACCESS_PACKAGEINTERNAL;
781 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
782 params_t*params, classinfo_t*return_type)
785 syntaxerror("not able to start another method scope");
788 state->method = rfx_calloc(sizeof(methodstate_t));
789 state->method->initcode = 0;
790 state->method->is_constructor = !strcmp(state->cls->info->name,name);
791 state->method->has_super = 0;
793 global->variable_count = 0;
795 /* state->vars is initialized by state_new */
796 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
798 for(p=params->list;p;p=p->next) {
799 new_variable(p->param->name, p->param->type);
801 if(state->method->is_constructor)
802 name = "__as3_constructor__";
803 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
806 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
807 params_t*params, classinfo_t*return_type, code_t*body)
809 namespace_t mname_ns = {flags2access(flags), ""};
810 multiname_t mname = {QNAME, &mname_ns, 0, name};
814 multiname_t*type2 = sig2mname(return_type);
816 if(state->method->is_constructor) {
817 f = abc_class_getconstructor(state->cls->abc, type2);
819 if(flags&FLAG_STATIC)
820 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
822 f = abc_class_method(state->cls->abc, type2, &mname);
823 slot = f->trait->slot_id;
825 //flash doesn't seem to allow us to access function slots
826 //state->method->info->slot = slot;
828 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
829 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
830 if(params->varargs) f->flags |= METHOD_NEED_REST;
834 for(p=params->list;p;p=p->next) {
835 if(params->varargs && !p->next) {
836 break; //varargs: omit last parameter in function signature
838 multiname_t*m = sig2mname(p->param->type);
839 list_append(f->parameters, m);
840 if(p->param->value) {
841 check_constant_against_type(p->param->type, p->param->value);
842 opt=1;list_append(f->optional_parameters, p->param->value);
844 syntaxerror("non-optional parameter not allowed after optional parameters");
847 f->body->code = body;
854 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
859 void breakjumpsto(code_t*c, code_t*jump)
864 if(c->opcode == OPCODE___BREAK__) {
865 c->opcode = OPCODE_JUMP;
872 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
875 return registry_getanytype();
876 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
877 return registry_getanytype();
880 return registry_getanytype();
882 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
887 return abc_coerce_a(c);
891 // cast an "any" type to a specific type. subject to
892 // runtime exceptions
893 return abc_coerce2(c, &m);
896 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
897 return abc_coerce2(c, &m);
899 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
900 return abc_coerce2(c, &m);
902 /* these are subject to overflow */
903 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
904 return abc_coerce2(c, &m);
906 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
907 return abc_coerce2(c, &m);
910 classinfo_t*supertype = from;
912 if(supertype == to) {
913 // target type is one of from's superclasses
914 return abc_coerce2(c, &m);
917 while(supertype->interfaces[t]) {
918 if(supertype->interfaces[t]==to) {
919 // to type is one of from's interfaces
920 return abc_coerce2(c, &m);
924 supertype = supertype->superclass;
926 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
928 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
930 syntaxerror("can't convert type %s to %s", from->name, to->name);
933 code_t*defaultvalue(code_t*c, classinfo_t*type)
935 if(TYPE_IS_INT(type)) {
936 c = abc_pushbyte(c, 0);
937 } else if(TYPE_IS_UINT(type)) {
938 c = abc_pushuint(c, 0);
939 } else if(TYPE_IS_FLOAT(type)) {
941 } else if(TYPE_IS_BOOLEAN(type)) {
942 c = abc_pushfalse(c);
949 char is_pushundefined(code_t*c)
951 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
954 void parserassert(int b)
956 if(!b) syntaxerror("internal error: assertion failed");
959 static classinfo_t* find_class(char*name)
963 c = registry_findclass(state->package, name);
965 /* try explicit imports */
966 dictentry_t* e = dict_get_slot(state->imports, name);
970 if(!strcmp(e->key, name)) {
971 c = (classinfo_t*)e->data;
976 /* try package.* imports */
977 import_list_t*l = state->wildcard_imports;
981 //printf("does package %s contain a class %s?\n", l->import->package, name);
982 c = registry_findclass(l->import->package, name);
986 /* try global package */
988 c = registry_findclass("", name);
993 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
997 [prefix code] [read instruction]
1001 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1004 if(in && in->opcode == OPCODE_COERCE_A) {
1005 in = code_cutlast(in);
1008 syntaxerror("internal error");
1010 /* chop off read instruction */
1014 prefix = r->prev;r->prev = 0;
1020 char use_temp_var = readbefore;
1022 /* generate the write instruction, and maybe append a dup to the prefix code */
1023 code_t* write = abc_nop(0);
1024 if(r->opcode == OPCODE_GETPROPERTY) {
1025 write->opcode = OPCODE_SETPROPERTY;
1026 multiname_t*m = (multiname_t*)r->data[0];
1027 write->data[0] = multiname_clone(m);
1028 if(m->type == QNAME || m->type == MULTINAME) {
1030 prefix = abc_dup(prefix); // we need the object, too
1033 } else if(m->type == MULTINAMEL) {
1035 /* dupping two values on the stack requires 5 operations and one register-
1036 couldn't adobe just have given us a dup2? */
1037 int temp = gettempvar();
1038 prefix = abc_setlocal(prefix, temp);
1039 prefix = abc_dup(prefix);
1040 prefix = abc_getlocal(prefix, temp);
1041 prefix = abc_swap(prefix);
1042 prefix = abc_getlocal(prefix, temp);
1046 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1048 } else if(r->opcode == OPCODE_GETSLOT) {
1049 write->opcode = OPCODE_SETSLOT;
1050 write->data[0] = r->data[0];
1052 prefix = abc_dup(prefix); // we need the object, too
1055 } else if(r->opcode == OPCODE_GETLOCAL) {
1056 write->opcode = OPCODE_SETLOCAL;
1057 write->data[0] = r->data[0];
1058 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1059 write->opcode = OPCODE_SETLOCAL_0;
1060 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1061 write->opcode = OPCODE_SETLOCAL_1;
1062 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1063 write->opcode = OPCODE_SETLOCAL_2;
1064 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1065 write->opcode = OPCODE_SETLOCAL_3;
1067 code_dump(r, 0, 0, "", stdout);
1068 syntaxerror("illegal lvalue: can't assign a value to this expression");
1075 /* with getproperty/getslot, we have to be extra careful not
1076 to execute the read code twice, as it might have side-effects
1077 (e.g. if the property is in fact a setter/getter combination)
1079 So read the value, modify it, and write it again,
1080 using prefix only once and making sure (by using a temporary
1081 register) that the return value is what we just wrote */
1082 temp = gettempvar();
1083 c = code_append(c, prefix);
1084 c = code_append(c, r);
1087 c = abc_setlocal(c, temp);
1089 c = code_append(c, middlepart);
1092 c = abc_setlocal(c, temp);
1094 c = code_append(c, write);
1095 c = abc_getlocal(c, temp);
1096 c = abc_kill(c, temp);
1098 /* if we're allowed to execute the read code twice *and*
1099 the middlepart doesn't modify the code, things are easier.
1101 code_t* r2 = code_dup(r);
1102 //c = code_append(c, prefix);
1103 parserassert(!prefix);
1104 c = code_append(c, r);
1105 c = code_append(c, middlepart);
1106 c = code_append(c, write);
1107 c = code_append(c, r2);
1110 /* even smaller version: overwrite the value without reading
1114 c = code_append(c, prefix);
1117 c = code_append(c, middlepart);
1118 c = code_append(c, write);
1119 c = code_append(c, r);
1121 temp = gettempvar();
1123 c = code_append(c, prefix);
1126 c = code_append(c, middlepart);
1128 c = abc_setlocal(c, temp);
1129 c = code_append(c, write);
1130 c = abc_getlocal(c, temp);
1137 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1138 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1145 /* ------------ code blocks / statements ---------------- */
1149 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1150 MAYBECODE: {$$=code_new();}
1152 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1153 CODE: CODEPIECE {$$=$1;}
1155 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1156 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1157 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1158 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1159 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1160 CODEPIECE: ';' {$$=code_new();}
1161 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1162 CODEPIECE: VOIDEXPRESSION {$$=$1}
1163 CODEPIECE: FOR {$$=$1}
1164 CODEPIECE: WHILE {$$=$1}
1165 CODEPIECE: BREAK {$$=$1}
1166 CODEPIECE: RETURN {$$=$1}
1167 CODEPIECE: IF {$$=$1}
1168 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1169 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1171 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1172 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1173 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1175 /* ------------ variables --------------------------- */
1177 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1178 | {$$.c=abc_pushundefined(0);
1182 VAR : "const" | "var"
1183 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1185 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1186 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1188 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1190 if(variable_exists($2))
1191 syntaxerror("Variable %s already defined", $2);
1193 if(!is_subtype_of($4.t, $3)) {
1194 syntaxerror("Can't convert %s to %s", $4.t->name,
1198 int index = new_variable($2, $3);
1201 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1203 $$ = converttype($$, $4.t, $3);
1204 $$ = abc_setlocal($$, index);
1206 $$ = defaultvalue(0, $3);
1207 $$ = abc_setlocal($$, index);
1210 /* if this is a typed variable:
1211 push default value for type on stack */
1213 state->method->initcode = defaultvalue(state->method->initcode, $3);
1214 state->method->initcode = abc_setlocal(state->method->initcode, index);
1217 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1219 $$ = abc_coerce_a($$);
1220 $$ = abc_setlocal($$, index);
1226 /* that's the default for a local register, anyway
1228 state->method->initcode = abc_pushundefined(state->method->initcode);
1229 state->method->initcode = abc_setlocal(state->method->initcode, index);
1231 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1234 /* ------------ control flow ------------------------- */
1236 MAYBEELSE: %prec below_else {$$ = code_new();}
1237 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1238 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1240 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1242 $$ = code_append($$, $4.c);
1243 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1245 $$ = code_append($$, $6);
1247 myjmp = $$ = abc_jump($$, 0);
1249 myif->branch = $$ = abc_nop($$);
1251 $$ = code_append($$, $7);
1252 myjmp->branch = $$ = abc_nop($$);
1255 $$ = killvars($$);old_state();
1258 FOR_INIT : {$$=code_new();}
1259 FOR_INIT : VARIABLE_DECLARATION
1260 FOR_INIT : VOIDEXPRESSION
1262 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1264 $$ = code_append($$, $4);
1265 code_t*loopstart = $$ = abc_label($$);
1266 $$ = code_append($$, $6.c);
1267 code_t*myif = $$ = abc_iffalse($$, 0);
1268 $$ = code_append($$, $10);
1269 $$ = code_append($$, $8);
1270 $$ = abc_jump($$, loopstart);
1271 code_t*out = $$ = abc_nop($$);
1272 breakjumpsto($$, out);
1275 $$ = killvars($$);old_state();
1278 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1281 code_t*myjmp = $$ = abc_jump($$, 0);
1282 code_t*loopstart = $$ = abc_label($$);
1283 $$ = code_append($$, $6);
1284 myjmp->branch = $$ = abc_nop($$);
1285 $$ = code_append($$, $4.c);
1286 $$ = abc_iftrue($$, loopstart);
1287 code_t*out = $$ = abc_nop($$);
1288 breakjumpsto($$, out);
1290 $$ = killvars($$);old_state();
1294 $$ = abc___break__(0);
1297 /* ------------ packages and imports ---------------- */
1299 X_IDENTIFIER: T_IDENTIFIER
1300 | "package" {$$="package";}
1302 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1303 PACKAGE: X_IDENTIFIER {$$=$1;}
1305 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1306 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1308 IMPORT : "import" QNAME {
1311 syntaxerror("Couldn't import class\n");
1312 state_has_imports();
1313 dict_put(state->imports, c->name, c);
1316 IMPORT : "import" PACKAGE '.' '*' {
1319 state_has_imports();
1320 list_append(state->wildcard_imports, i);
1324 /* ------------ classes and interfaces (header) -------------- */
1326 MAYBE_MODIFIERS : {$$=0;}
1327 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1328 MODIFIER_LIST : MODIFIER {$$=$1;}
1329 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1331 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1332 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1333 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1334 | KW_STATIC {$$=FLAG_STATIC;}
1335 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1336 | KW_FINAL {$$=FLAG_FINAL;}
1337 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1338 | KW_NATIVE {$$=FLAG_NATIVE;}
1339 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1341 EXTENDS : {$$=registry_getobjectclass();}
1342 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1344 EXTENDS_LIST : {$$=list_new();}
1345 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1347 IMPLEMENTS_LIST : {$$=list_new();}
1348 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1350 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1351 EXTENDS IMPLEMENTS_LIST
1352 '{' {startclass($1,$3,$4,$5, 0);}
1353 MAYBE_DECLARATION_LIST
1356 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1358 '{' {startclass($1,$3,0,$4,1);}
1359 MAYBE_IDECLARATION_LIST
1362 /* ------------ classes and interfaces (body) -------------- */
1364 MAYBE_DECLARATION_LIST :
1365 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1366 DECLARATION_LIST : DECLARATION
1367 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1369 DECLARATION : SLOT_DECLARATION
1370 DECLARATION : FUNCTION_DECLARATION
1372 MAYBE_IDECLARATION_LIST :
1373 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1374 IDECLARATION_LIST : IDECLARATION
1375 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1377 IDECLARATION : "var" T_IDENTIFIER {
1378 syntaxerror("variable declarations not allowed in interfaces");
1380 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1382 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1383 syntaxerror("invalid method modifiers: interface methods always need to be public");
1385 startfunction(0,$1,$3,$4,&$6,$8);
1386 endfunction(0,$1,$3,$4,&$6,$8, 0);
1389 /* ------------ classes and interfaces (body, slots ) ------- */
1391 VARCONST: "var" | "const"
1393 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1395 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1397 info->flags = flags;
1400 namespace_t mname_ns = {flags2access(flags), ""};
1401 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1403 if(!(flags&FLAG_STATIC)) {
1406 t=abc_class_slot(state->cls->abc, &mname, &m);
1408 t=abc_class_slot(state->cls->abc, &mname, 0);
1410 info->slot = t->slot_id;
1414 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1416 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1418 info->slot = t->slot_id;
1420 if($5.c && !is_pushundefined($5.c)) {
1422 c = abc_getlocal_0(c);
1423 c = code_append(c, $5.c);
1424 c = converttype(c, $5.t, $4);
1425 c = abc_setslot(c, t->slot_id);
1426 if(!(flags&FLAG_STATIC))
1427 state->cls->init = code_append(state->cls->init, c);
1429 state->cls->static_init = code_append(state->cls->static_init, c);
1432 t->kind= TRAIT_CONST;
1436 /* ------------ constants -------------------------------------- */
1438 MAYBESTATICCONSTANT: {$$=0;}
1439 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1441 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1442 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1443 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1444 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1445 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1446 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1447 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1448 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1449 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1451 /* ------------ classes and interfaces (body, functions) ------- */
1453 // non-vararg version
1455 memset(&$$,0,sizeof($$));
1457 MAYBE_PARAM_LIST: PARAM_LIST {
1462 MAYBE_PARAM_LIST: "..." PARAM {
1463 memset(&$$,0,sizeof($$));
1465 list_append($$.list, $2);
1467 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1470 list_append($$.list, $4);
1474 PARAM_LIST: PARAM_LIST ',' PARAM {
1476 list_append($$.list, $3);
1479 memset(&$$,0,sizeof($$));
1480 list_append($$.list, $1);
1483 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1484 $$ = malloc(sizeof(param_t));
1489 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1490 $$ = malloc(sizeof(param_t));
1492 $$->type = TYPE_ANY;
1495 GETSET : "get" {$$=$1;}
1499 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1500 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1503 if(state->method->late_binding) {
1504 c = abc_getlocal_0(c);
1505 c = abc_pushscope(c);
1507 if(state->method->is_constructor && !state->method->has_super) {
1508 // call default constructor
1509 c = abc_getlocal_0(c);
1510 c = abc_constructsuper(c, 0);
1512 c = wrap_function(c, state->method->initcode, $11);
1513 endfunction(0,$1,$3,$4,&$6,$8,c);
1516 /* ------------- package + class ids --------------- */
1518 CLASS: T_IDENTIFIER {
1520 /* try current package */
1521 $$ = find_class($1);
1522 if(!$$) syntaxerror("Could not find class %s\n", $1);
1525 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1526 $$ = registry_findclass($1, $3);
1527 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1530 QNAME: PACKAGEANDCLASS
1533 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1534 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1536 TYPE : QNAME {$$=$1;}
1537 | '*' {$$=registry_getanytype();}
1539 | "String" {$$=registry_getstringclass();}
1540 | "int" {$$=registry_getintclass();}
1541 | "uint" {$$=registry_getuintclass();}
1542 | "Boolean" {$$=registry_getbooleanclass();}
1543 | "Number" {$$=registry_getnumberclass();}
1546 MAYBETYPE: ':' TYPE {$$=$2;}
1549 /* ----------function calls, delete, constructor calls ------ */
1551 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1552 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1554 MAYBE_EXPRESSION_LIST : {$$=0;}
1555 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1556 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1557 typedcode_t*t = malloc(sizeof(typedcode_t));
1559 list_append($$, t);}
1560 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1561 typedcode_t*t = malloc(sizeof(typedcode_t));
1563 list_append($$, t);}
1565 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1570 $$.c = abc_getglobalscope($$.c);
1571 $$.c = abc_getslot($$.c, $2->slot);
1573 $$.c = abc_findpropstrict2($$.c, &m);
1576 typedcode_list_t*l = $3;
1579 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1584 $$.c = abc_construct($$.c, len);
1586 $$.c = abc_constructprop2($$.c, &m, len);
1590 /* TODO: use abc_call (for calling local variables),
1591 abc_callstatic (for calling own methods)
1594 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1595 typedcode_list_t*l = $3;
1597 code_t*paramcode = 0;
1599 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1605 if($$.c->opcode == OPCODE_COERCE_A) {
1606 $$.c = code_cutlast($$.c);
1610 multiname_t*name = 0;
1611 if($$.c->opcode == OPCODE_GETPROPERTY) {
1612 name = multiname_clone($$.c->data[0]);
1613 $$.c = code_cutlast($$.c);
1614 $$.c = code_append($$.c, paramcode);
1615 $$.c = abc_callproperty2($$.c, name, len);
1616 } else if($$.c->opcode == OPCODE_GETSLOT) {
1617 int slot = (int)(ptroff_t)$$.c->data[0];
1618 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1619 if(t->kind!=TRAIT_METHOD) {
1620 //flash allows to assign closures to members.
1621 //syntaxerror("not a function");
1624 $$.c = code_cutlast($$.c);
1625 $$.c = code_append($$.c, paramcode);
1626 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1627 $$.c = abc_callproperty2($$.c, name, len);
1628 } else if($$.c->opcode == OPCODE_GETSUPER) {
1629 name = multiname_clone($$.c->data[0]);
1630 $$.c = code_cutlast($$.c);
1631 $$.c = code_append($$.c, paramcode);
1632 $$.c = abc_callsuper2($$.c, name, len);
1634 $$.c = abc_getlocal_0($$.c);
1635 $$.c = code_append($$.c, paramcode);
1636 $$.c = abc_call($$.c, len);
1641 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1642 $$.t = $1.t->function->return_type;
1644 $$.c = abc_coerce_a($$.c);
1648 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1649 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1650 if(!state->method) syntaxerror("super() not allowed outside of a function");
1651 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1654 $$.c = abc_getlocal_0($$.c);
1655 typedcode_list_t*l = 0;
1657 for(l=$3;l;l=l->next) {
1658 $$.c = code_append($$.c, l->typedcode->c);len++;
1661 this is dependent on the control path, check this somewhere else
1662 if(state->method->has_super)
1663 syntaxerror("constructor may call super() only once");
1665 state->method->has_super = 1;
1666 $$.c = abc_constructsuper($$.c, len);
1667 $$.c = abc_pushundefined($$.c);
1671 DELETE: "delete" E {
1673 if($$.c->opcode == OPCODE_COERCE_A) {
1674 $$.c = code_cutlast($$.c);
1676 multiname_t*name = 0;
1677 if($$.c->opcode == OPCODE_GETPROPERTY) {
1678 $$.c->opcode = OPCODE_DELETEPROPERTY;
1679 } else if($$.c->opcode == OPCODE_GETSLOT) {
1680 int slot = (int)(ptroff_t)$$.c->data[0];
1681 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1682 $$.c = code_cutlast($$.c);
1683 $$.c = abc_deleteproperty2($$.c, name);
1685 $$.c = abc_getlocal_0($$.c);
1686 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1687 $$.c = abc_deleteproperty2($$.c, &m);
1689 $$.t = TYPE_BOOLEAN;
1692 RETURN: "return" %prec prec_none {
1693 $$ = abc_returnvoid(0);
1695 RETURN: "return" EXPRESSION {
1697 $$ = abc_returnvalue($$);
1700 // ----------------------- expression types -------------------------------------
1702 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1703 EXPRESSION : E %prec below_minus {$$ = $1;}
1704 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1706 $$.c = cut_last_push($$.c);
1707 $$.c = code_append($$.c,$3.c);
1710 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1711 $$=cut_last_push($1.c);
1714 // ----------------------- expression evaluation -------------------------------------
1717 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1719 E : DELETE {$$ = $1;}
1720 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1724 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1725 //MULTINAME(m, registry_getintclass());
1726 //$$.c = abc_coerce2($$.c, &m); // FIXME
1729 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1732 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1735 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1738 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1741 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1744 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1747 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1748 $$.t = TYPE_BOOLEAN;
1750 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1751 $$.t = TYPE_BOOLEAN;
1753 CONSTANT : "null" {$$.c = abc_pushnull(0);
1758 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1759 $$.t = TYPE_BOOLEAN;
1761 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1762 $$.t = TYPE_BOOLEAN;
1764 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1765 $$.t = TYPE_BOOLEAN;
1767 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1768 $$.t = TYPE_BOOLEAN;
1770 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1771 $$.t = TYPE_BOOLEAN;
1773 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1774 $$.t = TYPE_BOOLEAN;
1776 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1777 $$.t = TYPE_BOOLEAN;
1779 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1780 $$.t = TYPE_BOOLEAN;
1783 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1785 $$.c = converttype($$.c, $1.t, $$.t);
1786 $$.c = abc_dup($$.c);
1787 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1788 $$.c = cut_last_push($$.c);
1789 $$.c = code_append($$.c,$3.c);
1790 $$.c = converttype($$.c, $3.t, $$.t);
1791 code_t*label = $$.c = abc_label($$.c);
1792 jmp->branch = label;
1795 $$.t = join_types($1.t, $3.t, 'A');
1796 /*printf("%08x:\n",$1.t);
1797 code_dump($1.c, 0, 0, "", stdout);
1798 printf("%08x:\n",$3.t);
1799 code_dump($3.c, 0, 0, "", stdout);
1800 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1802 $$.c = converttype($$.c, $1.t, $$.t);
1803 $$.c = abc_dup($$.c);
1804 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1805 $$.c = cut_last_push($$.c);
1806 $$.c = code_append($$.c,$3.c);
1807 $$.c = converttype($$.c, $3.t, $$.t);
1808 code_t*label = $$.c = abc_label($$.c);
1809 jmp->branch = label;
1812 E : '!' E {$$.c=$2.c;
1813 $$.c = abc_not($$.c);
1814 $$.t = TYPE_BOOLEAN;
1817 E : '~' E {$$.c=$2.c;
1818 $$.c = abc_bitnot($$.c);
1822 E : E '&' E {$$.c = code_append($1.c,$3.c);
1823 $$.c = abc_bitand($$.c);
1827 E : E '^' E {$$.c = code_append($1.c,$3.c);
1828 $$.c = abc_bitxor($$.c);
1832 E : E '|' E {$$.c = code_append($1.c,$3.c);
1833 $$.c = abc_bitor($$.c);
1837 E : E '-' E {$$.c = code_append($1.c,$3.c);
1838 if(BOTH_INT($1,$3)) {
1839 $$.c = abc_subtract_i($$.c);
1842 $$.c = abc_subtract($$.c);
1846 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1847 $$.c = abc_rshift($$.c);
1850 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1851 $$.c = abc_urshift($$.c);
1854 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1855 $$.c = abc_lshift($$.c);
1859 E : E '/' E {$$.c = code_append($1.c,$3.c);
1860 $$.c = abc_divide($$.c);
1863 E : E '+' E {$$.c = code_append($1.c,$3.c);
1864 $$.c = abc_add($$.c);
1867 E : E '%' E {$$.c = code_append($1.c,$3.c);
1868 $$.c = abc_modulo($$.c);
1871 E : E '*' E {$$.c = code_append($1.c,$3.c);
1872 if(BOTH_INT($1,$3)) {
1873 $$.c = abc_multiply_i($$.c);
1876 $$.c = abc_multiply($$.c);
1881 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1882 if(use_astype && TYPE_IS_CLASS($3.t)) {
1883 MULTINAME(m,$3.t->cls);
1884 $$.c = abc_astype2($1.c, &m);
1887 $$.c = code_append($1.c, $3.c);
1888 $$.c = abc_astypelate($$.c);
1893 E : E "instanceof" E
1894 {$$.c = code_append($1.c, $3.c);
1895 $$.c = abc_instanceof($$.c);
1896 $$.t = TYPE_BOOLEAN;
1899 E : E "is" E {$$.c = code_append($1.c, $3.c);
1900 $$.c = abc_istypelate($$.c);
1901 $$.t = TYPE_BOOLEAN;
1904 E : "typeof" '(' E ')' {
1906 $$.c = abc_typeof($$.c);
1911 $$.c = cut_last_push($2.c);
1912 $$.c = abc_pushundefined($$.c);
1916 E : "void" { $$.c = abc_pushundefined(0);
1920 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
1925 $$.c=abc_negate_i($$.c);
1928 $$.c=abc_negate($$.c);
1935 $$.c = code_append($$.c, $3.c);
1937 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1938 $$.c = abc_getproperty2($$.c, &m);
1939 $$.t = 0; // array elements have unknown type
1944 if(BOTH_INT($1,$3)) {
1945 c=abc_multiply_i(c);
1949 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1950 $$.c = toreadwrite($1.c, c, 0, 0);
1955 code_t*c = abc_modulo($3.c);
1956 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1957 $$.c = toreadwrite($1.c, c, 0, 0);
1961 code_t*c = abc_lshift($3.c);
1962 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1963 $$.c = toreadwrite($1.c, c, 0, 0);
1967 code_t*c = abc_rshift($3.c);
1968 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1969 $$.c = toreadwrite($1.c, c, 0, 0);
1973 code_t*c = abc_urshift($3.c);
1974 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1975 $$.c = toreadwrite($1.c, c, 0, 0);
1979 code_t*c = abc_divide($3.c);
1980 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1981 $$.c = toreadwrite($1.c, c, 0, 0);
1986 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1991 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1993 $$.c = toreadwrite($1.c, c, 0, 0);
1996 E : E "-=" E { code_t*c = $3.c;
1997 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1998 c=abc_subtract_i(c);
2002 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2004 $$.c = toreadwrite($1.c, c, 0, 0);
2007 E : E '=' E { code_t*c = 0;
2008 c = code_append(c, $3.c);
2009 c = converttype(c, $3.t, $1.t);
2010 $$.c = toreadwrite($1.c, c, 1, 0);
2014 E : E '?' E ':' E %prec below_assignment {
2016 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2017 $$.c = code_append($$.c, $3.c);
2018 code_t*j2 = $$.c = abc_jump($$.c, 0);
2019 $$.c = j1->branch = abc_label($$.c);
2020 $$.c = code_append($$.c, $5.c);
2021 $$.c = j2->branch = abc_label($$.c);
2022 $$.t = join_types($3.t,$5.t,'?');
2025 // TODO: use inclocal where appropriate
2026 E : E "++" { code_t*c = 0;
2027 classinfo_t*type = $1.t;
2028 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2029 c=abc_increment_i(c);
2035 c=converttype(c, type, $1.t);
2036 $$.c = toreadwrite($1.c, c, 0, 1);
2039 E : E "--" { code_t*c = 0;
2040 classinfo_t*type = $1.t;
2041 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2042 c=abc_decrement_i(c);
2048 c=converttype(c, type, $1.t);
2049 $$.c = toreadwrite($1.c, c, 0, 1);
2053 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2054 classinfo_t*type = $2.t;
2055 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2056 c=abc_increment_i(c);
2062 c=converttype(c, type, $2.t);
2063 $$.c = toreadwrite($2.c, c, 0, 0);
2067 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2068 classinfo_t*type = $2.t;
2069 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2070 c=abc_decrement_i(c);
2076 c=converttype(c, type, $2.t);
2077 $$.c = toreadwrite($2.c, c, 0, 0);
2081 E : "super" '.' T_IDENTIFIER
2082 { if(!state->cls->info)
2083 syntaxerror("super keyword not allowed outside a class");
2084 classinfo_t*t = state->cls->info->superclass;
2085 if(!t) t = TYPE_OBJECT;
2087 memberinfo_t*f = registry_findmember(t, $3);
2088 namespace_t ns = {flags2access(f->flags), ""};
2089 MEMBER_MULTINAME(m, f, $3);
2091 $$.c = abc_getlocal_0($$.c);
2092 $$.c = abc_getsuper2($$.c, &m);
2093 $$.t = memberinfo_gettype(f);
2096 E : E '.' T_IDENTIFIER
2098 classinfo_t*t = $1.t;
2100 if(TYPE_IS_CLASS(t) && t->cls) {
2105 memberinfo_t*f = registry_findmember(t, $3);
2107 if(f && !is_static != !(f->flags&FLAG_STATIC))
2109 if(f && f->slot && !noslot) {
2110 $$.c = abc_getslot($$.c, f->slot);
2112 MEMBER_MULTINAME(m, f, $3);
2113 $$.c = abc_getproperty2($$.c, &m);
2115 /* determine type */
2116 $$.t = memberinfo_gettype(f);
2118 $$.c = abc_coerce_a($$.c);
2120 /* when resolving a property on an unknown type, we do know the
2121 name of the property (and don't seem to need the package), but
2122 we need to make avm2 try out all access modes */
2123 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2124 $$.c = abc_getproperty2($$.c, &m);
2125 $$.c = abc_coerce_a($$.c);
2126 $$.t = registry_getanytype();
2130 VAR_READ : T_IDENTIFIER {
2137 /* look at variables */
2138 if((i = find_variable($1, &$$.t)) >= 0) {
2139 // $1 is a local variable
2140 $$.c = abc_getlocal($$.c, i);
2142 /* look at current class' members */
2143 } else if((f = registry_findmember(state->cls->info, $1))) {
2144 // $1 is a function in this class
2145 int var_is_static = (f->flags&FLAG_STATIC);
2146 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2147 if(var_is_static != i_am_static) {
2148 /* there doesn't seem to be any "static" way to access
2149 static properties of a class */
2150 state->method->late_binding = 1;
2152 namespace_t ns = {flags2access(f->flags), ""};
2153 multiname_t m = {QNAME, &ns, 0, $1};
2154 $$.c = abc_findpropstrict2($$.c, &m);
2155 $$.c = abc_getproperty2($$.c, &m);
2158 $$.c = abc_getlocal_0($$.c);
2159 $$.c = abc_getslot($$.c, f->slot);
2161 namespace_t ns = {flags2access(f->flags), ""};
2162 multiname_t m = {QNAME, &ns, 0, $1};
2163 $$.c = abc_getlocal_0($$.c);
2164 $$.c = abc_getproperty2($$.c, &m);
2167 if(f->kind == MEMBER_METHOD) {
2168 $$.t = TYPE_FUNCTION(f);
2173 /* look at classes in the current package and imported classes */
2174 } else if((a = find_class($1))) {
2176 $$.c = abc_getglobalscope($$.c);
2177 $$.c = abc_getslot($$.c, a->slot);
2180 $$.c = abc_getlex2($$.c, &m);
2182 $$.t = TYPE_CLASS(a);
2184 /* unknown object, let the avm2 resolve it */
2186 if(strcmp($1,"trace"))
2187 warning("Couldn't resolve '%s', doing late binding", $1);
2188 state->method->late_binding = 1;
2190 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2193 $$.c = abc_findpropstrict2($$.c, &m);
2194 $$.c = abc_getproperty2($$.c, &m);
2199 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2200 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2201 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2203 // ----------------- namespaces -------------------------------------------------
2205 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2206 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2207 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2209 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER