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);
712 void check_code_for_break(code_t*c)
715 if(c->opcode == OPCODE___BREAK__) {
716 char*name = string_cstr(c->data[0]);
717 syntaxerror("Unresolved \"break %s\"", name);
719 if(c->opcode == OPCODE___CONTINUE__) {
720 char*name = string_cstr(c->data[0]);
721 syntaxerror("Unresolved \"continue %s\"", name);
728 static void check_constant_against_type(classinfo_t*t, constant_t*c)
730 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
731 if(TYPE_IS_NUMBER(t)) {
732 xassert(c->type == CONSTANT_FLOAT
733 || c->type == CONSTANT_INT
734 || c->type == CONSTANT_UINT);
735 } else if(TYPE_IS_UINT(t)) {
736 xassert(c->type == CONSTANT_UINT ||
737 (c->type == CONSTANT_INT && c->i>0));
738 } else if(TYPE_IS_INT(t)) {
739 xassert(c->type == CONSTANT_INT);
740 } else if(TYPE_IS_BOOLEAN(t)) {
741 xassert(c->type == CONSTANT_TRUE
742 || c->type == CONSTANT_FALSE);
746 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
748 memberinfo_t*minfo = 0;
749 if(getset != KW_GET && getset != KW_SET) {
750 if(registry_findmember(state->cls->info, name)) {
751 syntaxerror("class already contains a member/method called '%s'", name);
753 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
754 minfo->return_type = return_type;
755 // getslot on a member slot only returns "undefined", so no need
756 // to actually store these
757 //state->minfo->slot = state->method->abc->method->trait->slot_id;
759 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
763 else if(params->list)
764 type = params->list->param->type;
765 if((minfo=registry_findmember(state->cls->info, name))) {
766 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
767 syntaxerror("class already contains a member or method called '%s'", name);
769 syntaxerror("getter/setter for '%s' already defined", name);
770 /* make a setter or getter into a getset */
775 if(type && minfo->type != type)
776 syntaxerror("different type in getter and setter");
778 minfo = memberinfo_register(state->cls->info, name, gs);
781 /* can't assign a slot as getter and setter might have different slots */
782 //minfo->slot = slot;
784 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
785 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
786 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
787 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
788 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
792 static int flags2access(int flags)
795 if(flags&FLAG_PUBLIC) {
796 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
797 access = ACCESS_PACKAGE;
798 } else if(flags&FLAG_PRIVATE) {
799 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
800 access = ACCESS_PRIVATE;
801 } else if(flags&FLAG_PROTECTED) {
802 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
803 access = ACCESS_PROTECTED;
805 access = ACCESS_PACKAGEINTERNAL;
810 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
811 params_t*params, classinfo_t*return_type)
814 syntaxerror("not able to start another method scope");
817 state->method = rfx_calloc(sizeof(methodstate_t));
818 state->method->initcode = 0;
819 state->method->is_constructor = !strcmp(state->cls->info->name,name);
820 state->method->has_super = 0;
822 state->cls->has_constructor |= state->method->is_constructor;
824 global->variable_count = 0;
826 /* state->vars is initialized by state_new */
827 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
829 for(p=params->list;p;p=p->next) {
830 new_variable(p->param->name, p->param->type);
832 if(state->method->is_constructor)
833 name = "__as3_constructor__";
834 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
837 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
838 params_t*params, classinfo_t*return_type, code_t*body)
840 namespace_t mname_ns = {flags2access(flags), ""};
841 multiname_t mname = {QNAME, &mname_ns, 0, name};
845 multiname_t*type2 = sig2mname(return_type);
847 if(state->method->is_constructor) {
848 f = abc_class_getconstructor(state->cls->abc, type2);
850 if(flags&FLAG_STATIC)
851 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
853 f = abc_class_method(state->cls->abc, type2, &mname);
854 slot = f->trait->slot_id;
856 //flash doesn't seem to allow us to access function slots
857 //state->method->info->slot = slot;
859 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
860 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
861 if(params->varargs) f->flags |= METHOD_NEED_REST;
865 for(p=params->list;p;p=p->next) {
866 if(params->varargs && !p->next) {
867 break; //varargs: omit last parameter in function signature
869 multiname_t*m = sig2mname(p->param->type);
870 list_append(f->parameters, m);
871 if(p->param->value) {
872 check_constant_against_type(p->param->type, p->param->value);
873 opt=1;list_append(f->optional_parameters, p->param->value);
875 syntaxerror("non-optional parameter not allowed after optional parameters");
878 check_code_for_break(body);
881 f->body->code = body;
884 syntaxerror("interface methods can't have a method body");
891 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
896 void breakjumpsto(code_t*c, char*name, code_t*jump)
899 if(c->opcode == OPCODE___BREAK__) {
900 string_t*name2 = c->data[0];
901 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
902 c->opcode = OPCODE_JUMP;
909 void continuejumpsto(code_t*c, char*name, code_t*jump)
912 if(c->opcode == OPCODE___CONTINUE__) {
913 string_t*name2 = c->data[0];
914 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
915 c->opcode = OPCODE_JUMP;
923 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
926 return registry_getanytype();
927 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
928 return registry_getanytype();
931 return registry_getanytype();
933 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
938 return abc_coerce_a(c);
942 // cast an "any" type to a specific type. subject to
943 // runtime exceptions
944 return abc_coerce2(c, &m);
947 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
948 return abc_coerce2(c, &m);
950 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
951 return abc_coerce2(c, &m);
953 /* these are subject to overflow */
954 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
955 return abc_coerce2(c, &m);
957 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
958 return abc_coerce2(c, &m);
961 classinfo_t*supertype = from;
963 if(supertype == to) {
964 // target type is one of from's superclasses
965 return abc_coerce2(c, &m);
968 while(supertype->interfaces[t]) {
969 if(supertype->interfaces[t]==to) {
970 // to type is one of from's interfaces
971 return abc_coerce2(c, &m);
975 supertype = supertype->superclass;
977 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
979 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
981 syntaxerror("can't convert type %s to %s", from->name, to->name);
984 code_t*defaultvalue(code_t*c, classinfo_t*type)
986 if(TYPE_IS_INT(type)) {
987 c = abc_pushbyte(c, 0);
988 } else if(TYPE_IS_UINT(type)) {
989 c = abc_pushuint(c, 0);
990 } else if(TYPE_IS_FLOAT(type)) {
992 } else if(TYPE_IS_BOOLEAN(type)) {
993 c = abc_pushfalse(c);
1000 char is_pushundefined(code_t*c)
1002 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1005 void parserassert(int b)
1007 if(!b) syntaxerror("internal error: assertion failed");
1010 static classinfo_t* find_class(char*name)
1014 c = registry_findclass(state->package, name);
1016 /* try explicit imports */
1017 dictentry_t* e = dict_get_slot(state->imports, name);
1021 if(!strcmp(e->key, name)) {
1022 c = (classinfo_t*)e->data;
1027 /* try package.* imports */
1028 import_list_t*l = state->wildcard_imports;
1032 //printf("does package %s contain a class %s?\n", l->import->package, name);
1033 c = registry_findclass(l->import->package, name);
1037 /* try global package */
1039 c = registry_findclass("", name);
1044 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1048 [prefix code] [read instruction]
1052 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1055 if(in && in->opcode == OPCODE_COERCE_A) {
1056 in = code_cutlast(in);
1059 syntaxerror("internal error");
1061 /* chop off read instruction */
1065 prefix = r->prev;r->prev = 0;
1071 char use_temp_var = readbefore;
1073 /* generate the write instruction, and maybe append a dup to the prefix code */
1074 code_t* write = abc_nop(0);
1075 if(r->opcode == OPCODE_GETPROPERTY) {
1076 write->opcode = OPCODE_SETPROPERTY;
1077 multiname_t*m = (multiname_t*)r->data[0];
1078 write->data[0] = multiname_clone(m);
1079 if(m->type == QNAME || m->type == MULTINAME) {
1081 prefix = abc_dup(prefix); // we need the object, too
1084 } else if(m->type == MULTINAMEL) {
1086 /* dupping two values on the stack requires 5 operations and one register-
1087 couldn't adobe just have given us a dup2? */
1088 int temp = gettempvar();
1089 prefix = abc_setlocal(prefix, temp);
1090 prefix = abc_dup(prefix);
1091 prefix = abc_getlocal(prefix, temp);
1092 prefix = abc_swap(prefix);
1093 prefix = abc_getlocal(prefix, temp);
1097 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1099 } else if(r->opcode == OPCODE_GETSLOT) {
1100 write->opcode = OPCODE_SETSLOT;
1101 write->data[0] = r->data[0];
1103 prefix = abc_dup(prefix); // we need the object, too
1106 } else if(r->opcode == OPCODE_GETLOCAL) {
1107 write->opcode = OPCODE_SETLOCAL;
1108 write->data[0] = r->data[0];
1109 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1110 write->opcode = OPCODE_SETLOCAL_0;
1111 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1112 write->opcode = OPCODE_SETLOCAL_1;
1113 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1114 write->opcode = OPCODE_SETLOCAL_2;
1115 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1116 write->opcode = OPCODE_SETLOCAL_3;
1118 code_dump(r, 0, 0, "", stdout);
1119 syntaxerror("illegal lvalue: can't assign a value to this expression");
1126 /* with getproperty/getslot, we have to be extra careful not
1127 to execute the read code twice, as it might have side-effects
1128 (e.g. if the property is in fact a setter/getter combination)
1130 So read the value, modify it, and write it again,
1131 using prefix only once and making sure (by using a temporary
1132 register) that the return value is what we just wrote */
1133 temp = gettempvar();
1134 c = code_append(c, prefix);
1135 c = code_append(c, r);
1138 c = abc_setlocal(c, temp);
1140 c = code_append(c, middlepart);
1143 c = abc_setlocal(c, temp);
1145 c = code_append(c, write);
1146 c = abc_getlocal(c, temp);
1147 c = abc_kill(c, temp);
1149 /* if we're allowed to execute the read code twice *and*
1150 the middlepart doesn't modify the code, things are easier.
1152 code_t* r2 = code_dup(r);
1153 //c = code_append(c, prefix);
1154 parserassert(!prefix);
1155 c = code_append(c, r);
1156 c = code_append(c, middlepart);
1157 c = code_append(c, write);
1158 c = code_append(c, r2);
1161 /* even smaller version: overwrite the value without reading
1165 c = code_append(c, prefix);
1168 c = code_append(c, middlepart);
1169 c = code_append(c, write);
1170 c = code_append(c, r);
1172 temp = gettempvar();
1174 c = code_append(c, prefix);
1177 c = code_append(c, middlepart);
1179 c = abc_setlocal(c, temp);
1180 c = code_append(c, write);
1181 c = abc_getlocal(c, temp);
1188 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1189 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1196 /* ------------ code blocks / statements ---------------- */
1200 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1201 MAYBECODE: {$$=code_new();}
1203 CODE: CODE CODEPIECE {
1204 $$=code_append($1,$2);
1210 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1211 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1212 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1213 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1214 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1215 CODEPIECE: ';' {$$=code_new();}
1216 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1217 CODEPIECE: VOIDEXPRESSION {$$=$1}
1218 CODEPIECE: FOR {$$=$1}
1219 CODEPIECE: WHILE {$$=$1}
1220 CODEPIECE: DO_WHILE {$$=$1}
1221 CODEPIECE: BREAK {$$=$1}
1222 CODEPIECE: CONTINUE {$$=$1}
1223 CODEPIECE: RETURN {$$=$1}
1224 CODEPIECE: IF {$$=$1}
1225 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1226 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1228 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1229 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1230 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1232 /* ------------ variables --------------------------- */
1234 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1235 | {$$.c=abc_pushundefined(0);
1239 VAR : "const" | "var"
1240 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1242 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1243 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1245 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1247 if(variable_exists($2))
1248 syntaxerror("Variable %s already defined", $2);
1250 if(!is_subtype_of($4.t, $3)) {
1251 syntaxerror("Can't convert %s to %s", $4.t->name,
1255 int index = new_variable($2, $3);
1258 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1260 $$ = converttype($$, $4.t, $3);
1261 $$ = abc_setlocal($$, index);
1263 $$ = defaultvalue(0, $3);
1264 $$ = abc_setlocal($$, index);
1267 /* if this is a typed variable:
1268 push default value for type on stack */
1270 state->method->initcode = defaultvalue(state->method->initcode, $3);
1271 state->method->initcode = abc_setlocal(state->method->initcode, index);
1274 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1276 $$ = abc_coerce_a($$);
1277 $$ = abc_setlocal($$, index);
1283 /* that's the default for a local register, anyway
1285 state->method->initcode = abc_pushundefined(state->method->initcode);
1286 state->method->initcode = abc_setlocal(state->method->initcode, index);
1288 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1291 /* ------------ control flow ------------------------- */
1293 MAYBEELSE: %prec below_else {$$ = code_new();}
1294 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1295 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1297 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1299 $$ = code_append($$, $4.c);
1300 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1302 $$ = code_append($$, $6);
1304 myjmp = $$ = abc_jump($$, 0);
1306 myif->branch = $$ = abc_nop($$);
1308 $$ = code_append($$, $7);
1309 myjmp->branch = $$ = abc_nop($$);
1312 $$ = killvars($$);old_state();
1315 MAYBELABEL : T_IDENTIFIER ':' {$$=$1;}
1316 MAYBELABEL : {$$="";}
1318 FOR_INIT : {$$=code_new();}
1319 FOR_INIT : VARIABLE_DECLARATION
1320 FOR_INIT : VOIDEXPRESSION
1322 FOR : MAYBELABEL "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1324 $$ = code_append($$, $5);
1325 code_t*loopstart = $$ = abc_label($$);
1326 $$ = code_append($$, $7.c);
1327 code_t*myif = $$ = abc_iffalse($$, 0);
1328 $$ = code_append($$, $11);
1329 code_t*cont = $$ = abc_nop($$);
1330 $$ = code_append($$, $9);
1331 $$ = abc_jump($$, loopstart);
1332 code_t*out = $$ = abc_nop($$);
1333 breakjumpsto($$, $1, out);
1334 continuejumpsto($$, $1, cont);
1337 $$ = killvars($$);old_state();
1340 WHILE : MAYBELABEL "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1343 code_t*myjmp = $$ = abc_jump($$, 0);
1344 code_t*loopstart = $$ = abc_label($$);
1345 $$ = code_append($$, $7);
1346 myjmp->branch = $$ = abc_nop($$);
1347 $$ = code_append($$, $5.c);
1348 $$ = abc_iftrue($$, loopstart);
1349 code_t*out = $$ = abc_nop($$);
1350 breakjumpsto($$, $1, out);
1351 continuejumpsto($$, $1, loopstart);
1357 DO_WHILE : MAYBELABEL "do" {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1359 code_t*loopstart = $$ = abc_label($$);
1360 $$ = code_append($$, $4);
1361 code_t*cont = $$ = abc_nop($$);
1362 $$ = code_append($$, $7.c);
1363 $$ = abc_iftrue($$, loopstart);
1364 code_t*out = $$ = abc_nop($$);
1365 breakjumpsto($$, $1, out);
1366 continuejumpsto($$, $1, cont);
1371 BREAK : "break" %prec prec_none {
1372 $$ = abc___break__(0, "");
1374 BREAK : "break" T_IDENTIFIER {
1375 $$ = abc___break__(0, $2);
1377 CONTINUE : "continue" %prec prec_none {
1378 $$ = abc___continue__(0, "");
1380 CONTINUE : "continue" T_IDENTIFIER {
1381 $$ = abc___continue__(0, $2);
1384 /* ------------ packages and imports ---------------- */
1386 X_IDENTIFIER: T_IDENTIFIER
1387 | "package" {$$="package";}
1389 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1390 PACKAGE: X_IDENTIFIER {$$=$1;}
1392 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1393 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1395 IMPORT : "import" QNAME {
1398 syntaxerror("Couldn't import class\n");
1399 state_has_imports();
1400 dict_put(state->imports, c->name, c);
1403 IMPORT : "import" PACKAGE '.' '*' {
1406 state_has_imports();
1407 list_append(state->wildcard_imports, i);
1411 /* ------------ classes and interfaces (header) -------------- */
1413 MAYBE_MODIFIERS : {$$=0;}
1414 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1415 MODIFIER_LIST : MODIFIER {$$=$1;}
1416 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1418 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1419 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1420 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1421 | KW_STATIC {$$=FLAG_STATIC;}
1422 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1423 | KW_FINAL {$$=FLAG_FINAL;}
1424 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1425 | KW_NATIVE {$$=FLAG_NATIVE;}
1426 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1428 EXTENDS : {$$=registry_getobjectclass();}
1429 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1431 EXTENDS_LIST : {$$=list_new();}
1432 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1434 IMPLEMENTS_LIST : {$$=list_new();}
1435 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1437 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1438 EXTENDS IMPLEMENTS_LIST
1439 '{' {startclass($1,$3,$4,$5, 0);}
1440 MAYBE_DECLARATION_LIST
1443 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1445 '{' {startclass($1,$3,0,$4,1);}
1446 MAYBE_IDECLARATION_LIST
1449 /* ------------ classes and interfaces (body) -------------- */
1451 MAYBE_DECLARATION_LIST :
1452 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1453 DECLARATION_LIST : DECLARATION
1454 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1456 DECLARATION : SLOT_DECLARATION
1457 DECLARATION : FUNCTION_DECLARATION
1459 MAYBE_IDECLARATION_LIST :
1460 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1461 IDECLARATION_LIST : IDECLARATION
1462 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1464 IDECLARATION : "var" T_IDENTIFIER {
1465 syntaxerror("variable declarations not allowed in interfaces");
1467 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1469 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1470 syntaxerror("invalid method modifiers: interface methods always need to be public");
1472 startfunction(0,$1,$3,$4,&$6,$8);
1473 endfunction(0,$1,$3,$4,&$6,$8, 0);
1476 /* ------------ classes and interfaces (body, slots ) ------- */
1478 VARCONST: "var" | "const"
1480 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1482 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1484 info->flags = flags;
1487 namespace_t mname_ns = {flags2access(flags), ""};
1488 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1490 if(!(flags&FLAG_STATIC)) {
1493 t=abc_class_slot(state->cls->abc, &mname, &m);
1495 t=abc_class_slot(state->cls->abc, &mname, 0);
1497 info->slot = t->slot_id;
1501 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1503 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1505 info->slot = t->slot_id;
1507 if($5.c && !is_pushundefined($5.c)) {
1509 c = abc_getlocal_0(c);
1510 c = code_append(c, $5.c);
1511 c = converttype(c, $5.t, $4);
1512 c = abc_setslot(c, t->slot_id);
1513 if(!(flags&FLAG_STATIC))
1514 state->cls->init = code_append(state->cls->init, c);
1516 state->cls->static_init = code_append(state->cls->static_init, c);
1519 t->kind= TRAIT_CONST;
1523 /* ------------ constants -------------------------------------- */
1525 MAYBESTATICCONSTANT: {$$=0;}
1526 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1528 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1529 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1530 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1531 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1532 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1533 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1534 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1535 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1536 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1538 /* ------------ classes and interfaces (body, functions) ------- */
1540 // non-vararg version
1542 memset(&$$,0,sizeof($$));
1544 MAYBE_PARAM_LIST: PARAM_LIST {
1549 MAYBE_PARAM_LIST: "..." PARAM {
1550 memset(&$$,0,sizeof($$));
1552 list_append($$.list, $2);
1554 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1557 list_append($$.list, $4);
1561 PARAM_LIST: PARAM_LIST ',' PARAM {
1563 list_append($$.list, $3);
1566 memset(&$$,0,sizeof($$));
1567 list_append($$.list, $1);
1570 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1571 $$ = malloc(sizeof(param_t));
1576 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1577 $$ = malloc(sizeof(param_t));
1579 $$->type = TYPE_ANY;
1582 GETSET : "get" {$$=$1;}
1586 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1587 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1590 if(state->method->late_binding) {
1591 c = abc_getlocal_0(c);
1592 c = abc_pushscope(c);
1594 if(state->method->is_constructor && !state->method->has_super) {
1595 // call default constructor
1596 c = abc_getlocal_0(c);
1597 c = abc_constructsuper(c, 0);
1599 c = wrap_function(c, state->method->initcode, $11);
1600 endfunction(0,$1,$3,$4,&$6,$8,c);
1603 /* ------------- package + class ids --------------- */
1605 CLASS: T_IDENTIFIER {
1607 /* try current package */
1608 $$ = find_class($1);
1609 if(!$$) syntaxerror("Could not find class %s\n", $1);
1612 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1613 $$ = registry_findclass($1, $3);
1614 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1617 QNAME: PACKAGEANDCLASS
1620 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1621 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1623 TYPE : QNAME {$$=$1;}
1624 | '*' {$$=registry_getanytype();}
1626 | "String" {$$=registry_getstringclass();}
1627 | "int" {$$=registry_getintclass();}
1628 | "uint" {$$=registry_getuintclass();}
1629 | "Boolean" {$$=registry_getbooleanclass();}
1630 | "Number" {$$=registry_getnumberclass();}
1633 MAYBETYPE: ':' TYPE {$$=$2;}
1636 /* ----------function calls, delete, constructor calls ------ */
1638 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1639 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1641 MAYBE_EXPRESSION_LIST : {$$=0;}
1642 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1643 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1644 typedcode_t*t = malloc(sizeof(typedcode_t));
1646 list_append($$, t);}
1647 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1648 typedcode_t*t = malloc(sizeof(typedcode_t));
1650 list_append($$, t);}
1652 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1657 $$.c = abc_getglobalscope($$.c);
1658 $$.c = abc_getslot($$.c, $2->slot);
1660 $$.c = abc_findpropstrict2($$.c, &m);
1663 typedcode_list_t*l = $3;
1666 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1671 $$.c = abc_construct($$.c, len);
1673 $$.c = abc_constructprop2($$.c, &m, len);
1677 /* TODO: use abc_call (for calling local variables),
1678 abc_callstatic (for calling own methods)
1681 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1682 typedcode_list_t*l = $3;
1684 code_t*paramcode = 0;
1686 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1692 if($$.c->opcode == OPCODE_COERCE_A) {
1693 $$.c = code_cutlast($$.c);
1697 multiname_t*name = 0;
1698 if($$.c->opcode == OPCODE_GETPROPERTY) {
1699 name = multiname_clone($$.c->data[0]);
1700 $$.c = code_cutlast($$.c);
1701 $$.c = code_append($$.c, paramcode);
1702 $$.c = abc_callproperty2($$.c, name, len);
1703 } else if($$.c->opcode == OPCODE_GETSLOT) {
1704 int slot = (int)(ptroff_t)$$.c->data[0];
1705 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1706 if(t->kind!=TRAIT_METHOD) {
1707 //ok: flash allows to assign closures to members.
1710 $$.c = code_cutlast($$.c);
1711 $$.c = code_append($$.c, paramcode);
1712 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1713 $$.c = abc_callproperty2($$.c, name, len);
1714 } else if($$.c->opcode == OPCODE_GETSUPER) {
1715 name = multiname_clone($$.c->data[0]);
1716 $$.c = code_cutlast($$.c);
1717 $$.c = code_append($$.c, paramcode);
1718 $$.c = abc_callsuper2($$.c, name, len);
1720 $$.c = abc_getlocal_0($$.c);
1721 $$.c = code_append($$.c, paramcode);
1722 $$.c = abc_call($$.c, len);
1727 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1728 $$.t = $1.t->function->return_type;
1730 $$.c = abc_coerce_a($$.c);
1734 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1735 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1736 if(!state->method) syntaxerror("super() not allowed outside of a function");
1737 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1740 $$.c = abc_getlocal_0($$.c);
1741 typedcode_list_t*l = 0;
1743 for(l=$3;l;l=l->next) {
1744 $$.c = code_append($$.c, l->typedcode->c);len++;
1747 this is dependent on the control path, check this somewhere else
1748 if(state->method->has_super)
1749 syntaxerror("constructor may call super() only once");
1751 state->method->has_super = 1;
1752 $$.c = abc_constructsuper($$.c, len);
1753 $$.c = abc_pushundefined($$.c);
1757 DELETE: "delete" E {
1759 if($$.c->opcode == OPCODE_COERCE_A) {
1760 $$.c = code_cutlast($$.c);
1762 multiname_t*name = 0;
1763 if($$.c->opcode == OPCODE_GETPROPERTY) {
1764 $$.c->opcode = OPCODE_DELETEPROPERTY;
1765 } else if($$.c->opcode == OPCODE_GETSLOT) {
1766 int slot = (int)(ptroff_t)$$.c->data[0];
1767 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1768 $$.c = code_cutlast($$.c);
1769 $$.c = abc_deleteproperty2($$.c, name);
1771 $$.c = abc_getlocal_0($$.c);
1772 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1773 $$.c = abc_deleteproperty2($$.c, &m);
1775 $$.t = TYPE_BOOLEAN;
1778 RETURN: "return" %prec prec_none {
1779 $$ = abc_returnvoid(0);
1781 RETURN: "return" EXPRESSION {
1783 $$ = abc_returnvalue($$);
1786 // ----------------------- expression types -------------------------------------
1788 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1789 EXPRESSION : E %prec below_minus {$$ = $1;}
1790 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1792 $$.c = cut_last_push($$.c);
1793 $$.c = code_append($$.c,$3.c);
1796 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1797 $$=cut_last_push($1.c);
1800 // ----------------------- expression evaluation -------------------------------------
1803 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1805 E : DELETE {$$ = $1;}
1806 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1810 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1811 //MULTINAME(m, registry_getintclass());
1812 //$$.c = abc_coerce2($$.c, &m); // FIXME
1815 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1818 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1821 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1824 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1827 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1830 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1833 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1834 $$.t = TYPE_BOOLEAN;
1836 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1837 $$.t = TYPE_BOOLEAN;
1839 CONSTANT : "null" {$$.c = abc_pushnull(0);
1844 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1845 $$.t = TYPE_BOOLEAN;
1847 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1848 $$.t = TYPE_BOOLEAN;
1850 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1851 $$.t = TYPE_BOOLEAN;
1853 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1854 $$.t = TYPE_BOOLEAN;
1856 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1857 $$.t = TYPE_BOOLEAN;
1859 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1860 $$.t = TYPE_BOOLEAN;
1862 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1863 $$.t = TYPE_BOOLEAN;
1865 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1866 $$.t = TYPE_BOOLEAN;
1869 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1871 $$.c = converttype($$.c, $1.t, $$.t);
1872 $$.c = abc_dup($$.c);
1873 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1874 $$.c = cut_last_push($$.c);
1875 $$.c = code_append($$.c,$3.c);
1876 $$.c = converttype($$.c, $3.t, $$.t);
1877 code_t*label = $$.c = abc_label($$.c);
1878 jmp->branch = label;
1881 $$.t = join_types($1.t, $3.t, 'A');
1882 /*printf("%08x:\n",$1.t);
1883 code_dump($1.c, 0, 0, "", stdout);
1884 printf("%08x:\n",$3.t);
1885 code_dump($3.c, 0, 0, "", stdout);
1886 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1888 $$.c = converttype($$.c, $1.t, $$.t);
1889 $$.c = abc_dup($$.c);
1890 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1891 $$.c = cut_last_push($$.c);
1892 $$.c = code_append($$.c,$3.c);
1893 $$.c = converttype($$.c, $3.t, $$.t);
1894 code_t*label = $$.c = abc_label($$.c);
1895 jmp->branch = label;
1898 E : '!' E {$$.c=$2.c;
1899 $$.c = abc_not($$.c);
1900 $$.t = TYPE_BOOLEAN;
1903 E : '~' E {$$.c=$2.c;
1904 $$.c = abc_bitnot($$.c);
1908 E : E '&' E {$$.c = code_append($1.c,$3.c);
1909 $$.c = abc_bitand($$.c);
1913 E : E '^' E {$$.c = code_append($1.c,$3.c);
1914 $$.c = abc_bitxor($$.c);
1918 E : E '|' E {$$.c = code_append($1.c,$3.c);
1919 $$.c = abc_bitor($$.c);
1923 E : E '-' E {$$.c = code_append($1.c,$3.c);
1924 if(BOTH_INT($1,$3)) {
1925 $$.c = abc_subtract_i($$.c);
1928 $$.c = abc_subtract($$.c);
1932 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1933 $$.c = abc_rshift($$.c);
1936 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1937 $$.c = abc_urshift($$.c);
1940 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1941 $$.c = abc_lshift($$.c);
1945 E : E '/' E {$$.c = code_append($1.c,$3.c);
1946 $$.c = abc_divide($$.c);
1949 E : E '+' E {$$.c = code_append($1.c,$3.c);
1950 $$.c = abc_add($$.c);
1953 E : E '%' E {$$.c = code_append($1.c,$3.c);
1954 $$.c = abc_modulo($$.c);
1957 E : E '*' E {$$.c = code_append($1.c,$3.c);
1958 if(BOTH_INT($1,$3)) {
1959 $$.c = abc_multiply_i($$.c);
1962 $$.c = abc_multiply($$.c);
1967 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1968 if(use_astype && TYPE_IS_CLASS($3.t)) {
1969 MULTINAME(m,$3.t->cls);
1970 $$.c = abc_astype2($1.c, &m);
1973 $$.c = code_append($1.c, $3.c);
1974 $$.c = abc_astypelate($$.c);
1979 E : E "instanceof" E
1980 {$$.c = code_append($1.c, $3.c);
1981 $$.c = abc_instanceof($$.c);
1982 $$.t = TYPE_BOOLEAN;
1985 E : E "is" E {$$.c = code_append($1.c, $3.c);
1986 $$.c = abc_istypelate($$.c);
1987 $$.t = TYPE_BOOLEAN;
1990 E : "typeof" '(' E ')' {
1992 $$.c = abc_typeof($$.c);
1997 $$.c = cut_last_push($2.c);
1998 $$.c = abc_pushundefined($$.c);
2002 E : "void" { $$.c = abc_pushundefined(0);
2006 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2011 $$.c=abc_negate_i($$.c);
2014 $$.c=abc_negate($$.c);
2021 $$.c = code_append($$.c, $3.c);
2023 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2024 $$.c = abc_getproperty2($$.c, &m);
2025 $$.t = 0; // array elements have unknown type
2028 E : '[' MAYBE_EXPRESSION_LIST ']' {
2030 typedcode_list_t*l = 0;
2032 for(l=$2;l;l=l->next) {
2033 $$.c = code_append($$.c, l->typedcode->c);len++;
2035 $$.c = abc_newarray($$.c, len);
2036 $$.t = registry_getarrayclass();
2041 if(BOTH_INT($1,$3)) {
2042 c=abc_multiply_i(c);
2046 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2047 $$.c = toreadwrite($1.c, c, 0, 0);
2052 code_t*c = abc_modulo($3.c);
2053 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2054 $$.c = toreadwrite($1.c, c, 0, 0);
2058 code_t*c = abc_lshift($3.c);
2059 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2060 $$.c = toreadwrite($1.c, c, 0, 0);
2064 code_t*c = abc_rshift($3.c);
2065 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2066 $$.c = toreadwrite($1.c, c, 0, 0);
2070 code_t*c = abc_urshift($3.c);
2071 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2072 $$.c = toreadwrite($1.c, c, 0, 0);
2076 code_t*c = abc_divide($3.c);
2077 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2078 $$.c = toreadwrite($1.c, c, 0, 0);
2083 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2088 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2090 $$.c = toreadwrite($1.c, c, 0, 0);
2093 E : E "-=" E { code_t*c = $3.c;
2094 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2095 c=abc_subtract_i(c);
2099 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2101 $$.c = toreadwrite($1.c, c, 0, 0);
2104 E : E '=' E { code_t*c = 0;
2105 c = code_append(c, $3.c);
2106 c = converttype(c, $3.t, $1.t);
2107 $$.c = toreadwrite($1.c, c, 1, 0);
2111 E : E '?' E ':' E %prec below_assignment {
2113 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2114 $$.c = code_append($$.c, $3.c);
2115 code_t*j2 = $$.c = abc_jump($$.c, 0);
2116 $$.c = j1->branch = abc_label($$.c);
2117 $$.c = code_append($$.c, $5.c);
2118 $$.c = j2->branch = abc_label($$.c);
2119 $$.t = join_types($3.t,$5.t,'?');
2122 // TODO: use inclocal where appropriate
2123 E : E "++" { code_t*c = 0;
2124 classinfo_t*type = $1.t;
2125 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2126 c=abc_increment_i(c);
2132 c=converttype(c, type, $1.t);
2133 $$.c = toreadwrite($1.c, c, 0, 1);
2136 E : E "--" { code_t*c = 0;
2137 classinfo_t*type = $1.t;
2138 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2139 c=abc_decrement_i(c);
2145 c=converttype(c, type, $1.t);
2146 $$.c = toreadwrite($1.c, c, 0, 1);
2150 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2151 classinfo_t*type = $2.t;
2152 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2153 c=abc_increment_i(c);
2159 c=converttype(c, type, $2.t);
2160 $$.c = toreadwrite($2.c, c, 0, 0);
2164 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2165 classinfo_t*type = $2.t;
2166 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2167 c=abc_decrement_i(c);
2173 c=converttype(c, type, $2.t);
2174 $$.c = toreadwrite($2.c, c, 0, 0);
2178 E : "super" '.' T_IDENTIFIER
2179 { if(!state->cls->info)
2180 syntaxerror("super keyword not allowed outside a class");
2181 classinfo_t*t = state->cls->info->superclass;
2182 if(!t) t = TYPE_OBJECT;
2184 memberinfo_t*f = registry_findmember(t, $3);
2185 namespace_t ns = {flags2access(f->flags), ""};
2186 MEMBER_MULTINAME(m, f, $3);
2188 $$.c = abc_getlocal_0($$.c);
2189 $$.c = abc_getsuper2($$.c, &m);
2190 $$.t = memberinfo_gettype(f);
2193 E : E '.' T_IDENTIFIER
2195 classinfo_t*t = $1.t;
2197 if(TYPE_IS_CLASS(t) && t->cls) {
2202 memberinfo_t*f = registry_findmember(t, $3);
2204 if(f && !is_static != !(f->flags&FLAG_STATIC))
2206 if(f && f->slot && !noslot) {
2207 $$.c = abc_getslot($$.c, f->slot);
2209 MEMBER_MULTINAME(m, f, $3);
2210 $$.c = abc_getproperty2($$.c, &m);
2212 /* determine type */
2213 $$.t = memberinfo_gettype(f);
2215 $$.c = abc_coerce_a($$.c);
2217 /* when resolving a property on an unknown type, we do know the
2218 name of the property (and don't seem to need the package), but
2219 we need to make avm2 try out all access modes */
2220 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2221 $$.c = abc_getproperty2($$.c, &m);
2222 $$.c = abc_coerce_a($$.c);
2223 $$.t = registry_getanytype();
2227 VAR_READ : T_IDENTIFIER {
2234 /* look at variables */
2235 if((i = find_variable($1, &$$.t)) >= 0) {
2236 // $1 is a local variable
2237 $$.c = abc_getlocal($$.c, i);
2239 /* look at current class' members */
2240 } else if((f = registry_findmember(state->cls->info, $1))) {
2241 // $1 is a function in this class
2242 int var_is_static = (f->flags&FLAG_STATIC);
2243 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2244 if(var_is_static != i_am_static) {
2245 /* there doesn't seem to be any "static" way to access
2246 static properties of a class */
2247 state->method->late_binding = 1;
2249 namespace_t ns = {flags2access(f->flags), ""};
2250 multiname_t m = {QNAME, &ns, 0, $1};
2251 $$.c = abc_findpropstrict2($$.c, &m);
2252 $$.c = abc_getproperty2($$.c, &m);
2255 $$.c = abc_getlocal_0($$.c);
2256 $$.c = abc_getslot($$.c, f->slot);
2258 namespace_t ns = {flags2access(f->flags), ""};
2259 multiname_t m = {QNAME, &ns, 0, $1};
2260 $$.c = abc_getlocal_0($$.c);
2261 $$.c = abc_getproperty2($$.c, &m);
2264 if(f->kind == MEMBER_METHOD) {
2265 $$.t = TYPE_FUNCTION(f);
2270 /* look at classes in the current package and imported classes */
2271 } else if((a = find_class($1))) {
2272 if(a->flags & FLAG_METHOD) {
2274 $$.c = abc_findpropstrict2($$.c, &m);
2275 $$.c = abc_getproperty2($$.c, &m);
2276 $$.t = TYPE_FUNCTION(a->function);
2279 $$.c = abc_getglobalscope($$.c);
2280 $$.c = abc_getslot($$.c, a->slot);
2283 $$.c = abc_getlex2($$.c, &m);
2285 $$.t = TYPE_CLASS(a);
2288 /* unknown object, let the avm2 resolve it */
2290 if(strcmp($1,"trace"))
2291 warning("Couldn't resolve '%s', doing late binding", $1);
2292 state->method->late_binding = 1;
2294 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2297 $$.c = abc_findpropstrict2($$.c, &m);
2298 $$.c = abc_getproperty2($$.c, &m);
2303 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2304 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2305 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2307 // ----------------- namespaces -------------------------------------------------
2309 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2310 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2311 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2313 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER