3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
30 #include "tokenizer.h"
42 enum yytokentype token;
45 classinfo_t*classinfo;
46 classinfo_list_t*classinfo_list;
49 unsigned int number_uint;
53 typedcode_list_t*value_list;
62 %token<id> T_IDENTIFIER
64 %token<token> T_REGEXP
66 %token<number_int> T_INT
67 %token<number_uint> T_UINT
68 %token<number_uint> T_BYTE
69 %token<number_uint> T_SHORT
70 %token<number_float> T_FLOAT
72 %token<token> KW_IMPLEMENTS
73 %token<token> KW_NAMESPACE "namespace"
74 %token<token> KW_PACKAGE "package"
75 %token<token> KW_PROTECTED
76 %token<token> KW_PUBLIC
77 %token<token> KW_PRIVATE
78 %token<token> KW_USE "use"
79 %token<token> KW_INTERNAL
80 %token<token> KW_NEW "new"
81 %token<token> KW_NATIVE
82 %token<token> KW_FUNCTION "function"
83 %token<token> KW_UNDEFINED "undefined"
84 %token<token> KW_CONTINUE "continue"
85 %token<token> KW_FOR "for"
86 %token<token> KW_CLASS "class"
87 %token<token> KW_CONST "const"
88 %token<token> KW_SET "set"
89 %token<token> KW_VOID "void"
90 %token<token> KW_STATIC
91 %token<token> KW_INSTANCEOF "instanceof"
92 %token<token> KW_IMPORT "import"
93 %token<token> KW_RETURN "return"
94 %token<token> KW_TYPEOF "typeof"
95 %token<token> KW_INTERFACE "interface"
96 %token<token> KW_NULL "null"
97 %token<token> KW_VAR "var"
98 %token<token> KW_DYNAMIC
99 %token<token> KW_OVERRIDE
100 %token<token> KW_FINAL
101 %token<token> KW_GET "get"
102 %token<token> KW_SUPER "super"
103 %token<token> KW_EXTENDS
104 %token<token> KW_FALSE "false"
105 %token<token> KW_TRUE "true"
106 %token<token> KW_BOOLEAN "Boolean"
107 %token<token> KW_UINT "uint"
108 %token<token> KW_INT "int"
109 %token<token> KW_WHILE "while"
110 %token<token> KW_NUMBER "Number"
111 %token<token> KW_STRING "String"
112 %token<token> KW_DELETE "delete"
113 %token<token> KW_IF "if"
114 %token<token> KW_ELSE "else"
115 %token<token> KW_BREAK "break"
116 %token<token> KW_IS "is"
117 %token<token> KW_AS "as"
118 %token<token> KW_DO "do"
120 %token<token> T_EQEQ "=="
121 %token<token> T_EQEQEQ "==="
122 %token<token> T_NE "!="
123 %token<token> T_NEE "!=="
124 %token<token> T_LE "<="
125 %token<token> T_GE ">="
126 %token<token> T_DIVBY "/="
127 %token<token> T_MODBY "%="
128 %token<token> T_MULBY "*="
129 %token<token> T_PLUSBY "+="
130 %token<token> T_MINUSBY "-="
131 %token<token> T_SHRBY ">>="
132 %token<token> T_SHLBY "<<="
133 %token<token> T_USHRBY ">>>="
134 %token<token> T_OROR "||"
135 %token<token> T_ANDAND "&&"
136 %token<token> T_COLONCOLON "::"
137 %token<token> T_MINUSMINUS "--"
138 %token<token> T_PLUSPLUS "++"
139 %token<token> T_DOTDOT ".."
140 %token<token> T_DOTDOTDOT "..."
141 %token<token> T_SHL "<<"
142 %token<token> T_USHR ">>>"
143 %token<token> T_SHR ">>"
145 %type <id> X_IDENTIFIER PACKAGE MAYBELABEL
146 %type <token> VARCONST
148 %type <code> CODEPIECE
149 %type <code> CODEBLOCK MAYBECODE
150 %type <token> PACKAGE_DECLARATION
151 %type <token> FUNCTION_DECLARATION
152 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
153 %type <token> CLASS_DECLARATION
154 %type <token> NAMESPACE_DECLARATION
155 %type <token> INTERFACE_DECLARATION
156 %type <code> VOIDEXPRESSION
157 %type <value> EXPRESSION NONCOMMAEXPRESSION
158 %type <value> MAYBEEXPRESSION
159 %type <value> E DELETE
160 %type <value> CONSTANT
161 %type <code> FOR IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
162 %type <token> USE_NAMESPACE
163 %type <code> FOR_INIT
165 %type <classinfo> MAYBETYPE
168 %type <params> PARAM_LIST
169 %type <params> MAYBE_PARAM_LIST
170 %type <flags> MAYBE_MODIFIERS
171 %type <flags> MODIFIER_LIST
172 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
173 %type <classinfo_list> IMPLEMENTS_LIST
174 %type <classinfo> EXTENDS
175 %type <classinfo_list> EXTENDS_LIST
176 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
177 %type <classinfo_list> QNAME_LIST
178 %type <classinfo> TYPE
180 //%type <token> VARIABLE
181 %type <value> VAR_READ
183 //%type <token> T_IDENTIFIER
184 %type <token> MODIFIER
185 %type <value> FUNCTIONCALL
186 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
188 // precedence: from low to high
192 %left below_semicolon
195 %nonassoc below_assignment // for ?:, contrary to spec
196 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
203 %nonassoc "==" "!=" "===" "!=="
205 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
206 %left "<<" ">>" ">>>"
210 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
212 %left '[' ']' '{' "new" '.' ".." "::"
213 %nonassoc T_IDENTIFIER
218 // needed for "return" precedence:
219 %nonassoc T_STRING T_REGEXP
220 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
221 %nonassoc "false" "true" "null" "undefined" "super"
226 static int yyerror(char*s)
228 syntaxerror("%s", s);
230 static char* concat3str(const char* t1, const char* t2, const char* t3)
235 char*text = malloc(l1+l2+l3+1);
236 memcpy(text , t1, l1);
237 memcpy(text+l1, t2, l2);
238 memcpy(text+l1+l2, t3, l3);
243 typedef struct _import {
247 DECLARE_LIST(import);
249 typedef struct _classstate {
255 char has_constructor;
258 typedef struct _methodstate {
262 /* code that needs to be executed at the start of
263 a method (like initializing local registers) */
269 typedef struct _state {
273 import_list_t*wildcard_imports;
275 char has_own_imports;
278 methodstate_t*method;
283 typedef struct _global {
290 static global_t*global = 0;
291 static state_t* state = 0;
295 #define MULTINAME(m,x) \
298 registry_fill_multiname(&m, &m##_ns, x);
300 #define MEMBER_MULTINAME(m,f,n) \
304 m##_ns.access = flags2access(f->flags); \
308 m.namespace_set = 0; \
311 m.type = MULTINAME; \
313 m.namespace_set = &nopackage_namespace_set; \
317 /* warning: list length of namespace set is undefined */
318 #define MULTINAME_LATE(m, access, package) \
319 namespace_t m##_ns = {access, package}; \
320 namespace_set_t m##_nsset; \
321 namespace_list_t m##_l;m##_l.next = 0; \
322 m##_nsset.namespaces = &m##_l; \
323 m##_nsset = m##_nsset; \
324 m##_l.namespace = &m##_ns; \
325 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
327 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
328 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
329 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
330 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
331 static namespace_list_t nl4 = {&ns4,0};
332 static namespace_list_t nl3 = {&ns3,&nl4};
333 static namespace_list_t nl2 = {&ns2,&nl3};
334 static namespace_list_t nl1 = {&ns1,&nl2};
335 static namespace_set_t nopackage_namespace_set = {&nl1};
337 static state_list_t*state_stack=0;
339 static void init_globals()
341 global = rfx_calloc(sizeof(global_t));
344 static void new_state()
347 NEW(state_list_t, sl);
349 state_t*oldstate = state;
351 memcpy(s, state, sizeof(state_t)); //shallow copy
352 sl->next = state_stack;
355 s->imports = dict_new();
360 state->has_own_imports = 0;
361 state->vars = dict_new();
363 static void state_has_imports()
365 state->wildcard_imports = list_clone(state->wildcard_imports);
366 state->imports = dict_clone(state->imports);
367 state->has_own_imports = 1;
370 static void old_state()
372 if(!state_stack || !state_stack->next)
373 syntaxerror("invalid nesting");
374 state_t*oldstate = state;
375 state_list_t*old = state_stack;
376 state_stack = state_stack->next;
378 state = state_stack->state;
379 /*if(state->method->initcode) {
380 printf("residual initcode\n");
381 code_dump(state->method->initcode, 0, 0, "", stdout);
383 if(oldstate->has_own_imports) {
384 list_free(oldstate->wildcard_imports);
385 dict_destroy(oldstate->imports);oldstate->imports=0;
388 void initialize_state()
393 global->file = abc_file_new();
394 global->file->flags &= ~ABCFILE_LAZY;
396 global->init = abc_initscript(global->file, 0);
397 code_t*c = global->init->method->body->code;
399 c = abc_getlocal_0(c);
400 c = abc_pushscope(c);
402 /* findpropstrict doesn't just return a scope object- it
403 also makes it "active" somehow. Push local_0 on the
404 scope stack and read it back with findpropstrict, it'll
405 contain properties like "trace". Trying to find the same
406 property on a "vanilla" local_0 yields only a "undefined" */
407 //c = abc_findpropstrict(c, "[package]::trace");
409 /*c = abc_getlocal_0(c);
410 c = abc_findpropstrict(c, "[package]::trace");
412 c = abc_setlocal_1(c);
414 c = abc_pushbyte(c, 0);
415 c = abc_setlocal_2(c);
417 code_t*xx = c = abc_label(c);
418 c = abc_findpropstrict(c, "[package]::trace");
419 c = abc_pushstring(c, "prop:");
420 c = abc_hasnext2(c, 1, 2);
422 c = abc_setlocal_3(c);
423 c = abc_callpropvoid(c, "[package]::trace", 2);
424 c = abc_getlocal_3(c);
426 c = abc_iftrue(c,xx);*/
428 c = abc_findpropstrict(c, "[package]::trace");
429 c = abc_pushstring(c, "[entering global init function]");
430 c = abc_callpropvoid(c, "[package]::trace", 1);
432 global->init->method->body->code = c;
434 void* finalize_state()
436 if(state->level!=1) {
437 syntaxerror("unexpected end of file");
439 abc_method_body_t*m = global->init->method->body;
442 __ findpropstrict(m, "[package]::trace");
443 __ pushstring(m, "[leaving global init function]");
444 __ callpropvoid(m, "[package]::trace", 1);
450 static void startpackage(char*name)
453 syntaxerror("Packages can not be nested.");
456 /*printf("entering package \"%s\"\n", name);*/
457 state->package = name;
459 static void endpackage()
461 /*printf("leaving package \"%s\"\n", state->package);*/
466 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
469 syntaxerror("inner classes now allowed");
472 state->cls = rfx_calloc(sizeof(classstate_t));
475 classinfo_list_t*mlist=0;
476 /*printf("entering class %s\n", name);
477 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
479 printf(" extends: %s.%s\n", extends->package, extends->name);
480 printf(" implements (%d): ", list_length(implements));
481 for(mlist=implements;mlist;mlist=mlist->next) {
482 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
487 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
488 syntaxerror("invalid modifier(s)");
490 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
491 syntaxerror("public and internal not supported at the same time.");
493 /* create the class name, together with the proper attributes */
497 if(!(flags&FLAG_PUBLIC) && !state->package) {
498 access = ACCESS_PRIVATE; package = current_filename;
499 } else if(!(flags&FLAG_PUBLIC) && state->package) {
500 access = ACCESS_PACKAGEINTERNAL; package = state->package;
501 } else if(state->package) {
502 access = ACCESS_PACKAGE; package = state->package;
504 syntaxerror("public classes only allowed inside a package");
507 if(registry_findclass(package, classname)) {
508 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
512 /* build info struct */
513 int num_interfaces = (list_length(implements));
514 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
515 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
517 classinfo_list_t*l = implements;
518 for(l=implements;l;l=l->next) {
519 state->cls->info->interfaces[pos++] = l->classinfo;
522 multiname_t*extends2 = sig2mname(extends);
524 MULTINAME(classname2,state->cls->info);
527 state->cls_init = abc_getlocal_0(state->cls_init);
528 state->cls_init = abc_constructsuper(state->cls_init, 0);
531 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
532 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
533 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
535 state->cls->info->flags |= CLASS_INTERFACE;
536 abc_class_interface(state->cls->abc);
539 abc_class_protectedNS(state->cls->abc, classname);
541 for(mlist=implements;mlist;mlist=mlist->next) {
542 MULTINAME(m, mlist->classinfo);
543 abc_class_add_interface(state->cls->abc, &m);
546 /* now write the construction code for this class */
547 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
549 abc_method_body_t*m = global->init->method->body;
550 __ getglobalscope(m);
551 classinfo_t*s = extends;
556 //TODO: take a look at the current scope stack, maybe
557 // we can re-use something
562 multiname_t*s2 = sig2mname(s);
564 multiname_destroy(s2);
566 __ pushscope(m); count++;
567 m->code = m->code->prev->prev; // invert
569 /* continue appending after last op end */
570 while(m->code && m->code->next) m->code = m->code->next;
572 /* TODO: if this is one of *our* classes, we can also
573 do a getglobalscope/getslot <nr> (which references
574 the init function's slots) */
576 __ getlex2(m, extends2);
578 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
579 stack is not the superclass */
580 __ pushscope(m);count++;
583 /* notice: we get a verify error #1107 if the top element on the scope
584 stack is not the global object */
586 __ pushscope(m);count++;
588 __ newclass(m,state->cls->abc);
592 __ setslot(m, slotindex);
594 /* flash.display.MovieClip handling */
595 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
596 if(state->package && state->package[0]) {
597 globalclass = concat3str(state->package, ".", classname);
599 globalclass = strdup(classname);
602 multiname_destroy(extends2);
605 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
607 c = code_append(c, initcode);
608 c = code_append(c, body);
609 /* append return if necessary */
610 if(!c || c->opcode != OPCODE_RETURNVOID &&
611 c->opcode != OPCODE_RETURNVALUE) {
612 c = abc_returnvoid(c);
617 static void endclass()
619 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
621 c = abc_getlocal_0(c);
622 c = abc_constructsuper(c, 0);
623 state->cls->init = code_append(state->cls->init, c);
626 if(state->cls->init) {
627 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
628 m->body->code = wrap_function(0, state->cls->init, m->body->code);
630 if(state->cls->static_init) {
631 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
632 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
634 // handy for scope testing
638 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
644 typedef struct _variable {
649 static int find_variable(char*name, classinfo_t**m)
651 state_list_t* s = state_stack;
655 v = dict_lookup(s->state->vars, name);
666 static int find_variable_safe(char*name, classinfo_t**m)
668 int i = find_variable(name, m);
670 syntaxerror("undefined variable: %s", name);
673 static char variable_exists(char*name)
675 return dict_lookup(state->vars, name)!=0;
677 static int new_variable(char*name, classinfo_t*type)
680 v->index = global->variable_count;
682 dict_put(state->vars, name, v);
683 return global->variable_count++;
685 #define TEMPVARNAME "__as3_temp__"
686 static int gettempvar()
688 int i = find_variable(TEMPVARNAME, 0);
690 i = new_variable(TEMPVARNAME, 0);
695 code_t* killvars(code_t*c)
698 for(t=0;t<state->vars->hashsize;t++) {
699 dictentry_t*e =state->vars->slots[t];
701 variable_t*v = (variable_t*)e->data;
702 //do this always, otherwise register types don't match
703 //in the verifier when doing nested loops
704 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
705 c = abc_kill(c, v->index);
713 static void check_constant_against_type(classinfo_t*t, constant_t*c)
715 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
716 if(TYPE_IS_NUMBER(t)) {
717 xassert(c->type == CONSTANT_FLOAT
718 || c->type == CONSTANT_INT
719 || c->type == CONSTANT_UINT);
720 } else if(TYPE_IS_UINT(t)) {
721 xassert(c->type == CONSTANT_UINT ||
722 (c->type == CONSTANT_INT && c->i>0));
723 } else if(TYPE_IS_INT(t)) {
724 xassert(c->type == CONSTANT_INT);
725 } else if(TYPE_IS_BOOLEAN(t)) {
726 xassert(c->type == CONSTANT_TRUE
727 || c->type == CONSTANT_FALSE);
731 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
733 memberinfo_t*minfo = 0;
734 if(getset != KW_GET && getset != KW_SET) {
735 if(registry_findmember(state->cls->info, name)) {
736 syntaxerror("class already contains a member/method called '%s'", name);
738 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
739 minfo->return_type = return_type;
740 // getslot on a member slot only returns "undefined", so no need
741 // to actually store these
742 //state->minfo->slot = state->method->abc->method->trait->slot_id;
744 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
748 else if(params->list)
749 type = params->list->param->type;
750 if((minfo=registry_findmember(state->cls->info, name))) {
751 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
752 syntaxerror("class already contains a member or method called '%s'", name);
754 syntaxerror("getter/setter for '%s' already defined", name);
755 /* make a setter or getter into a getset */
760 if(type && minfo->type != type)
761 syntaxerror("different type in getter and setter");
763 minfo = memberinfo_register(state->cls->info, name, gs);
766 /* can't assign a slot as getter and setter might have different slots */
767 //minfo->slot = slot;
769 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
770 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
771 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
772 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
773 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
777 static int flags2access(int flags)
780 if(flags&FLAG_PUBLIC) {
781 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
782 access = ACCESS_PACKAGE;
783 } else if(flags&FLAG_PRIVATE) {
784 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
785 access = ACCESS_PRIVATE;
786 } else if(flags&FLAG_PROTECTED) {
787 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
788 access = ACCESS_PROTECTED;
790 access = ACCESS_PACKAGEINTERNAL;
795 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
796 params_t*params, classinfo_t*return_type)
799 syntaxerror("not able to start another method scope");
802 state->method = rfx_calloc(sizeof(methodstate_t));
803 state->method->initcode = 0;
804 state->method->is_constructor = !strcmp(state->cls->info->name,name);
805 state->method->has_super = 0;
807 state->cls->has_constructor |= state->method->is_constructor;
809 global->variable_count = 0;
811 /* state->vars is initialized by state_new */
812 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
814 for(p=params->list;p;p=p->next) {
815 new_variable(p->param->name, p->param->type);
817 if(state->method->is_constructor)
818 name = "__as3_constructor__";
819 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
822 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
823 params_t*params, classinfo_t*return_type, code_t*body)
825 namespace_t mname_ns = {flags2access(flags), ""};
826 multiname_t mname = {QNAME, &mname_ns, 0, name};
830 multiname_t*type2 = sig2mname(return_type);
832 if(state->method->is_constructor) {
833 f = abc_class_getconstructor(state->cls->abc, type2);
835 if(flags&FLAG_STATIC)
836 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
838 f = abc_class_method(state->cls->abc, type2, &mname);
839 slot = f->trait->slot_id;
841 //flash doesn't seem to allow us to access function slots
842 //state->method->info->slot = slot;
844 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
845 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
846 if(params->varargs) f->flags |= METHOD_NEED_REST;
850 for(p=params->list;p;p=p->next) {
851 if(params->varargs && !p->next) {
852 break; //varargs: omit last parameter in function signature
854 multiname_t*m = sig2mname(p->param->type);
855 list_append(f->parameters, m);
856 if(p->param->value) {
857 check_constant_against_type(p->param->type, p->param->value);
858 opt=1;list_append(f->optional_parameters, p->param->value);
860 syntaxerror("non-optional parameter not allowed after optional parameters");
863 f->body->code = body;
870 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
875 void breakjumpsto(code_t*c, char*name, code_t*jump)
878 if(c->opcode == OPCODE___BREAK__) {
879 c->opcode = OPCODE_JUMP;
885 void continuejumpsto(code_t*c, char*name, code_t*jump)
888 if(c->opcode == OPCODE___CONTINUE__) {
889 c->opcode = OPCODE_JUMP;
896 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
899 return registry_getanytype();
900 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
901 return registry_getanytype();
904 return registry_getanytype();
906 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
911 return abc_coerce_a(c);
915 // cast an "any" type to a specific type. subject to
916 // runtime exceptions
917 return abc_coerce2(c, &m);
920 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
921 return abc_coerce2(c, &m);
923 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
924 return abc_coerce2(c, &m);
926 /* these are subject to overflow */
927 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
928 return abc_coerce2(c, &m);
930 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
931 return abc_coerce2(c, &m);
934 classinfo_t*supertype = from;
936 if(supertype == to) {
937 // target type is one of from's superclasses
938 return abc_coerce2(c, &m);
941 while(supertype->interfaces[t]) {
942 if(supertype->interfaces[t]==to) {
943 // to type is one of from's interfaces
944 return abc_coerce2(c, &m);
948 supertype = supertype->superclass;
950 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
952 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
954 syntaxerror("can't convert type %s to %s", from->name, to->name);
957 code_t*defaultvalue(code_t*c, classinfo_t*type)
959 if(TYPE_IS_INT(type)) {
960 c = abc_pushbyte(c, 0);
961 } else if(TYPE_IS_UINT(type)) {
962 c = abc_pushuint(c, 0);
963 } else if(TYPE_IS_FLOAT(type)) {
965 } else if(TYPE_IS_BOOLEAN(type)) {
966 c = abc_pushfalse(c);
973 char is_pushundefined(code_t*c)
975 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
978 void parserassert(int b)
980 if(!b) syntaxerror("internal error: assertion failed");
983 static classinfo_t* find_class(char*name)
987 c = registry_findclass(state->package, name);
989 /* try explicit imports */
990 dictentry_t* e = dict_get_slot(state->imports, name);
994 if(!strcmp(e->key, name)) {
995 c = (classinfo_t*)e->data;
1000 /* try package.* imports */
1001 import_list_t*l = state->wildcard_imports;
1005 //printf("does package %s contain a class %s?\n", l->import->package, name);
1006 c = registry_findclass(l->import->package, name);
1010 /* try global package */
1012 c = registry_findclass("", name);
1017 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1021 [prefix code] [read instruction]
1025 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1028 if(in && in->opcode == OPCODE_COERCE_A) {
1029 in = code_cutlast(in);
1032 syntaxerror("internal error");
1034 /* chop off read instruction */
1038 prefix = r->prev;r->prev = 0;
1044 char use_temp_var = readbefore;
1046 /* generate the write instruction, and maybe append a dup to the prefix code */
1047 code_t* write = abc_nop(0);
1048 if(r->opcode == OPCODE_GETPROPERTY) {
1049 write->opcode = OPCODE_SETPROPERTY;
1050 multiname_t*m = (multiname_t*)r->data[0];
1051 write->data[0] = multiname_clone(m);
1052 if(m->type == QNAME || m->type == MULTINAME) {
1054 prefix = abc_dup(prefix); // we need the object, too
1057 } else if(m->type == MULTINAMEL) {
1059 /* dupping two values on the stack requires 5 operations and one register-
1060 couldn't adobe just have given us a dup2? */
1061 int temp = gettempvar();
1062 prefix = abc_setlocal(prefix, temp);
1063 prefix = abc_dup(prefix);
1064 prefix = abc_getlocal(prefix, temp);
1065 prefix = abc_swap(prefix);
1066 prefix = abc_getlocal(prefix, temp);
1070 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1072 } else if(r->opcode == OPCODE_GETSLOT) {
1073 write->opcode = OPCODE_SETSLOT;
1074 write->data[0] = r->data[0];
1076 prefix = abc_dup(prefix); // we need the object, too
1079 } else if(r->opcode == OPCODE_GETLOCAL) {
1080 write->opcode = OPCODE_SETLOCAL;
1081 write->data[0] = r->data[0];
1082 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1083 write->opcode = OPCODE_SETLOCAL_0;
1084 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1085 write->opcode = OPCODE_SETLOCAL_1;
1086 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1087 write->opcode = OPCODE_SETLOCAL_2;
1088 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1089 write->opcode = OPCODE_SETLOCAL_3;
1091 code_dump(r, 0, 0, "", stdout);
1092 syntaxerror("illegal lvalue: can't assign a value to this expression");
1099 /* with getproperty/getslot, we have to be extra careful not
1100 to execute the read code twice, as it might have side-effects
1101 (e.g. if the property is in fact a setter/getter combination)
1103 So read the value, modify it, and write it again,
1104 using prefix only once and making sure (by using a temporary
1105 register) that the return value is what we just wrote */
1106 temp = gettempvar();
1107 c = code_append(c, prefix);
1108 c = code_append(c, r);
1111 c = abc_setlocal(c, temp);
1113 c = code_append(c, middlepart);
1116 c = abc_setlocal(c, temp);
1118 c = code_append(c, write);
1119 c = abc_getlocal(c, temp);
1120 c = abc_kill(c, temp);
1122 /* if we're allowed to execute the read code twice *and*
1123 the middlepart doesn't modify the code, things are easier.
1125 code_t* r2 = code_dup(r);
1126 //c = code_append(c, prefix);
1127 parserassert(!prefix);
1128 c = code_append(c, r);
1129 c = code_append(c, middlepart);
1130 c = code_append(c, write);
1131 c = code_append(c, r2);
1134 /* even smaller version: overwrite the value without reading
1138 c = code_append(c, prefix);
1141 c = code_append(c, middlepart);
1142 c = code_append(c, write);
1143 c = code_append(c, r);
1145 temp = gettempvar();
1147 c = code_append(c, prefix);
1150 c = code_append(c, middlepart);
1152 c = abc_setlocal(c, temp);
1153 c = code_append(c, write);
1154 c = abc_getlocal(c, temp);
1161 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1162 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1169 /* ------------ code blocks / statements ---------------- */
1173 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1174 MAYBECODE: {$$=code_new();}
1176 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1177 CODE: CODEPIECE {$$=$1;}
1179 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1180 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1181 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1182 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1183 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1184 CODEPIECE: ';' {$$=code_new();}
1185 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1186 CODEPIECE: VOIDEXPRESSION {$$=$1}
1187 CODEPIECE: FOR {$$=$1}
1188 CODEPIECE: WHILE {$$=$1}
1189 CODEPIECE: DO_WHILE {$$=$1}
1190 CODEPIECE: BREAK {$$=$1}
1191 CODEPIECE: CONTINUE {$$=$1}
1192 CODEPIECE: RETURN {$$=$1}
1193 CODEPIECE: IF {$$=$1}
1194 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1195 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1197 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1198 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1199 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1201 /* ------------ variables --------------------------- */
1203 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1204 | {$$.c=abc_pushundefined(0);
1208 VAR : "const" | "var"
1209 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1211 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1212 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1214 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1216 if(variable_exists($2))
1217 syntaxerror("Variable %s already defined", $2);
1219 if(!is_subtype_of($4.t, $3)) {
1220 syntaxerror("Can't convert %s to %s", $4.t->name,
1224 int index = new_variable($2, $3);
1227 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1229 $$ = converttype($$, $4.t, $3);
1230 $$ = abc_setlocal($$, index);
1232 $$ = defaultvalue(0, $3);
1233 $$ = abc_setlocal($$, index);
1236 /* if this is a typed variable:
1237 push default value for type on stack */
1239 state->method->initcode = defaultvalue(state->method->initcode, $3);
1240 state->method->initcode = abc_setlocal(state->method->initcode, index);
1243 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1245 $$ = abc_coerce_a($$);
1246 $$ = abc_setlocal($$, index);
1252 /* that's the default for a local register, anyway
1254 state->method->initcode = abc_pushundefined(state->method->initcode);
1255 state->method->initcode = abc_setlocal(state->method->initcode, index);
1257 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1260 /* ------------ control flow ------------------------- */
1262 MAYBEELSE: %prec below_else {$$ = code_new();}
1263 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1264 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1266 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1268 $$ = code_append($$, $4.c);
1269 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1271 $$ = code_append($$, $6);
1273 myjmp = $$ = abc_jump($$, 0);
1275 myif->branch = $$ = abc_nop($$);
1277 $$ = code_append($$, $7);
1278 myjmp->branch = $$ = abc_nop($$);
1281 $$ = killvars($$);old_state();
1284 MAYBELABEL : T_IDENTIFIER ':' {$$=$1;}
1285 MAYBELABEL : {$$="";}
1287 FOR_INIT : {$$=code_new();}
1288 FOR_INIT : VARIABLE_DECLARATION
1289 FOR_INIT : VOIDEXPRESSION
1291 FOR : MAYBELABEL "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1293 $$ = code_append($$, $5);
1294 code_t*loopstart = $$ = abc_label($$);
1295 $$ = code_append($$, $7.c);
1296 code_t*myif = $$ = abc_iffalse($$, 0);
1297 $$ = code_append($$, $11);
1298 code_t*cont = $$ = abc_nop($$);
1299 $$ = code_append($$, $9);
1300 $$ = abc_jump($$, loopstart);
1301 code_t*out = $$ = abc_nop($$);
1302 breakjumpsto($$, $1, out);
1303 continuejumpsto($$, $1, cont);
1306 $$ = killvars($$);old_state();
1309 WHILE : MAYBELABEL "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1312 code_t*myjmp = $$ = abc_jump($$, 0);
1313 code_t*loopstart = $$ = abc_label($$);
1314 $$ = code_append($$, $7);
1315 myjmp->branch = $$ = abc_nop($$);
1316 $$ = code_append($$, $5.c);
1317 $$ = abc_iftrue($$, loopstart);
1318 code_t*out = $$ = abc_nop($$);
1319 breakjumpsto($$, $1, out);
1320 continuejumpsto($$, $1, loopstart);
1326 DO_WHILE : MAYBELABEL "do" {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1328 code_t*loopstart = $$ = abc_label($$);
1329 $$ = code_append($$, $4);
1330 code_t*cont = $$ = abc_nop($$);
1331 $$ = code_append($$, $7.c);
1332 $$ = abc_iftrue($$, loopstart);
1333 code_t*out = $$ = abc_nop($$);
1334 breakjumpsto($$, $1, out);
1335 continuejumpsto($$, $1, cont);
1340 BREAK : "break" %prec prec_none {
1341 $$ = abc___break__(0, "");
1343 BREAK : "break" T_IDENTIFIER {
1344 $$ = abc___break__(0, $2);
1346 CONTINUE : "continue" %prec prec_none {
1347 $$ = abc___continue__(0, "");
1349 CONTINUE : "continue" T_IDENTIFIER {
1350 $$ = abc___continue__(0, $2);
1353 /* ------------ packages and imports ---------------- */
1355 X_IDENTIFIER: T_IDENTIFIER
1356 | "package" {$$="package";}
1358 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1359 PACKAGE: X_IDENTIFIER {$$=$1;}
1361 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1362 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1364 IMPORT : "import" QNAME {
1367 syntaxerror("Couldn't import class\n");
1368 state_has_imports();
1369 dict_put(state->imports, c->name, c);
1372 IMPORT : "import" PACKAGE '.' '*' {
1375 state_has_imports();
1376 list_append(state->wildcard_imports, i);
1380 /* ------------ classes and interfaces (header) -------------- */
1382 MAYBE_MODIFIERS : {$$=0;}
1383 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1384 MODIFIER_LIST : MODIFIER {$$=$1;}
1385 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1387 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1388 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1389 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1390 | KW_STATIC {$$=FLAG_STATIC;}
1391 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1392 | KW_FINAL {$$=FLAG_FINAL;}
1393 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1394 | KW_NATIVE {$$=FLAG_NATIVE;}
1395 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1397 EXTENDS : {$$=registry_getobjectclass();}
1398 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1400 EXTENDS_LIST : {$$=list_new();}
1401 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1403 IMPLEMENTS_LIST : {$$=list_new();}
1404 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1406 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1407 EXTENDS IMPLEMENTS_LIST
1408 '{' {startclass($1,$3,$4,$5, 0);}
1409 MAYBE_DECLARATION_LIST
1412 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1414 '{' {startclass($1,$3,0,$4,1);}
1415 MAYBE_IDECLARATION_LIST
1418 /* ------------ classes and interfaces (body) -------------- */
1420 MAYBE_DECLARATION_LIST :
1421 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1422 DECLARATION_LIST : DECLARATION
1423 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1425 DECLARATION : SLOT_DECLARATION
1426 DECLARATION : FUNCTION_DECLARATION
1428 MAYBE_IDECLARATION_LIST :
1429 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1430 IDECLARATION_LIST : IDECLARATION
1431 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1433 IDECLARATION : "var" T_IDENTIFIER {
1434 syntaxerror("variable declarations not allowed in interfaces");
1436 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1438 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1439 syntaxerror("invalid method modifiers: interface methods always need to be public");
1441 startfunction(0,$1,$3,$4,&$6,$8);
1442 endfunction(0,$1,$3,$4,&$6,$8, 0);
1445 /* ------------ classes and interfaces (body, slots ) ------- */
1447 VARCONST: "var" | "const"
1449 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1451 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1453 info->flags = flags;
1456 namespace_t mname_ns = {flags2access(flags), ""};
1457 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1459 if(!(flags&FLAG_STATIC)) {
1462 t=abc_class_slot(state->cls->abc, &mname, &m);
1464 t=abc_class_slot(state->cls->abc, &mname, 0);
1466 info->slot = t->slot_id;
1470 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1472 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1474 info->slot = t->slot_id;
1476 if($5.c && !is_pushundefined($5.c)) {
1478 c = abc_getlocal_0(c);
1479 c = code_append(c, $5.c);
1480 c = converttype(c, $5.t, $4);
1481 c = abc_setslot(c, t->slot_id);
1482 if(!(flags&FLAG_STATIC))
1483 state->cls->init = code_append(state->cls->init, c);
1485 state->cls->static_init = code_append(state->cls->static_init, c);
1488 t->kind= TRAIT_CONST;
1492 /* ------------ constants -------------------------------------- */
1494 MAYBESTATICCONSTANT: {$$=0;}
1495 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1497 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1498 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1499 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1500 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1501 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1502 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1503 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1504 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1505 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1507 /* ------------ classes and interfaces (body, functions) ------- */
1509 // non-vararg version
1511 memset(&$$,0,sizeof($$));
1513 MAYBE_PARAM_LIST: PARAM_LIST {
1518 MAYBE_PARAM_LIST: "..." PARAM {
1519 memset(&$$,0,sizeof($$));
1521 list_append($$.list, $2);
1523 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1526 list_append($$.list, $4);
1530 PARAM_LIST: PARAM_LIST ',' PARAM {
1532 list_append($$.list, $3);
1535 memset(&$$,0,sizeof($$));
1536 list_append($$.list, $1);
1539 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1540 $$ = malloc(sizeof(param_t));
1545 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1546 $$ = malloc(sizeof(param_t));
1548 $$->type = TYPE_ANY;
1551 GETSET : "get" {$$=$1;}
1555 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1556 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1559 if(state->method->late_binding) {
1560 c = abc_getlocal_0(c);
1561 c = abc_pushscope(c);
1563 if(state->method->is_constructor && !state->method->has_super) {
1564 // call default constructor
1565 c = abc_getlocal_0(c);
1566 c = abc_constructsuper(c, 0);
1568 c = wrap_function(c, state->method->initcode, $11);
1569 endfunction(0,$1,$3,$4,&$6,$8,c);
1572 /* ------------- package + class ids --------------- */
1574 CLASS: T_IDENTIFIER {
1576 /* try current package */
1577 $$ = find_class($1);
1578 if(!$$) syntaxerror("Could not find class %s\n", $1);
1581 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1582 $$ = registry_findclass($1, $3);
1583 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1586 QNAME: PACKAGEANDCLASS
1589 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1590 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1592 TYPE : QNAME {$$=$1;}
1593 | '*' {$$=registry_getanytype();}
1595 | "String" {$$=registry_getstringclass();}
1596 | "int" {$$=registry_getintclass();}
1597 | "uint" {$$=registry_getuintclass();}
1598 | "Boolean" {$$=registry_getbooleanclass();}
1599 | "Number" {$$=registry_getnumberclass();}
1602 MAYBETYPE: ':' TYPE {$$=$2;}
1605 /* ----------function calls, delete, constructor calls ------ */
1607 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1608 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1610 MAYBE_EXPRESSION_LIST : {$$=0;}
1611 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1612 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1613 typedcode_t*t = malloc(sizeof(typedcode_t));
1615 list_append($$, t);}
1616 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1617 typedcode_t*t = malloc(sizeof(typedcode_t));
1619 list_append($$, t);}
1621 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1626 $$.c = abc_getglobalscope($$.c);
1627 $$.c = abc_getslot($$.c, $2->slot);
1629 $$.c = abc_findpropstrict2($$.c, &m);
1632 typedcode_list_t*l = $3;
1635 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1640 $$.c = abc_construct($$.c, len);
1642 $$.c = abc_constructprop2($$.c, &m, len);
1646 /* TODO: use abc_call (for calling local variables),
1647 abc_callstatic (for calling own methods)
1650 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1651 typedcode_list_t*l = $3;
1653 code_t*paramcode = 0;
1655 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1661 if($$.c->opcode == OPCODE_COERCE_A) {
1662 $$.c = code_cutlast($$.c);
1666 multiname_t*name = 0;
1667 if($$.c->opcode == OPCODE_GETPROPERTY) {
1668 name = multiname_clone($$.c->data[0]);
1669 $$.c = code_cutlast($$.c);
1670 $$.c = code_append($$.c, paramcode);
1671 $$.c = abc_callproperty2($$.c, name, len);
1672 } else if($$.c->opcode == OPCODE_GETSLOT) {
1673 int slot = (int)(ptroff_t)$$.c->data[0];
1674 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1675 if(t->kind!=TRAIT_METHOD) {
1676 //ok: flash allows to assign closures to members.
1679 $$.c = code_cutlast($$.c);
1680 $$.c = code_append($$.c, paramcode);
1681 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1682 $$.c = abc_callproperty2($$.c, name, len);
1683 } else if($$.c->opcode == OPCODE_GETSUPER) {
1684 name = multiname_clone($$.c->data[0]);
1685 $$.c = code_cutlast($$.c);
1686 $$.c = code_append($$.c, paramcode);
1687 $$.c = abc_callsuper2($$.c, name, len);
1689 $$.c = abc_getlocal_0($$.c);
1690 $$.c = code_append($$.c, paramcode);
1691 $$.c = abc_call($$.c, len);
1696 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1697 $$.t = $1.t->function->return_type;
1699 $$.c = abc_coerce_a($$.c);
1703 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1704 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1705 if(!state->method) syntaxerror("super() not allowed outside of a function");
1706 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1709 $$.c = abc_getlocal_0($$.c);
1710 typedcode_list_t*l = 0;
1712 for(l=$3;l;l=l->next) {
1713 $$.c = code_append($$.c, l->typedcode->c);len++;
1716 this is dependent on the control path, check this somewhere else
1717 if(state->method->has_super)
1718 syntaxerror("constructor may call super() only once");
1720 state->method->has_super = 1;
1721 $$.c = abc_constructsuper($$.c, len);
1722 $$.c = abc_pushundefined($$.c);
1726 DELETE: "delete" E {
1728 if($$.c->opcode == OPCODE_COERCE_A) {
1729 $$.c = code_cutlast($$.c);
1731 multiname_t*name = 0;
1732 if($$.c->opcode == OPCODE_GETPROPERTY) {
1733 $$.c->opcode = OPCODE_DELETEPROPERTY;
1734 } else if($$.c->opcode == OPCODE_GETSLOT) {
1735 int slot = (int)(ptroff_t)$$.c->data[0];
1736 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1737 $$.c = code_cutlast($$.c);
1738 $$.c = abc_deleteproperty2($$.c, name);
1740 $$.c = abc_getlocal_0($$.c);
1741 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1742 $$.c = abc_deleteproperty2($$.c, &m);
1744 $$.t = TYPE_BOOLEAN;
1747 RETURN: "return" %prec prec_none {
1748 $$ = abc_returnvoid(0);
1750 RETURN: "return" EXPRESSION {
1752 $$ = abc_returnvalue($$);
1755 // ----------------------- expression types -------------------------------------
1757 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1758 EXPRESSION : E %prec below_minus {$$ = $1;}
1759 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1761 $$.c = cut_last_push($$.c);
1762 $$.c = code_append($$.c,$3.c);
1765 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1766 $$=cut_last_push($1.c);
1769 // ----------------------- expression evaluation -------------------------------------
1772 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1774 E : DELETE {$$ = $1;}
1775 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1779 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1780 //MULTINAME(m, registry_getintclass());
1781 //$$.c = abc_coerce2($$.c, &m); // FIXME
1784 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1787 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1790 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1793 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1796 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1799 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1802 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1803 $$.t = TYPE_BOOLEAN;
1805 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1806 $$.t = TYPE_BOOLEAN;
1808 CONSTANT : "null" {$$.c = abc_pushnull(0);
1813 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1814 $$.t = TYPE_BOOLEAN;
1816 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1817 $$.t = TYPE_BOOLEAN;
1819 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1820 $$.t = TYPE_BOOLEAN;
1822 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1823 $$.t = TYPE_BOOLEAN;
1825 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1826 $$.t = TYPE_BOOLEAN;
1828 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1829 $$.t = TYPE_BOOLEAN;
1831 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1832 $$.t = TYPE_BOOLEAN;
1834 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1835 $$.t = TYPE_BOOLEAN;
1838 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1840 $$.c = converttype($$.c, $1.t, $$.t);
1841 $$.c = abc_dup($$.c);
1842 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1843 $$.c = cut_last_push($$.c);
1844 $$.c = code_append($$.c,$3.c);
1845 $$.c = converttype($$.c, $3.t, $$.t);
1846 code_t*label = $$.c = abc_label($$.c);
1847 jmp->branch = label;
1850 $$.t = join_types($1.t, $3.t, 'A');
1851 /*printf("%08x:\n",$1.t);
1852 code_dump($1.c, 0, 0, "", stdout);
1853 printf("%08x:\n",$3.t);
1854 code_dump($3.c, 0, 0, "", stdout);
1855 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1857 $$.c = converttype($$.c, $1.t, $$.t);
1858 $$.c = abc_dup($$.c);
1859 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1860 $$.c = cut_last_push($$.c);
1861 $$.c = code_append($$.c,$3.c);
1862 $$.c = converttype($$.c, $3.t, $$.t);
1863 code_t*label = $$.c = abc_label($$.c);
1864 jmp->branch = label;
1867 E : '!' E {$$.c=$2.c;
1868 $$.c = abc_not($$.c);
1869 $$.t = TYPE_BOOLEAN;
1872 E : '~' E {$$.c=$2.c;
1873 $$.c = abc_bitnot($$.c);
1877 E : E '&' E {$$.c = code_append($1.c,$3.c);
1878 $$.c = abc_bitand($$.c);
1882 E : E '^' E {$$.c = code_append($1.c,$3.c);
1883 $$.c = abc_bitxor($$.c);
1887 E : E '|' E {$$.c = code_append($1.c,$3.c);
1888 $$.c = abc_bitor($$.c);
1892 E : E '-' E {$$.c = code_append($1.c,$3.c);
1893 if(BOTH_INT($1,$3)) {
1894 $$.c = abc_subtract_i($$.c);
1897 $$.c = abc_subtract($$.c);
1901 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1902 $$.c = abc_rshift($$.c);
1905 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1906 $$.c = abc_urshift($$.c);
1909 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1910 $$.c = abc_lshift($$.c);
1914 E : E '/' E {$$.c = code_append($1.c,$3.c);
1915 $$.c = abc_divide($$.c);
1918 E : E '+' E {$$.c = code_append($1.c,$3.c);
1919 $$.c = abc_add($$.c);
1922 E : E '%' E {$$.c = code_append($1.c,$3.c);
1923 $$.c = abc_modulo($$.c);
1926 E : E '*' E {$$.c = code_append($1.c,$3.c);
1927 if(BOTH_INT($1,$3)) {
1928 $$.c = abc_multiply_i($$.c);
1931 $$.c = abc_multiply($$.c);
1936 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1937 if(use_astype && TYPE_IS_CLASS($3.t)) {
1938 MULTINAME(m,$3.t->cls);
1939 $$.c = abc_astype2($1.c, &m);
1942 $$.c = code_append($1.c, $3.c);
1943 $$.c = abc_astypelate($$.c);
1948 E : E "instanceof" E
1949 {$$.c = code_append($1.c, $3.c);
1950 $$.c = abc_instanceof($$.c);
1951 $$.t = TYPE_BOOLEAN;
1954 E : E "is" E {$$.c = code_append($1.c, $3.c);
1955 $$.c = abc_istypelate($$.c);
1956 $$.t = TYPE_BOOLEAN;
1959 E : "typeof" '(' E ')' {
1961 $$.c = abc_typeof($$.c);
1966 $$.c = cut_last_push($2.c);
1967 $$.c = abc_pushundefined($$.c);
1971 E : "void" { $$.c = abc_pushundefined(0);
1975 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
1980 $$.c=abc_negate_i($$.c);
1983 $$.c=abc_negate($$.c);
1990 $$.c = code_append($$.c, $3.c);
1992 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1993 $$.c = abc_getproperty2($$.c, &m);
1994 $$.t = 0; // array elements have unknown type
1997 E : '[' MAYBE_EXPRESSION_LIST ']' {
1999 typedcode_list_t*l = 0;
2001 for(l=$2;l;l=l->next) {
2002 $$.c = code_append($$.c, l->typedcode->c);len++;
2004 $$.c = abc_newarray($$.c, len);
2005 $$.t = registry_getarrayclass();
2010 if(BOTH_INT($1,$3)) {
2011 c=abc_multiply_i(c);
2015 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2016 $$.c = toreadwrite($1.c, c, 0, 0);
2021 code_t*c = abc_modulo($3.c);
2022 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2023 $$.c = toreadwrite($1.c, c, 0, 0);
2027 code_t*c = abc_lshift($3.c);
2028 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2029 $$.c = toreadwrite($1.c, c, 0, 0);
2033 code_t*c = abc_rshift($3.c);
2034 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2035 $$.c = toreadwrite($1.c, c, 0, 0);
2039 code_t*c = abc_urshift($3.c);
2040 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2041 $$.c = toreadwrite($1.c, c, 0, 0);
2045 code_t*c = abc_divide($3.c);
2046 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2047 $$.c = toreadwrite($1.c, c, 0, 0);
2052 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2057 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2059 $$.c = toreadwrite($1.c, c, 0, 0);
2062 E : E "-=" E { code_t*c = $3.c;
2063 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2064 c=abc_subtract_i(c);
2068 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2070 $$.c = toreadwrite($1.c, c, 0, 0);
2073 E : E '=' E { code_t*c = 0;
2074 c = code_append(c, $3.c);
2075 c = converttype(c, $3.t, $1.t);
2076 $$.c = toreadwrite($1.c, c, 1, 0);
2080 E : E '?' E ':' E %prec below_assignment {
2082 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2083 $$.c = code_append($$.c, $3.c);
2084 code_t*j2 = $$.c = abc_jump($$.c, 0);
2085 $$.c = j1->branch = abc_label($$.c);
2086 $$.c = code_append($$.c, $5.c);
2087 $$.c = j2->branch = abc_label($$.c);
2088 $$.t = join_types($3.t,$5.t,'?');
2091 // TODO: use inclocal where appropriate
2092 E : E "++" { code_t*c = 0;
2093 classinfo_t*type = $1.t;
2094 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2095 c=abc_increment_i(c);
2101 c=converttype(c, type, $1.t);
2102 $$.c = toreadwrite($1.c, c, 0, 1);
2105 E : E "--" { code_t*c = 0;
2106 classinfo_t*type = $1.t;
2107 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2108 c=abc_decrement_i(c);
2114 c=converttype(c, type, $1.t);
2115 $$.c = toreadwrite($1.c, c, 0, 1);
2119 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2120 classinfo_t*type = $2.t;
2121 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2122 c=abc_increment_i(c);
2128 c=converttype(c, type, $2.t);
2129 $$.c = toreadwrite($2.c, c, 0, 0);
2133 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2134 classinfo_t*type = $2.t;
2135 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2136 c=abc_decrement_i(c);
2142 c=converttype(c, type, $2.t);
2143 $$.c = toreadwrite($2.c, c, 0, 0);
2147 E : "super" '.' T_IDENTIFIER
2148 { if(!state->cls->info)
2149 syntaxerror("super keyword not allowed outside a class");
2150 classinfo_t*t = state->cls->info->superclass;
2151 if(!t) t = TYPE_OBJECT;
2153 memberinfo_t*f = registry_findmember(t, $3);
2154 namespace_t ns = {flags2access(f->flags), ""};
2155 MEMBER_MULTINAME(m, f, $3);
2157 $$.c = abc_getlocal_0($$.c);
2158 $$.c = abc_getsuper2($$.c, &m);
2159 $$.t = memberinfo_gettype(f);
2162 E : E '.' T_IDENTIFIER
2164 classinfo_t*t = $1.t;
2166 if(TYPE_IS_CLASS(t) && t->cls) {
2171 memberinfo_t*f = registry_findmember(t, $3);
2173 if(f && !is_static != !(f->flags&FLAG_STATIC))
2175 if(f && f->slot && !noslot) {
2176 $$.c = abc_getslot($$.c, f->slot);
2178 MEMBER_MULTINAME(m, f, $3);
2179 $$.c = abc_getproperty2($$.c, &m);
2181 /* determine type */
2182 $$.t = memberinfo_gettype(f);
2184 $$.c = abc_coerce_a($$.c);
2186 /* when resolving a property on an unknown type, we do know the
2187 name of the property (and don't seem to need the package), but
2188 we need to make avm2 try out all access modes */
2189 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2190 $$.c = abc_getproperty2($$.c, &m);
2191 $$.c = abc_coerce_a($$.c);
2192 $$.t = registry_getanytype();
2196 VAR_READ : T_IDENTIFIER {
2203 /* look at variables */
2204 if((i = find_variable($1, &$$.t)) >= 0) {
2205 // $1 is a local variable
2206 $$.c = abc_getlocal($$.c, i);
2208 /* look at current class' members */
2209 } else if((f = registry_findmember(state->cls->info, $1))) {
2210 // $1 is a function in this class
2211 int var_is_static = (f->flags&FLAG_STATIC);
2212 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2213 if(var_is_static != i_am_static) {
2214 /* there doesn't seem to be any "static" way to access
2215 static properties of a class */
2216 state->method->late_binding = 1;
2218 namespace_t ns = {flags2access(f->flags), ""};
2219 multiname_t m = {QNAME, &ns, 0, $1};
2220 $$.c = abc_findpropstrict2($$.c, &m);
2221 $$.c = abc_getproperty2($$.c, &m);
2224 $$.c = abc_getlocal_0($$.c);
2225 $$.c = abc_getslot($$.c, f->slot);
2227 namespace_t ns = {flags2access(f->flags), ""};
2228 multiname_t m = {QNAME, &ns, 0, $1};
2229 $$.c = abc_getlocal_0($$.c);
2230 $$.c = abc_getproperty2($$.c, &m);
2233 if(f->kind == MEMBER_METHOD) {
2234 $$.t = TYPE_FUNCTION(f);
2239 /* look at classes in the current package and imported classes */
2240 } else if((a = find_class($1))) {
2241 if(a->flags & FLAG_METHOD) {
2243 $$.c = abc_findpropstrict2($$.c, &m);
2244 $$.c = abc_getproperty2($$.c, &m);
2245 $$.t = TYPE_FUNCTION(a->function);
2248 $$.c = abc_getglobalscope($$.c);
2249 $$.c = abc_getslot($$.c, a->slot);
2252 $$.c = abc_getlex2($$.c, &m);
2254 $$.t = TYPE_CLASS(a);
2257 /* unknown object, let the avm2 resolve it */
2259 if(strcmp($1,"trace"))
2260 warning("Couldn't resolve '%s', doing late binding", $1);
2261 state->method->late_binding = 1;
2263 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2266 $$.c = abc_findpropstrict2($$.c, &m);
2267 $$.c = abc_getproperty2($$.c, &m);
2272 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2273 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2274 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2276 // ----------------- namespaces -------------------------------------------------
2278 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2279 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2280 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2282 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER