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<id> T_FOR "for"
73 %token<id> T_WHILE "while"
76 %token<token> KW_IMPLEMENTS
77 %token<token> KW_NAMESPACE "namespace"
78 %token<token> KW_PACKAGE "package"
79 %token<token> KW_PROTECTED
80 %token<token> KW_PUBLIC
81 %token<token> KW_PRIVATE
82 %token<token> KW_USE "use"
83 %token<token> KW_INTERNAL
84 %token<token> KW_NEW "new"
85 %token<token> KW_NATIVE
86 %token<token> KW_FUNCTION "function"
87 %token<token> KW_UNDEFINED "undefined"
88 %token<token> KW_CONTINUE "continue"
89 %token<token> KW_CLASS "class"
90 %token<token> KW_CONST "const"
91 %token<token> KW_SET "set"
92 %token<token> KW_VOID "void"
93 %token<token> KW_STATIC
94 %token<token> KW_INSTANCEOF "instanceof"
95 %token<token> KW_IMPORT "import"
96 %token<token> KW_RETURN "return"
97 %token<token> KW_TYPEOF "typeof"
98 %token<token> KW_INTERFACE "interface"
99 %token<token> KW_NULL "null"
100 %token<token> KW_VAR "var"
101 %token<token> KW_DYNAMIC "dynamic"
102 %token<token> KW_OVERRIDE
103 %token<token> KW_FINAL
104 %token<token> KW_GET "get"
105 %token<token> KW_SUPER "super"
106 %token<token> KW_EXTENDS
107 %token<token> KW_FALSE "false"
108 %token<token> KW_TRUE "true"
109 %token<token> KW_BOOLEAN "Boolean"
110 %token<token> KW_UINT "uint"
111 %token<token> KW_INT "int"
112 %token<token> KW_NUMBER "Number"
113 %token<token> KW_STRING "String"
114 %token<token> KW_DELETE "delete"
115 %token<token> KW_IF "if"
116 %token<token> KW_ELSE "else"
117 %token<token> KW_BREAK "break"
118 %token<token> KW_IS "is"
119 %token<token> KW_AS "as"
121 %token<token> T_EQEQ "=="
122 %token<token> T_EQEQEQ "==="
123 %token<token> T_NE "!="
124 %token<token> T_NEE "!=="
125 %token<token> T_LE "<="
126 %token<token> T_GE ">="
127 %token<token> T_DIVBY "/="
128 %token<token> T_MODBY "%="
129 %token<token> T_MULBY "*="
130 %token<token> T_PLUSBY "+="
131 %token<token> T_MINUSBY "-="
132 %token<token> T_SHRBY ">>="
133 %token<token> T_SHLBY "<<="
134 %token<token> T_USHRBY ">>>="
135 %token<token> T_OROR "||"
136 %token<token> T_ANDAND "&&"
137 %token<token> T_COLONCOLON "::"
138 %token<token> T_MINUSMINUS "--"
139 %token<token> T_PLUSPLUS "++"
140 %token<token> T_DOTDOT ".."
141 %token<token> T_DOTDOTDOT "..."
142 %token<token> T_SHL "<<"
143 %token<token> T_USHR ">>>"
144 %token<token> T_SHR ">>"
146 %type <id> X_IDENTIFIER PACKAGE
147 %type <token> VARCONST
149 %type <code> CODEPIECE
150 %type <code> CODEBLOCK MAYBECODE
151 %type <token> PACKAGE_DECLARATION
152 %type <token> FUNCTION_DECLARATION
153 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
154 %type <token> CLASS_DECLARATION
155 %type <token> NAMESPACE_DECLARATION
156 %type <token> INTERFACE_DECLARATION
157 %type <code> VOIDEXPRESSION
158 %type <value> EXPRESSION NONCOMMAEXPRESSION
159 %type <value> MAYBEEXPRESSION
160 %type <value> E DELETE
161 %type <value> CONSTANT
162 %type <code> FOR IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
163 %type <token> USE_NAMESPACE
164 %type <code> FOR_INIT
166 %type <classinfo> MAYBETYPE
169 %type <params> PARAM_LIST
170 %type <params> MAYBE_PARAM_LIST
171 %type <flags> MAYBE_MODIFIERS
172 %type <flags> MODIFIER_LIST
173 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
174 %type <classinfo_list> IMPLEMENTS_LIST
175 %type <classinfo> EXTENDS
176 %type <classinfo_list> EXTENDS_LIST
177 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
178 %type <classinfo_list> QNAME_LIST
179 %type <classinfo> TYPE
181 //%type <token> VARIABLE
182 %type <value> VAR_READ
184 //%type <token> T_IDENTIFIER
185 %type <token> MODIFIER
186 %type <value> FUNCTIONCALL
187 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
189 // precedence: from low to high
193 %left below_semicolon
196 %nonassoc below_assignment // for ?:, contrary to spec
197 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
204 %nonassoc "==" "!=" "===" "!=="
206 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
207 %left "<<" ">>" ">>>"
211 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
213 %nonassoc below_curly
214 %left '[' ']' '{' "new" '.' ".." "::"
215 %nonassoc T_IDENTIFIER
220 // needed for "return" precedence:
221 %nonassoc T_STRING T_REGEXP
222 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
223 %nonassoc "false" "true" "null" "undefined" "super"
229 static int yyerror(char*s)
231 syntaxerror("%s", s);
233 static char* concat3str(const char* t1, const char* t2, const char* t3)
238 char*text = malloc(l1+l2+l3+1);
239 memcpy(text , t1, l1);
240 memcpy(text+l1, t2, l2);
241 memcpy(text+l1+l2, t3, l3);
246 typedef struct _import {
250 DECLARE_LIST(import);
252 typedef struct _classstate {
258 char has_constructor;
261 typedef struct _methodstate {
265 /* code that needs to be executed at the start of
266 a method (like initializing local registers) */
272 typedef struct _state {
276 import_list_t*wildcard_imports;
278 char has_own_imports;
281 methodstate_t*method;
286 typedef struct _global {
293 static global_t*global = 0;
294 static state_t* state = 0;
298 #define MULTINAME(m,x) \
301 registry_fill_multiname(&m, &m##_ns, x);
303 #define MEMBER_MULTINAME(m,f,n) \
307 m##_ns.access = flags2access(f->flags); \
311 m.namespace_set = 0; \
314 m.type = MULTINAME; \
316 m.namespace_set = &nopackage_namespace_set; \
320 /* warning: list length of namespace set is undefined */
321 #define MULTINAME_LATE(m, access, package) \
322 namespace_t m##_ns = {access, package}; \
323 namespace_set_t m##_nsset; \
324 namespace_list_t m##_l;m##_l.next = 0; \
325 m##_nsset.namespaces = &m##_l; \
326 m##_nsset = m##_nsset; \
327 m##_l.namespace = &m##_ns; \
328 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
330 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
331 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
332 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
333 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
334 static namespace_list_t nl4 = {&ns4,0};
335 static namespace_list_t nl3 = {&ns3,&nl4};
336 static namespace_list_t nl2 = {&ns2,&nl3};
337 static namespace_list_t nl1 = {&ns1,&nl2};
338 static namespace_set_t nopackage_namespace_set = {&nl1};
340 static state_list_t*state_stack=0;
342 static void init_globals()
344 global = rfx_calloc(sizeof(global_t));
347 static void new_state()
350 NEW(state_list_t, sl);
352 state_t*oldstate = state;
354 memcpy(s, state, sizeof(state_t)); //shallow copy
355 sl->next = state_stack;
358 s->imports = dict_new();
363 state->has_own_imports = 0;
364 state->vars = dict_new();
366 static void state_has_imports()
368 state->wildcard_imports = list_clone(state->wildcard_imports);
369 state->imports = dict_clone(state->imports);
370 state->has_own_imports = 1;
373 static void old_state()
375 if(!state_stack || !state_stack->next)
376 syntaxerror("invalid nesting");
377 state_t*oldstate = state;
378 state_list_t*old = state_stack;
379 state_stack = state_stack->next;
381 state = state_stack->state;
382 /*if(state->method->initcode) {
383 printf("residual initcode\n");
384 code_dump(state->method->initcode, 0, 0, "", stdout);
386 if(oldstate->has_own_imports) {
387 list_free(oldstate->wildcard_imports);
388 dict_destroy(oldstate->imports);oldstate->imports=0;
391 void initialize_state()
396 global->file = abc_file_new();
397 global->file->flags &= ~ABCFILE_LAZY;
399 global->init = abc_initscript(global->file, 0);
400 code_t*c = global->init->method->body->code;
402 c = abc_getlocal_0(c);
403 c = abc_pushscope(c);
405 /* findpropstrict doesn't just return a scope object- it
406 also makes it "active" somehow. Push local_0 on the
407 scope stack and read it back with findpropstrict, it'll
408 contain properties like "trace". Trying to find the same
409 property on a "vanilla" local_0 yields only a "undefined" */
410 //c = abc_findpropstrict(c, "[package]::trace");
412 /*c = abc_getlocal_0(c);
413 c = abc_findpropstrict(c, "[package]::trace");
415 c = abc_setlocal_1(c);
417 c = abc_pushbyte(c, 0);
418 c = abc_setlocal_2(c);
420 code_t*xx = c = abc_label(c);
421 c = abc_findpropstrict(c, "[package]::trace");
422 c = abc_pushstring(c, "prop:");
423 c = abc_hasnext2(c, 1, 2);
425 c = abc_setlocal_3(c);
426 c = abc_callpropvoid(c, "[package]::trace", 2);
427 c = abc_getlocal_3(c);
429 c = abc_iftrue(c,xx);*/
431 c = abc_findpropstrict(c, "[package]::trace");
432 c = abc_pushstring(c, "[entering global init function]");
433 c = abc_callpropvoid(c, "[package]::trace", 1);
435 global->init->method->body->code = c;
437 void* finalize_state()
439 if(state->level!=1) {
440 syntaxerror("unexpected end of file");
442 abc_method_body_t*m = global->init->method->body;
445 __ findpropstrict(m, "[package]::trace");
446 __ pushstring(m, "[leaving global init function]");
447 __ callpropvoid(m, "[package]::trace", 1);
453 static void startpackage(char*name)
456 syntaxerror("Packages can not be nested.");
459 /*printf("entering package \"%s\"\n", name);*/
460 state->package = name;
462 static void endpackage()
464 /*printf("leaving package \"%s\"\n", state->package);*/
469 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
472 syntaxerror("inner classes now allowed");
475 state->cls = rfx_calloc(sizeof(classstate_t));
478 classinfo_list_t*mlist=0;
479 /*printf("entering class %s\n", name);
480 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
482 printf(" extends: %s.%s\n", extends->package, extends->name);
483 printf(" implements (%d): ", list_length(implements));
484 for(mlist=implements;mlist;mlist=mlist->next) {
485 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
490 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
491 syntaxerror("invalid modifier(s)");
493 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
494 syntaxerror("public and internal not supported at the same time.");
496 /* create the class name, together with the proper attributes */
500 if(!(flags&FLAG_PUBLIC) && !state->package) {
501 access = ACCESS_PRIVATE; package = current_filename;
502 } else if(!(flags&FLAG_PUBLIC) && state->package) {
503 access = ACCESS_PACKAGEINTERNAL; package = state->package;
504 } else if(state->package) {
505 access = ACCESS_PACKAGE; package = state->package;
507 syntaxerror("public classes only allowed inside a package");
510 if(registry_findclass(package, classname)) {
511 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
515 /* build info struct */
516 int num_interfaces = (list_length(implements));
517 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
518 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
520 classinfo_list_t*l = implements;
521 for(l=implements;l;l=l->next) {
522 state->cls->info->interfaces[pos++] = l->classinfo;
525 multiname_t*extends2 = sig2mname(extends);
527 MULTINAME(classname2,state->cls->info);
530 state->cls_init = abc_getlocal_0(state->cls_init);
531 state->cls_init = abc_constructsuper(state->cls_init, 0);
534 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
535 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
536 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
538 state->cls->info->flags |= CLASS_INTERFACE;
539 abc_class_interface(state->cls->abc);
542 abc_class_protectedNS(state->cls->abc, classname);
544 for(mlist=implements;mlist;mlist=mlist->next) {
545 MULTINAME(m, mlist->classinfo);
546 abc_class_add_interface(state->cls->abc, &m);
549 /* now write the construction code for this class */
550 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
552 abc_method_body_t*m = global->init->method->body;
553 __ getglobalscope(m);
554 classinfo_t*s = extends;
559 //TODO: take a look at the current scope stack, maybe
560 // we can re-use something
565 multiname_t*s2 = sig2mname(s);
567 multiname_destroy(s2);
569 __ pushscope(m); count++;
570 m->code = m->code->prev->prev; // invert
572 /* continue appending after last op end */
573 while(m->code && m->code->next) m->code = m->code->next;
575 /* TODO: if this is one of *our* classes, we can also
576 do a getglobalscope/getslot <nr> (which references
577 the init function's slots) */
579 __ getlex2(m, extends2);
581 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
582 stack is not the superclass */
583 __ pushscope(m);count++;
586 /* notice: we get a verify error #1107 if the top element on the scope
587 stack is not the global object */
589 __ pushscope(m);count++;
591 __ newclass(m,state->cls->abc);
595 __ setslot(m, slotindex);
597 /* flash.display.MovieClip handling */
598 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
599 if(state->package && state->package[0]) {
600 globalclass = concat3str(state->package, ".", classname);
602 globalclass = strdup(classname);
605 multiname_destroy(extends2);
608 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
610 c = code_append(c, initcode);
611 c = code_append(c, body);
612 /* append return if necessary */
613 if(!c || c->opcode != OPCODE_RETURNVOID &&
614 c->opcode != OPCODE_RETURNVALUE) {
615 c = abc_returnvoid(c);
620 static void endclass()
622 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
624 c = abc_getlocal_0(c);
625 c = abc_constructsuper(c, 0);
626 state->cls->init = code_append(state->cls->init, c);
629 if(state->cls->init) {
630 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
631 m->body->code = wrap_function(0, state->cls->init, m->body->code);
633 if(state->cls->static_init) {
634 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
635 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
637 // handy for scope testing
641 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
647 typedef struct _variable {
652 static int find_variable(char*name, classinfo_t**m)
654 state_list_t* s = state_stack;
658 v = dict_lookup(s->state->vars, name);
669 static int find_variable_safe(char*name, classinfo_t**m)
671 int i = find_variable(name, m);
673 syntaxerror("undefined variable: %s", name);
676 static char variable_exists(char*name)
678 return dict_lookup(state->vars, name)!=0;
680 static int new_variable(char*name, classinfo_t*type)
683 v->index = global->variable_count;
685 dict_put(state->vars, name, v);
686 return global->variable_count++;
688 #define TEMPVARNAME "__as3_temp__"
689 static int gettempvar()
691 int i = find_variable(TEMPVARNAME, 0);
693 i = new_variable(TEMPVARNAME, 0);
698 code_t* killvars(code_t*c)
701 for(t=0;t<state->vars->hashsize;t++) {
702 dictentry_t*e =state->vars->slots[t];
704 variable_t*v = (variable_t*)e->data;
705 //do this always, otherwise register types don't match
706 //in the verifier when doing nested loops
707 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
708 c = abc_kill(c, v->index);
715 void check_code_for_break(code_t*c)
718 if(c->opcode == OPCODE___BREAK__) {
719 char*name = string_cstr(c->data[0]);
720 syntaxerror("Unresolved \"break %s\"", name);
722 if(c->opcode == OPCODE___CONTINUE__) {
723 char*name = string_cstr(c->data[0]);
724 syntaxerror("Unresolved \"continue %s\"", name);
731 static void check_constant_against_type(classinfo_t*t, constant_t*c)
733 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
734 if(TYPE_IS_NUMBER(t)) {
735 xassert(c->type == CONSTANT_FLOAT
736 || c->type == CONSTANT_INT
737 || c->type == CONSTANT_UINT);
738 } else if(TYPE_IS_UINT(t)) {
739 xassert(c->type == CONSTANT_UINT ||
740 (c->type == CONSTANT_INT && c->i>0));
741 } else if(TYPE_IS_INT(t)) {
742 xassert(c->type == CONSTANT_INT);
743 } else if(TYPE_IS_BOOLEAN(t)) {
744 xassert(c->type == CONSTANT_TRUE
745 || c->type == CONSTANT_FALSE);
749 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
751 memberinfo_t*minfo = 0;
752 if(getset != KW_GET && getset != KW_SET) {
753 if(registry_findmember(state->cls->info, name)) {
754 syntaxerror("class already contains a member/method called '%s'", name);
756 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
757 minfo->return_type = return_type;
758 // getslot on a member slot only returns "undefined", so no need
759 // to actually store these
760 //state->minfo->slot = state->method->abc->method->trait->slot_id;
762 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
766 else if(params->list)
767 type = params->list->param->type;
768 if((minfo=registry_findmember(state->cls->info, name))) {
769 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
770 syntaxerror("class already contains a member or method called '%s'", name);
772 syntaxerror("getter/setter for '%s' already defined", name);
773 /* make a setter or getter into a getset */
778 if(type && minfo->type != type)
779 syntaxerror("different type in getter and setter");
781 minfo = memberinfo_register(state->cls->info, name, gs);
784 /* can't assign a slot as getter and setter might have different slots */
785 //minfo->slot = slot;
787 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
788 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
789 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
790 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
791 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
795 static int flags2access(int flags)
798 if(flags&FLAG_PUBLIC) {
799 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
800 access = ACCESS_PACKAGE;
801 } else if(flags&FLAG_PRIVATE) {
802 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
803 access = ACCESS_PRIVATE;
804 } else if(flags&FLAG_PROTECTED) {
805 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
806 access = ACCESS_PROTECTED;
808 access = ACCESS_PACKAGEINTERNAL;
813 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
814 params_t*params, classinfo_t*return_type)
817 syntaxerror("not able to start another method scope");
820 state->method = rfx_calloc(sizeof(methodstate_t));
821 state->method->initcode = 0;
822 state->method->is_constructor = !strcmp(state->cls->info->name,name);
823 state->method->has_super = 0;
825 state->cls->has_constructor |= state->method->is_constructor;
827 global->variable_count = 0;
829 /* state->vars is initialized by state_new */
830 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
832 for(p=params->list;p;p=p->next) {
833 new_variable(p->param->name, p->param->type);
835 if(state->method->is_constructor)
836 name = "__as3_constructor__";
837 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
840 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
841 params_t*params, classinfo_t*return_type, code_t*body)
843 namespace_t mname_ns = {flags2access(flags), ""};
844 multiname_t mname = {QNAME, &mname_ns, 0, name};
848 multiname_t*type2 = sig2mname(return_type);
850 if(state->method->is_constructor) {
851 f = abc_class_getconstructor(state->cls->abc, type2);
853 if(flags&FLAG_STATIC)
854 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
856 f = abc_class_method(state->cls->abc, type2, &mname);
857 slot = f->trait->slot_id;
859 //flash doesn't seem to allow us to access function slots
860 //state->method->info->slot = slot;
862 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
863 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
864 if(params->varargs) f->flags |= METHOD_NEED_REST;
868 for(p=params->list;p;p=p->next) {
869 if(params->varargs && !p->next) {
870 break; //varargs: omit last parameter in function signature
872 multiname_t*m = sig2mname(p->param->type);
873 list_append(f->parameters, m);
874 if(p->param->value) {
875 check_constant_against_type(p->param->type, p->param->value);
876 opt=1;list_append(f->optional_parameters, p->param->value);
878 syntaxerror("non-optional parameter not allowed after optional parameters");
881 check_code_for_break(body);
884 f->body->code = body;
887 syntaxerror("interface methods can't have a method body");
894 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
899 void breakjumpsto(code_t*c, char*name, code_t*jump)
902 if(c->opcode == OPCODE___BREAK__) {
903 string_t*name2 = c->data[0];
904 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
905 c->opcode = OPCODE_JUMP;
912 void continuejumpsto(code_t*c, char*name, code_t*jump)
915 if(c->opcode == OPCODE___CONTINUE__) {
916 string_t*name2 = c->data[0];
917 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
918 c->opcode = OPCODE_JUMP;
926 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
929 return registry_getanytype();
930 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
931 return registry_getanytype();
934 return registry_getanytype();
936 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
941 return abc_coerce_a(c);
945 // cast an "any" type to a specific type. subject to
946 // runtime exceptions
947 return abc_coerce2(c, &m);
950 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
951 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
952 // allow conversion between number types
953 return abc_coerce2(c, &m);
955 //printf("%s.%s\n", from.package, from.name);
956 //printf("%s.%s\n", to.package, to.name);
958 classinfo_t*supertype = from;
960 if(supertype == to) {
961 // target type is one of from's superclasses
962 return abc_coerce2(c, &m);
965 while(supertype->interfaces[t]) {
966 if(supertype->interfaces[t]==to) {
967 // target type is one of from's interfaces
968 return abc_coerce2(c, &m);
972 supertype = supertype->superclass;
974 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
976 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
978 syntaxerror("can't convert type %s to %s", from->name, to->name);
981 code_t*defaultvalue(code_t*c, classinfo_t*type)
983 if(TYPE_IS_INT(type)) {
984 c = abc_pushbyte(c, 0);
985 } else if(TYPE_IS_UINT(type)) {
986 c = abc_pushuint(c, 0);
987 } else if(TYPE_IS_FLOAT(type)) {
989 } else if(TYPE_IS_BOOLEAN(type)) {
990 c = abc_pushfalse(c);
997 char is_pushundefined(code_t*c)
999 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1002 void parserassert(int b)
1004 if(!b) syntaxerror("internal error: assertion failed");
1007 static classinfo_t* find_class(char*name)
1011 c = registry_findclass(state->package, name);
1013 /* try explicit imports */
1014 dictentry_t* e = dict_get_slot(state->imports, name);
1018 if(!strcmp(e->key, name)) {
1019 c = (classinfo_t*)e->data;
1024 /* try package.* imports */
1025 import_list_t*l = state->wildcard_imports;
1029 //printf("does package %s contain a class %s?\n", l->import->package, name);
1030 c = registry_findclass(l->import->package, name);
1034 /* try global package */
1036 c = registry_findclass("", name);
1041 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1045 [prefix code] [read instruction]
1049 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1052 if(in && in->opcode == OPCODE_COERCE_A) {
1053 in = code_cutlast(in);
1056 syntaxerror("internal error");
1058 /* chop off read instruction */
1062 prefix = r->prev;r->prev = 0;
1068 char use_temp_var = readbefore;
1070 /* generate the write instruction, and maybe append a dup to the prefix code */
1071 code_t* write = abc_nop(0);
1072 if(r->opcode == OPCODE_GETPROPERTY) {
1073 write->opcode = OPCODE_SETPROPERTY;
1074 multiname_t*m = (multiname_t*)r->data[0];
1075 write->data[0] = multiname_clone(m);
1076 if(m->type == QNAME || m->type == MULTINAME) {
1078 prefix = abc_dup(prefix); // we need the object, too
1081 } else if(m->type == MULTINAMEL) {
1083 /* dupping two values on the stack requires 5 operations and one register-
1084 couldn't adobe just have given us a dup2? */
1085 int temp = gettempvar();
1086 prefix = abc_setlocal(prefix, temp);
1087 prefix = abc_dup(prefix);
1088 prefix = abc_getlocal(prefix, temp);
1089 prefix = abc_swap(prefix);
1090 prefix = abc_getlocal(prefix, temp);
1094 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1096 } else if(r->opcode == OPCODE_GETSLOT) {
1097 write->opcode = OPCODE_SETSLOT;
1098 write->data[0] = r->data[0];
1100 prefix = abc_dup(prefix); // we need the object, too
1103 } else if(r->opcode == OPCODE_GETLOCAL) {
1104 write->opcode = OPCODE_SETLOCAL;
1105 write->data[0] = r->data[0];
1106 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1107 write->opcode = OPCODE_SETLOCAL_0;
1108 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1109 write->opcode = OPCODE_SETLOCAL_1;
1110 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1111 write->opcode = OPCODE_SETLOCAL_2;
1112 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1113 write->opcode = OPCODE_SETLOCAL_3;
1115 code_dump(r, 0, 0, "", stdout);
1116 syntaxerror("illegal lvalue: can't assign a value to this expression");
1123 /* with getproperty/getslot, we have to be extra careful not
1124 to execute the read code twice, as it might have side-effects
1125 (e.g. if the property is in fact a setter/getter combination)
1127 So read the value, modify it, and write it again,
1128 using prefix only once and making sure (by using a temporary
1129 register) that the return value is what we just wrote */
1130 temp = gettempvar();
1131 c = code_append(c, prefix);
1132 c = code_append(c, r);
1135 c = abc_setlocal(c, temp);
1137 c = code_append(c, middlepart);
1140 c = abc_setlocal(c, temp);
1142 c = code_append(c, write);
1143 c = abc_getlocal(c, temp);
1144 c = abc_kill(c, temp);
1146 /* if we're allowed to execute the read code twice *and*
1147 the middlepart doesn't modify the code, things are easier.
1149 code_t* r2 = code_dup(r);
1150 //c = code_append(c, prefix);
1151 parserassert(!prefix);
1152 c = code_append(c, r);
1153 c = code_append(c, middlepart);
1154 c = code_append(c, write);
1155 c = code_append(c, r2);
1158 /* even smaller version: overwrite the value without reading
1162 c = code_append(c, prefix);
1165 c = code_append(c, middlepart);
1166 c = code_append(c, write);
1167 c = code_append(c, r);
1169 temp = gettempvar();
1171 c = code_append(c, prefix);
1174 c = code_append(c, middlepart);
1176 c = abc_setlocal(c, temp);
1177 c = code_append(c, write);
1178 c = abc_getlocal(c, temp);
1185 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1186 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1193 /* ------------ code blocks / statements ---------------- */
1197 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1198 MAYBECODE: {$$=code_new();}
1200 CODE: CODE CODEPIECE {
1201 $$=code_append($1,$2);
1207 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1208 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1209 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1210 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1211 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1212 CODEPIECE: ';' {$$=code_new();}
1213 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1214 CODEPIECE: VOIDEXPRESSION {$$=$1}
1215 CODEPIECE: FOR {$$=$1}
1216 CODEPIECE: WHILE {$$=$1}
1217 CODEPIECE: DO_WHILE {$$=$1}
1218 CODEPIECE: BREAK {$$=$1}
1219 CODEPIECE: CONTINUE {$$=$1}
1220 CODEPIECE: RETURN {$$=$1}
1221 CODEPIECE: IF {$$=$1}
1222 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1223 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1225 CODEBLOCK : '{' CODE '}' {$$=$2;}
1226 CODEBLOCK : '{' '}' {$$=0;}
1227 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1228 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1230 /* ------------ variables --------------------------- */
1232 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1233 | {$$.c=abc_pushundefined(0);
1237 VAR : "const" | "var"
1238 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1240 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1241 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1243 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1245 if(variable_exists($2))
1246 syntaxerror("Variable %s already defined", $2);
1248 if(!is_subtype_of($4.t, $3)) {
1249 syntaxerror("Can't convert %s to %s", $4.t->name,
1253 int index = new_variable($2, $3);
1256 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1258 $$ = converttype($$, $4.t, $3);
1259 $$ = abc_setlocal($$, index);
1261 $$ = defaultvalue(0, $3);
1262 $$ = abc_setlocal($$, index);
1265 /* if this is a typed variable:
1266 push default value for type on stack */
1268 state->method->initcode = defaultvalue(state->method->initcode, $3);
1269 state->method->initcode = abc_setlocal(state->method->initcode, index);
1272 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1274 $$ = abc_coerce_a($$);
1275 $$ = abc_setlocal($$, index);
1281 /* that's the default for a local register, anyway
1283 state->method->initcode = abc_pushundefined(state->method->initcode);
1284 state->method->initcode = abc_setlocal(state->method->initcode, index);
1286 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1289 /* ------------ control flow ------------------------- */
1291 MAYBEELSE: %prec below_else {$$ = code_new();}
1292 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1293 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1295 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1297 $$ = code_append($$, $4.c);
1298 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1300 $$ = code_append($$, $6);
1302 myjmp = $$ = abc_jump($$, 0);
1304 myif->branch = $$ = abc_nop($$);
1306 $$ = code_append($$, $7);
1307 myjmp->branch = $$ = abc_nop($$);
1310 $$ = killvars($$);old_state();
1313 FOR_INIT : {$$=code_new();}
1314 FOR_INIT : VARIABLE_DECLARATION
1315 FOR_INIT : VOIDEXPRESSION
1317 FOR : T_FOR '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1319 $$ = code_append($$, $4);
1320 code_t*loopstart = $$ = abc_label($$);
1321 $$ = code_append($$, $6.c);
1322 code_t*myif = $$ = abc_iffalse($$, 0);
1323 $$ = code_append($$, $10);
1324 code_t*cont = $$ = abc_nop($$);
1325 $$ = code_append($$, $8);
1326 $$ = abc_jump($$, loopstart);
1327 code_t*out = $$ = abc_nop($$);
1328 breakjumpsto($$, $1, out);
1329 continuejumpsto($$, $1, cont);
1332 $$ = killvars($$);old_state();
1335 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1338 code_t*myjmp = $$ = abc_jump($$, 0);
1339 code_t*loopstart = $$ = abc_label($$);
1340 $$ = code_append($$, $6);
1341 code_t*cont = $$ = abc_nop($$);
1342 myjmp->branch = cont;
1343 $$ = code_append($$, $4.c);
1344 $$ = abc_iftrue($$, loopstart);
1345 code_t*out = $$ = abc_nop($$);
1346 breakjumpsto($$, $1, out);
1347 continuejumpsto($$, $1, cont);
1353 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1355 code_t*loopstart = $$ = abc_label($$);
1356 $$ = code_append($$, $3);
1357 code_t*cont = $$ = abc_nop($$);
1358 $$ = code_append($$, $6.c);
1359 $$ = abc_iftrue($$, loopstart);
1360 code_t*out = $$ = abc_nop($$);
1361 breakjumpsto($$, $1, out);
1362 continuejumpsto($$, $1, cont);
1367 BREAK : "break" %prec prec_none {
1368 $$ = abc___break__(0, "");
1370 BREAK : "break" T_IDENTIFIER {
1371 $$ = abc___break__(0, $2);
1373 CONTINUE : "continue" %prec prec_none {
1374 $$ = abc___continue__(0, "");
1376 CONTINUE : "continue" T_IDENTIFIER {
1377 $$ = abc___continue__(0, $2);
1380 /* ------------ packages and imports ---------------- */
1382 X_IDENTIFIER: T_IDENTIFIER
1383 | "package" {$$="package";}
1385 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1386 PACKAGE: X_IDENTIFIER {$$=$1;}
1388 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1389 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1391 IMPORT : "import" QNAME {
1394 syntaxerror("Couldn't import class\n");
1395 state_has_imports();
1396 dict_put(state->imports, c->name, c);
1399 IMPORT : "import" PACKAGE '.' '*' {
1402 state_has_imports();
1403 list_append(state->wildcard_imports, i);
1407 /* ------------ classes and interfaces (header) -------------- */
1409 MAYBE_MODIFIERS : {$$=0;}
1410 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1411 MODIFIER_LIST : MODIFIER {$$=$1;}
1412 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1414 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1415 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1416 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1417 | KW_STATIC {$$=FLAG_STATIC;}
1418 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1419 | KW_FINAL {$$=FLAG_FINAL;}
1420 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1421 | KW_NATIVE {$$=FLAG_NATIVE;}
1422 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1424 EXTENDS : {$$=registry_getobjectclass();}
1425 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1427 EXTENDS_LIST : {$$=list_new();}
1428 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1430 IMPLEMENTS_LIST : {$$=list_new();}
1431 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1433 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1434 EXTENDS IMPLEMENTS_LIST
1435 '{' {startclass($1,$3,$4,$5, 0);}
1436 MAYBE_DECLARATION_LIST
1439 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1441 '{' {startclass($1,$3,0,$4,1);}
1442 MAYBE_IDECLARATION_LIST
1445 /* ------------ classes and interfaces (body) -------------- */
1447 MAYBE_DECLARATION_LIST :
1448 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1449 DECLARATION_LIST : DECLARATION
1450 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1452 DECLARATION : SLOT_DECLARATION
1453 DECLARATION : FUNCTION_DECLARATION
1455 MAYBE_IDECLARATION_LIST :
1456 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1457 IDECLARATION_LIST : IDECLARATION
1458 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1460 IDECLARATION : "var" T_IDENTIFIER {
1461 syntaxerror("variable declarations not allowed in interfaces");
1463 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1465 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1466 syntaxerror("invalid method modifiers: interface methods always need to be public");
1468 startfunction(0,$1,$3,$4,&$6,$8);
1469 endfunction(0,$1,$3,$4,&$6,$8, 0);
1472 /* ------------ classes and interfaces (body, slots ) ------- */
1474 VARCONST: "var" | "const"
1476 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1478 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1480 info->flags = flags;
1483 namespace_t mname_ns = {flags2access(flags), ""};
1484 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1486 if(!(flags&FLAG_STATIC)) {
1489 t=abc_class_slot(state->cls->abc, &mname, &m);
1491 t=abc_class_slot(state->cls->abc, &mname, 0);
1493 info->slot = t->slot_id;
1497 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1499 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1501 info->slot = t->slot_id;
1503 if($5.c && !is_pushundefined($5.c)) {
1505 c = abc_getlocal_0(c);
1506 c = code_append(c, $5.c);
1507 c = converttype(c, $5.t, $4);
1508 c = abc_setslot(c, t->slot_id);
1509 if(!(flags&FLAG_STATIC))
1510 state->cls->init = code_append(state->cls->init, c);
1512 state->cls->static_init = code_append(state->cls->static_init, c);
1515 t->kind= TRAIT_CONST;
1519 /* ------------ constants -------------------------------------- */
1521 MAYBESTATICCONSTANT: {$$=0;}
1522 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1524 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1525 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1526 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1527 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1528 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1529 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1530 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1531 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1532 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1534 /* ------------ classes and interfaces (body, functions) ------- */
1536 // non-vararg version
1538 memset(&$$,0,sizeof($$));
1540 MAYBE_PARAM_LIST: PARAM_LIST {
1545 MAYBE_PARAM_LIST: "..." PARAM {
1546 memset(&$$,0,sizeof($$));
1548 list_append($$.list, $2);
1550 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1553 list_append($$.list, $4);
1557 PARAM_LIST: PARAM_LIST ',' PARAM {
1559 list_append($$.list, $3);
1562 memset(&$$,0,sizeof($$));
1563 list_append($$.list, $1);
1566 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1567 $$ = malloc(sizeof(param_t));
1572 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1573 $$ = malloc(sizeof(param_t));
1575 $$->type = TYPE_ANY;
1578 GETSET : "get" {$$=$1;}
1582 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1583 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1586 if(state->method->late_binding) {
1587 c = abc_getlocal_0(c);
1588 c = abc_pushscope(c);
1590 if(state->method->is_constructor && !state->method->has_super) {
1591 // call default constructor
1592 c = abc_getlocal_0(c);
1593 c = abc_constructsuper(c, 0);
1595 c = wrap_function(c, state->method->initcode, $11);
1596 endfunction(0,$1,$3,$4,&$6,$8,c);
1599 /* ------------- package + class ids --------------- */
1601 CLASS: T_IDENTIFIER {
1603 /* try current package */
1604 $$ = find_class($1);
1605 if(!$$) syntaxerror("Could not find class %s\n", $1);
1608 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1609 $$ = registry_findclass($1, $3);
1610 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1613 QNAME: PACKAGEANDCLASS
1616 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1617 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1619 TYPE : QNAME {$$=$1;}
1620 | '*' {$$=registry_getanytype();}
1621 | "void" {$$=registry_getanytype();}
1623 | "String" {$$=registry_getstringclass();}
1624 | "int" {$$=registry_getintclass();}
1625 | "uint" {$$=registry_getuintclass();}
1626 | "Boolean" {$$=registry_getbooleanclass();}
1627 | "Number" {$$=registry_getnumberclass();}
1630 MAYBETYPE: ':' TYPE {$$=$2;}
1633 /* ----------function calls, delete, constructor calls ------ */
1635 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1636 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1638 MAYBE_EXPRESSION_LIST : {$$=0;}
1639 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1640 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1641 typedcode_t*t = malloc(sizeof(typedcode_t));
1643 list_append($$, t);}
1644 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1645 typedcode_t*t = malloc(sizeof(typedcode_t));
1647 list_append($$, t);}
1649 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1654 $$.c = abc_getglobalscope($$.c);
1655 $$.c = abc_getslot($$.c, $2->slot);
1657 $$.c = abc_findpropstrict2($$.c, &m);
1660 typedcode_list_t*l = $3;
1663 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1668 $$.c = abc_construct($$.c, len);
1670 $$.c = abc_constructprop2($$.c, &m, len);
1674 /* TODO: use abc_call (for calling local variables),
1675 abc_callstatic (for calling own methods)
1678 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1679 typedcode_list_t*l = $3;
1681 code_t*paramcode = 0;
1683 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1689 if($$.c->opcode == OPCODE_COERCE_A) {
1690 $$.c = code_cutlast($$.c);
1694 multiname_t*name = 0;
1695 if($$.c->opcode == OPCODE_GETPROPERTY) {
1696 name = multiname_clone($$.c->data[0]);
1697 $$.c = code_cutlast($$.c);
1698 $$.c = code_append($$.c, paramcode);
1699 $$.c = abc_callproperty2($$.c, name, len);
1700 } else if($$.c->opcode == OPCODE_GETSLOT) {
1701 int slot = (int)(ptroff_t)$$.c->data[0];
1702 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1703 if(t->kind!=TRAIT_METHOD) {
1704 //ok: flash allows to assign closures to members.
1707 $$.c = code_cutlast($$.c);
1708 $$.c = code_append($$.c, paramcode);
1709 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1710 $$.c = abc_callproperty2($$.c, name, len);
1711 } else if($$.c->opcode == OPCODE_GETSUPER) {
1712 name = multiname_clone($$.c->data[0]);
1713 $$.c = code_cutlast($$.c);
1714 $$.c = code_append($$.c, paramcode);
1715 $$.c = abc_callsuper2($$.c, name, len);
1717 $$.c = abc_getlocal_0($$.c);
1718 $$.c = code_append($$.c, paramcode);
1719 $$.c = abc_call($$.c, len);
1724 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1725 $$.t = $1.t->function->return_type;
1727 $$.c = abc_coerce_a($$.c);
1731 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1732 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1733 if(!state->method) syntaxerror("super() not allowed outside of a function");
1734 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1737 $$.c = abc_getlocal_0($$.c);
1738 typedcode_list_t*l = 0;
1740 for(l=$3;l;l=l->next) {
1741 $$.c = code_append($$.c, l->typedcode->c);len++;
1744 this is dependent on the control path, check this somewhere else
1745 if(state->method->has_super)
1746 syntaxerror("constructor may call super() only once");
1748 state->method->has_super = 1;
1749 $$.c = abc_constructsuper($$.c, len);
1750 $$.c = abc_pushundefined($$.c);
1754 DELETE: "delete" E {
1756 if($$.c->opcode == OPCODE_COERCE_A) {
1757 $$.c = code_cutlast($$.c);
1759 multiname_t*name = 0;
1760 if($$.c->opcode == OPCODE_GETPROPERTY) {
1761 $$.c->opcode = OPCODE_DELETEPROPERTY;
1762 } else if($$.c->opcode == OPCODE_GETSLOT) {
1763 int slot = (int)(ptroff_t)$$.c->data[0];
1764 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1765 $$.c = code_cutlast($$.c);
1766 $$.c = abc_deleteproperty2($$.c, name);
1768 $$.c = abc_getlocal_0($$.c);
1769 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1770 $$.c = abc_deleteproperty2($$.c, &m);
1772 $$.t = TYPE_BOOLEAN;
1775 RETURN: "return" %prec prec_none {
1776 $$ = abc_returnvoid(0);
1778 RETURN: "return" EXPRESSION {
1780 $$ = abc_returnvalue($$);
1783 // ----------------------- expression types -------------------------------------
1785 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1786 EXPRESSION : E %prec below_minus {$$ = $1;}
1787 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1789 $$.c = cut_last_push($$.c);
1790 $$.c = code_append($$.c,$3.c);
1793 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1794 $$=cut_last_push($1.c);
1797 // ----------------------- expression evaluation -------------------------------------
1800 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1802 E : DELETE {$$ = $1;}
1803 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1807 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1808 //MULTINAME(m, registry_getintclass());
1809 //$$.c = abc_coerce2($$.c, &m); // FIXME
1812 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1815 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1818 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1821 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1824 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1827 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1830 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1831 $$.t = TYPE_BOOLEAN;
1833 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1834 $$.t = TYPE_BOOLEAN;
1836 CONSTANT : "null" {$$.c = abc_pushnull(0);
1841 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1842 $$.t = TYPE_BOOLEAN;
1844 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1845 $$.t = TYPE_BOOLEAN;
1847 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1848 $$.t = TYPE_BOOLEAN;
1850 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1851 $$.t = TYPE_BOOLEAN;
1853 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1854 $$.t = TYPE_BOOLEAN;
1856 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1857 $$.t = TYPE_BOOLEAN;
1859 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1860 $$.t = TYPE_BOOLEAN;
1862 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1863 $$.t = TYPE_BOOLEAN;
1866 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1868 $$.c = converttype($$.c, $1.t, $$.t);
1869 $$.c = abc_dup($$.c);
1870 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1871 $$.c = cut_last_push($$.c);
1872 $$.c = code_append($$.c,$3.c);
1873 $$.c = converttype($$.c, $3.t, $$.t);
1874 code_t*label = $$.c = abc_label($$.c);
1875 jmp->branch = label;
1878 $$.t = join_types($1.t, $3.t, 'A');
1879 /*printf("%08x:\n",$1.t);
1880 code_dump($1.c, 0, 0, "", stdout);
1881 printf("%08x:\n",$3.t);
1882 code_dump($3.c, 0, 0, "", stdout);
1883 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1885 $$.c = converttype($$.c, $1.t, $$.t);
1886 $$.c = abc_dup($$.c);
1887 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1888 $$.c = cut_last_push($$.c);
1889 $$.c = code_append($$.c,$3.c);
1890 $$.c = converttype($$.c, $3.t, $$.t);
1891 code_t*label = $$.c = abc_label($$.c);
1892 jmp->branch = label;
1895 E : '!' E {$$.c=$2.c;
1896 $$.c = abc_not($$.c);
1897 $$.t = TYPE_BOOLEAN;
1900 E : '~' E {$$.c=$2.c;
1901 $$.c = abc_bitnot($$.c);
1905 E : E '&' E {$$.c = code_append($1.c,$3.c);
1906 $$.c = abc_bitand($$.c);
1910 E : E '^' E {$$.c = code_append($1.c,$3.c);
1911 $$.c = abc_bitxor($$.c);
1915 E : E '|' E {$$.c = code_append($1.c,$3.c);
1916 $$.c = abc_bitor($$.c);
1920 E : E '-' E {$$.c = code_append($1.c,$3.c);
1921 if(BOTH_INT($1,$3)) {
1922 $$.c = abc_subtract_i($$.c);
1925 $$.c = abc_subtract($$.c);
1929 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1930 $$.c = abc_rshift($$.c);
1933 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1934 $$.c = abc_urshift($$.c);
1937 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1938 $$.c = abc_lshift($$.c);
1942 E : E '/' E {$$.c = code_append($1.c,$3.c);
1943 $$.c = abc_divide($$.c);
1946 E : E '+' E {$$.c = code_append($1.c,$3.c);
1947 $$.c = abc_add($$.c);
1950 E : E '%' E {$$.c = code_append($1.c,$3.c);
1951 $$.c = abc_modulo($$.c);
1954 E : E '*' E {$$.c = code_append($1.c,$3.c);
1955 if(BOTH_INT($1,$3)) {
1956 $$.c = abc_multiply_i($$.c);
1959 $$.c = abc_multiply($$.c);
1964 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1965 if(use_astype && TYPE_IS_CLASS($3.t)) {
1966 MULTINAME(m,$3.t->cls);
1967 $$.c = abc_astype2($1.c, &m);
1970 $$.c = code_append($1.c, $3.c);
1971 $$.c = abc_astypelate($$.c);
1976 E : E "instanceof" E
1977 {$$.c = code_append($1.c, $3.c);
1978 $$.c = abc_instanceof($$.c);
1979 $$.t = TYPE_BOOLEAN;
1982 E : E "is" E {$$.c = code_append($1.c, $3.c);
1983 $$.c = abc_istypelate($$.c);
1984 $$.t = TYPE_BOOLEAN;
1987 E : "typeof" '(' E ')' {
1989 $$.c = abc_typeof($$.c);
1994 $$.c = cut_last_push($2.c);
1995 $$.c = abc_pushundefined($$.c);
1999 E : "void" { $$.c = abc_pushundefined(0);
2003 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2008 $$.c=abc_negate_i($$.c);
2011 $$.c=abc_negate($$.c);
2018 $$.c = code_append($$.c, $3.c);
2020 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2021 $$.c = abc_getproperty2($$.c, &m);
2022 $$.t = 0; // array elements have unknown type
2025 E : '[' MAYBE_EXPRESSION_LIST ']' {
2027 typedcode_list_t*l = 0;
2029 for(l=$2;l;l=l->next) {
2030 $$.c = code_append($$.c, l->typedcode->c);len++;
2032 $$.c = abc_newarray($$.c, len);
2033 $$.t = registry_getarrayclass();
2036 MAYBE_EXPRPAIR_LIST : {$$=0;}
2037 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2039 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2040 typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $1;
2041 typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $3;
2043 list_append($$, t1);
2044 list_append($$, t2);
2046 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2048 typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $3;
2049 typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $5;
2050 list_append($$, t1);
2051 list_append($$, t2);
2056 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2058 typedcode_list_t*l = 0;
2060 for(l=$2;l;l=l->next) {
2061 $$.c = code_append($$.c, l->typedcode->c);len++;
2063 $$.c = abc_newobject($$.c, len/2);
2064 $$.t = registry_getobjectclass();
2069 if(BOTH_INT($1,$3)) {
2070 c=abc_multiply_i(c);
2074 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2075 $$.c = toreadwrite($1.c, c, 0, 0);
2080 code_t*c = abc_modulo($3.c);
2081 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2082 $$.c = toreadwrite($1.c, c, 0, 0);
2086 code_t*c = abc_lshift($3.c);
2087 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2088 $$.c = toreadwrite($1.c, c, 0, 0);
2092 code_t*c = abc_rshift($3.c);
2093 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2094 $$.c = toreadwrite($1.c, c, 0, 0);
2098 code_t*c = abc_urshift($3.c);
2099 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2100 $$.c = toreadwrite($1.c, c, 0, 0);
2104 code_t*c = abc_divide($3.c);
2105 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2106 $$.c = toreadwrite($1.c, c, 0, 0);
2111 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2116 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2118 $$.c = toreadwrite($1.c, c, 0, 0);
2121 E : E "-=" E { code_t*c = $3.c;
2122 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2123 c=abc_subtract_i(c);
2127 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2129 $$.c = toreadwrite($1.c, c, 0, 0);
2132 E : E '=' E { code_t*c = 0;
2133 c = code_append(c, $3.c);
2134 c = converttype(c, $3.t, $1.t);
2135 $$.c = toreadwrite($1.c, c, 1, 0);
2139 E : E '?' E ':' E %prec below_assignment {
2141 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2142 $$.c = code_append($$.c, $3.c);
2143 code_t*j2 = $$.c = abc_jump($$.c, 0);
2144 $$.c = j1->branch = abc_label($$.c);
2145 $$.c = code_append($$.c, $5.c);
2146 $$.c = j2->branch = abc_label($$.c);
2147 $$.t = join_types($3.t,$5.t,'?');
2150 // TODO: use inclocal where appropriate
2151 E : E "++" { code_t*c = 0;
2152 classinfo_t*type = $1.t;
2153 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2154 c=abc_increment_i(c);
2160 c=converttype(c, type, $1.t);
2161 $$.c = toreadwrite($1.c, c, 0, 1);
2164 E : E "--" { code_t*c = 0;
2165 classinfo_t*type = $1.t;
2166 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2167 c=abc_decrement_i(c);
2173 c=converttype(c, type, $1.t);
2174 $$.c = toreadwrite($1.c, c, 0, 1);
2178 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2179 classinfo_t*type = $2.t;
2180 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2181 c=abc_increment_i(c);
2187 c=converttype(c, type, $2.t);
2188 $$.c = toreadwrite($2.c, c, 0, 0);
2192 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2193 classinfo_t*type = $2.t;
2194 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2195 c=abc_decrement_i(c);
2201 c=converttype(c, type, $2.t);
2202 $$.c = toreadwrite($2.c, c, 0, 0);
2206 E : "super" '.' T_IDENTIFIER
2207 { if(!state->cls->info)
2208 syntaxerror("super keyword not allowed outside a class");
2209 classinfo_t*t = state->cls->info->superclass;
2210 if(!t) t = TYPE_OBJECT;
2212 memberinfo_t*f = registry_findmember(t, $3);
2213 namespace_t ns = {flags2access(f->flags), ""};
2214 MEMBER_MULTINAME(m, f, $3);
2216 $$.c = abc_getlocal_0($$.c);
2217 $$.c = abc_getsuper2($$.c, &m);
2218 $$.t = memberinfo_gettype(f);
2221 E : E '.' T_IDENTIFIER
2223 classinfo_t*t = $1.t;
2225 if(TYPE_IS_CLASS(t) && t->cls) {
2230 memberinfo_t*f = registry_findmember(t, $3);
2232 if(f && !is_static != !(f->flags&FLAG_STATIC))
2234 if(f && f->slot && !noslot) {
2235 $$.c = abc_getslot($$.c, f->slot);
2237 MEMBER_MULTINAME(m, f, $3);
2238 $$.c = abc_getproperty2($$.c, &m);
2240 /* determine type */
2241 $$.t = memberinfo_gettype(f);
2243 $$.c = abc_coerce_a($$.c);
2245 /* when resolving a property on an unknown type, we do know the
2246 name of the property (and don't seem to need the package), but
2247 we need to make avm2 try out all access modes */
2248 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2249 $$.c = abc_getproperty2($$.c, &m);
2250 $$.c = abc_coerce_a($$.c);
2251 $$.t = registry_getanytype();
2255 VAR_READ : T_IDENTIFIER {
2262 /* look at variables */
2263 if((i = find_variable($1, &$$.t)) >= 0) {
2264 // $1 is a local variable
2265 $$.c = abc_getlocal($$.c, i);
2267 /* look at current class' members */
2268 } else if((f = registry_findmember(state->cls->info, $1))) {
2269 // $1 is a function in this class
2270 int var_is_static = (f->flags&FLAG_STATIC);
2271 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2272 if(var_is_static != i_am_static) {
2273 /* there doesn't seem to be any "static" way to access
2274 static properties of a class */
2275 state->method->late_binding = 1;
2277 namespace_t ns = {flags2access(f->flags), ""};
2278 multiname_t m = {QNAME, &ns, 0, $1};
2279 $$.c = abc_findpropstrict2($$.c, &m);
2280 $$.c = abc_getproperty2($$.c, &m);
2283 $$.c = abc_getlocal_0($$.c);
2284 $$.c = abc_getslot($$.c, f->slot);
2286 namespace_t ns = {flags2access(f->flags), ""};
2287 multiname_t m = {QNAME, &ns, 0, $1};
2288 $$.c = abc_getlocal_0($$.c);
2289 $$.c = abc_getproperty2($$.c, &m);
2292 if(f->kind == MEMBER_METHOD) {
2293 $$.t = TYPE_FUNCTION(f);
2298 /* look at classes in the current package and imported classes */
2299 } else if((a = find_class($1))) {
2300 if(a->flags & FLAG_METHOD) {
2302 $$.c = abc_findpropstrict2($$.c, &m);
2303 $$.c = abc_getproperty2($$.c, &m);
2304 $$.t = TYPE_FUNCTION(a->function);
2307 $$.c = abc_getglobalscope($$.c);
2308 $$.c = abc_getslot($$.c, a->slot);
2311 $$.c = abc_getlex2($$.c, &m);
2313 $$.t = TYPE_CLASS(a);
2316 /* unknown object, let the avm2 resolve it */
2318 if(strcmp($1,"trace"))
2319 warning("Couldn't resolve '%s', doing late binding", $1);
2320 state->method->late_binding = 1;
2322 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2325 $$.c = abc_findpropstrict2($$.c, &m);
2326 $$.c = abc_getproperty2($$.c, &m);
2331 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2332 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2333 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2335 // ----------------- namespaces -------------------------------------------------
2337 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2338 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2339 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2341 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER