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_FOR "for"
84 %token<token> KW_CLASS "class"
85 %token<token> KW_CONST "const"
86 %token<token> KW_SET "set"
87 %token<token> KW_STATIC
88 %token<token> KW_IMPORT "import"
89 %token<token> KW_RETURN "return"
90 %token<token> KW_INTERFACE "interface"
91 %token<token> KW_NULL "null"
92 %token<token> KW_VAR "var"
93 %token<token> KW_DYNAMIC
94 %token<token> KW_OVERRIDE
95 %token<token> KW_FINAL
96 %token<token> KW_GET "get"
97 %token<token> KW_EXTENDS
98 %token<token> KW_FALSE "false"
99 %token<token> KW_TRUE "true"
100 %token<token> KW_BOOLEAN "Boolean"
101 %token<token> KW_UINT "uint"
102 %token<token> KW_INT "int"
103 %token<token> KW_WHILE "while"
104 %token<token> KW_NUMBER "Number"
105 %token<token> KW_STRING "String"
106 %token<token> KW_IF "if"
107 %token<token> KW_ELSE "else"
108 %token<token> KW_BREAK "break"
109 %token<token> KW_IS "is"
110 %token<token> KW_AS "as"
112 %token<token> T_EQEQ "=="
113 %token<token> T_EQEQEQ "==="
114 %token<token> T_NE "!="
115 %token<token> T_LE "<="
116 %token<token> T_GE ">="
117 %token<token> T_DIVBY "/="
118 %token<token> T_MODBY "%="
119 %token<token> T_MULBY "*="
120 %token<token> T_PLUSBY "+="
121 %token<token> T_MINUSBY "-="
122 %token<token> T_SHRBY ">>="
123 %token<token> T_SHLBY "<<="
124 %token<token> T_USHRBY ">>>="
125 %token<token> T_OROR "||"
126 %token<token> T_ANDAND "&&"
127 %token<token> T_COLONCOLON "::"
128 %token<token> T_MINUSMINUS "--"
129 %token<token> T_PLUSPLUS "++"
130 %token<token> T_DOTDOT ".."
131 %token<token> T_DOTDOTDOT "..."
132 %token<token> T_SHL "<<"
133 %token<token> T_USHR ">>>"
134 %token<token> T_SHR ">>"
135 %token<token> T_SEMICOLON ';'
136 %token<token> T_STAR '*'
137 %token<token> T_DOT '.'
139 %type <id> X_IDENTIFIER PACKAGE
140 %type <token> VARCONST
142 %type <code> CODEPIECE
143 %type <code> CODEBLOCK MAYBECODE
144 %type <token> PACKAGE_DECLARATION
145 %type <token> FUNCTION_DECLARATION
146 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
147 %type <token> CLASS_DECLARATION
148 %type <token> NAMESPACE_DECLARATION
149 %type <token> INTERFACE_DECLARATION
150 %type <code> VOIDEXPRESSION
151 %type <value> EXPRESSION NONCOMMAEXPRESSION
152 %type <value> MAYBEEXPRESSION
154 %type <value> CONSTANT
155 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
156 %type <token> USE_NAMESPACE
157 %type <code> FOR_INIT
159 %type <classinfo> MAYBETYPE
162 %type <params> PARAM_LIST
163 %type <params> MAYBE_PARAM_LIST
164 %type <flags> MAYBE_MODIFIERS
165 %type <flags> MODIFIER_LIST
166 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
167 %type <classinfo_list> IMPLEMENTS_LIST
168 %type <classinfo> EXTENDS
169 %type <classinfo_list> EXTENDS_LIST
170 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
171 %type <classinfo_list> QNAME_LIST
172 %type <classinfo> TYPE
174 //%type <token> VARIABLE
175 %type <value> VAR_READ
177 //%type <token> T_IDENTIFIER
178 %type <token> MODIFIER
179 %type <value> FUNCTIONCALL
180 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
182 // precedence: from low to high
183 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
187 %right '=' "/=" "%=" "*=" "+=" "-=" ">>=" "<<=" ">>>="
193 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
195 %left prec_belowminus
210 %nonassoc T_IDENTIFIER
211 %left below_semicolon
216 // needed for "return" precedence:
217 %nonassoc T_STRING T_REGEXP
218 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
219 %nonassoc "new" "false" "true" "null"
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 _state {
257 /* code that needs to be executed at the start of
258 a method (like initializing local registers) */
261 import_list_t*wildcard_imports;
263 char has_own_imports;
269 code_t*cls_static_init;
279 typedef struct _global {
283 static global_t*global = 0;
284 static state_t* state = 0;
288 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
290 /* warning: list length of namespace set is undefined */
291 #define MULTINAME_LATE(m, access, package) \
292 namespace_t m##_ns = {access, package}; \
293 namespace_set_t m##_nsset; \
294 namespace_list_t m##_l;m##_l.next = 0; \
295 m##_nsset.namespaces = &m##_l; \
296 m##_nsset = m##_nsset; \
297 m##_l.namespace = &m##_ns; \
298 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
300 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
301 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
302 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
303 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
304 static namespace_list_t nl4 = {&ns4,0};
305 static namespace_list_t nl3 = {&ns3,&nl4};
306 static namespace_list_t nl2 = {&ns2,&nl3};
307 static namespace_list_t nl1 = {&ns1,&nl2};
308 static namespace_set_t nopackage_namespace_set = {&nl1};
310 static state_list_t*state_stack=0;
312 static void init_globals()
314 global = rfx_calloc(sizeof(global_t));
317 static void new_state()
320 NEW(state_list_t, sl);
322 state_t*oldstate = state;
324 memcpy(s, state, sizeof(state_t)); //shallow copy
325 sl->next = state_stack;
328 s->imports = dict_new();
333 state->vars = dict_new();
335 state->has_own_imports = 0;
337 static void state_has_imports()
339 state->wildcard_imports = list_clone(state->wildcard_imports);
340 state->imports = dict_clone(state->imports);
341 state->has_own_imports = 1;
344 static void old_state()
346 if(!state_stack || !state_stack->next)
347 syntaxerror("invalid nesting");
348 state_t*oldstate = state;
349 state_list_t*old = state_stack;
350 state_stack = state_stack->next;
352 state = state_stack->state;
353 /*if(state->initcode) {
354 printf("residual initcode\n");
355 code_dump(state->initcode, 0, 0, "", stdout);
357 if(oldstate->has_own_imports) {
358 list_free(oldstate->wildcard_imports);
359 dict_destroy(oldstate->imports);oldstate->imports=0;
361 state->initcode = code_append(state->initcode, oldstate->initcode);
363 void initialize_state()
368 state->file = abc_file_new();
369 state->file->flags &= ~ABCFILE_LAZY;
371 state->init = abc_initscript(state->file, 0);
372 code_t*c = state->init->method->body->code;
374 c = abc_getlocal_0(c);
375 c = abc_pushscope(c);
377 /* findpropstrict doesn't just return a scope object- it
378 also makes it "active" somehow. Push local_0 on the
379 scope stack and read it back with findpropstrict, it'll
380 contain properties like "trace". Trying to find the same
381 property on a "vanilla" local_0 yields only a "undefined" */
382 //c = abc_findpropstrict(c, "[package]::trace");
384 /*c = abc_getlocal_0(c);
385 c = abc_findpropstrict(c, "[package]::trace");
387 c = abc_setlocal_1(c);
389 c = abc_pushbyte(c, 0);
390 c = abc_setlocal_2(c);
392 code_t*xx = c = abc_label(c);
393 c = abc_findpropstrict(c, "[package]::trace");
394 c = abc_pushstring(c, "prop:");
395 c = abc_hasnext2(c, 1, 2);
397 c = abc_setlocal_3(c);
398 c = abc_callpropvoid(c, "[package]::trace", 2);
399 c = abc_getlocal_3(c);
401 c = abc_iftrue(c,xx);*/
403 c = abc_findpropstrict(c, "[package]::trace");
404 c = abc_pushstring(c, "[entering global init function]");
405 c = abc_callpropvoid(c, "[package]::trace", 1);
407 state->init->method->body->code = c;
409 void* finalize_state()
411 if(state->level!=1) {
412 syntaxerror("unexpected end of file");
414 abc_method_body_t*m = state->init->method->body;
417 __ findpropstrict(m, "[package]::trace");
418 __ pushstring(m, "[leaving global init function]");
419 __ callpropvoid(m, "[package]::trace", 1);
425 static void startpackage(char*name)
428 syntaxerror("Packages can not be nested.");
431 /*printf("entering package \"%s\"\n", name);*/
432 state->package = name;
434 static void endpackage()
436 /*printf("leaving package \"%s\"\n", state->package);*/
441 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
444 syntaxerror("inner classes now allowed");
449 classinfo_list_t*mlist=0;
450 /*printf("entering class %s\n", name);
451 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
453 printf(" extends: %s.%s\n", extends->package, extends->name);
454 printf(" implements (%d): ", list_length(implements));
455 for(mlist=implements;mlist;mlist=mlist->next) {
456 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
461 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
462 syntaxerror("invalid modifier(s)");
464 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
465 syntaxerror("public and internal not supported at the same time.");
467 /* create the class name, together with the proper attributes */
471 if(!(flags&FLAG_PUBLIC) && !state->package) {
472 access = ACCESS_PRIVATE; package = current_filename;
473 } else if(!(flags&FLAG_PUBLIC) && state->package) {
474 access = ACCESS_PACKAGEINTERNAL; package = state->package;
475 } else if(state->package) {
476 access = ACCESS_PACKAGE; package = state->package;
478 syntaxerror("public classes only allowed inside a package");
481 if(registry_findclass(package, classname)) {
482 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
485 /* build info struct */
486 int num_interfaces = (list_length(implements));
487 state->clsinfo = classinfo_register(access, package, classname, num_interfaces);
488 state->clsinfo->superclass = extends;
490 classinfo_list_t*l = implements;
491 for(l=implements;l;l=l->next) {
492 state->clsinfo->interfaces[pos++] = l->classinfo;
495 MULTINAME(classname2,state->clsinfo);
497 multiname_t*extends2 = sig2mname(extends);
500 state->cls_init = abc_getlocal_0(state->cls_init);
501 state->cls_init = abc_constructsuper(state->cls_init, 0);
504 state->cls = abc_class_new(state->file, &classname2, extends2);
505 if(flags&FLAG_FINAL) abc_class_final(state->cls);
506 if(flags&FLAG_DYNAMIC) abc_class_sealed(state->cls);
507 if(interface) abc_class_interface(state->cls);
509 for(mlist=implements;mlist;mlist=mlist->next) {
510 MULTINAME(m, mlist->classinfo);
511 abc_class_add_interface(state->cls, &m);
514 /* now write the construction code for this class */
515 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
517 abc_method_body_t*m = state->init->method->body;
518 __ getglobalscope(m);
519 classinfo_t*s = extends;
524 //TODO: take a look at the current scope stack, maybe
525 // we can re-use something
530 multiname_t*s2 = sig2mname(s);
532 multiname_destroy(s2);
534 __ pushscope(m); count++;
535 m->code = m->code->prev->prev; // invert
537 /* continue appending after last op end */
538 while(m->code && m->code->next) m->code = m->code->next;
540 /* TODO: if this is one of *our* classes, we can also
541 do a getglobalscope/getslot <nr> (which references
542 the init function's slots) */
544 __ getlex2(m, extends2);
546 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
547 stack is not the superclass */
548 __ pushscope(m);count++;
551 /* notice: we get a verify error #1107 if the top element on the scope
552 stack is not the global object */
554 __ pushscope(m);count++;
556 __ newclass(m,state->cls);
560 __ setslot(m, slotindex);
562 /* flash.display.MovieClip handling */
563 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
564 if(state->package && state->package[0]) {
565 globalclass = concat3str(state->package, ".", classname);
567 globalclass = strdup(classname);
570 multiname_destroy(extends2);
573 static void endclass()
575 if(state->cls_init) {
576 if(!state->cls->constructor) {
577 abc_method_t*m = abc_class_constructor(state->cls, 0);
578 m->body->code = code_append(m->body->code, state->cls_init);
579 m->body->code = abc_returnvoid(m->body->code);
581 code_t*c = state->cls->constructor->body->code;
582 c = code_append(state->cls_init, c);
583 state->cls->constructor->body->code = c;
587 if(state->cls_static_init) {
588 if(!state->cls->static_constructor) {
589 abc_method_t*m = abc_class_staticconstructor(state->cls, 0);
590 m->body->code = code_append(m->body->code, state->cls_static_init);
591 m->body->code = abc_returnvoid(m->body->code);
593 state->cls->static_constructor->body->code =
594 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
601 typedef struct _variable {
606 static int find_variable(char*name, classinfo_t**m)
608 state_list_t* s = state_stack;
610 variable_t*v = dict_lookup(s->state->vars, name);
621 static int find_variable_safe(char*name, classinfo_t**m)
623 int i = find_variable(name, m);
625 syntaxerror("undefined variable: %s", name);
628 static char variable_exists(char*name)
630 return dict_lookup(state->vars, name)!=0;
632 static int new_variable(char*name, classinfo_t*type)
635 v->index = global->variable_count;
637 dict_put(state->vars, name, v);
638 return global->variable_count++;
640 #define TEMPVARNAME "__as3_temp__"
641 static int gettempvar()
643 int i = find_variable(TEMPVARNAME, 0);
645 return new_variable(TEMPVARNAME, 0);
651 code_t* killvars(code_t*c)
654 for(t=0;t<state->vars->hashsize;t++) {
655 dictentry_t*e =state->vars->slots[t];
657 variable_t*v = (variable_t*)e->data;
658 //do this always, otherwise register types don't match
659 //in the verifier when doing nested loops
660 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
661 c = abc_kill(c, v->index);
669 static void check_constant_against_type(classinfo_t*t, constant_t*c)
671 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
672 if(TYPE_IS_NUMBER(t)) {
673 xassert(c->type == CONSTANT_FLOAT
674 || c->type == CONSTANT_INT
675 || c->type == CONSTANT_UINT);
676 } else if(TYPE_IS_UINT(t)) {
677 xassert(c->type == CONSTANT_UINT ||
678 (c->type == CONSTANT_INT && c->i>0));
679 } else if(TYPE_IS_INT(t)) {
680 xassert(c->type == CONSTANT_INT);
681 } else if(TYPE_IS_BOOLEAN(t)) {
682 xassert(c->type == CONSTANT_TRUE
683 || c->type == CONSTANT_FALSE);
687 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
689 memberinfo_t*minfo = 0;
690 if(getset != KW_GET && getset != KW_SET) {
691 if(registry_findmember(state->clsinfo, name)) {
692 syntaxerror("class already contains a member/method called '%s'", name);
694 minfo = memberinfo_register(state->clsinfo, name, MEMBER_METHOD);
695 minfo->return_type = return_type;
696 // getslot on a member slot only returns "undefined", so no need
697 // to actually store these
698 //state->minfo->slot = state->m->method->trait->slot_id;
700 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
704 else if(params->list)
705 type = params->list->param->type;
706 if((minfo=registry_findmember(state->clsinfo, name))) {
707 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
708 syntaxerror("class already contains a member or method called '%s'", name);
710 syntaxerror("getter/setter for '%s' already defined", name);
711 /* make a setter or getter into a getset */
716 if(type && minfo->type != type)
717 syntaxerror("different type in getter and setter");
719 minfo = memberinfo_register(state->clsinfo, name, gs);
722 /* can't assign a slot as getter and setter might have different slots */
723 //minfo->slot = slot;
725 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
726 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
727 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
728 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
729 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
733 static int flags2access(int flags)
736 if(flags&FLAG_PUBLIC) {
737 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
738 access = ACCESS_PACKAGE;
739 } else if(flags&FLAG_PRIVATE) {
740 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
741 access = ACCESS_PRIVATE;
742 } else if(flags&FLAG_PROTECTED) {
743 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
744 access = ACCESS_PROTECTED;
746 access = ACCESS_PACKAGEINTERNAL;
751 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
752 params_t*params, classinfo_t*return_type)
756 global->variable_count = 0;
757 state->function = name;
760 syntaxerror("not able to start another method scope");
763 namespace_t mname_ns = {flags2access(flags), ""};
764 multiname_t mname = {QNAME, &mname_ns, 0, name};
766 multiname_t*type2 = sig2mname(return_type);
768 if(!strcmp(state->clsinfo->name,name)) {
769 state->m = abc_class_constructor(state->cls, type2);
770 name = "__as3_constructor__";
772 if(flags&FLAG_STATIC)
773 state->m = abc_class_staticmethod(state->cls, type2, &mname);
775 state->m = abc_class_method(state->cls, type2, &mname);
776 slot = state->m->trait->slot_id;
778 state->minfo = registerfunction(getset, flags, name, params, return_type, slot);
780 if(getset == KW_GET) state->m->trait->kind = TRAIT_GETTER;
781 if(getset == KW_SET) state->m->trait->kind = TRAIT_SETTER;
782 if(params->varargs) state->m->flags |= METHOD_NEED_REST;
786 for(p=params->list;p;p=p->next) {
787 if(params->varargs && !p->next) {
788 break; //varargs: omit last parameter in function signature
790 multiname_t*m = sig2mname(p->param->type);
791 list_append(state->m->parameters, m);
792 if(p->param->value) {
793 check_constant_against_type(p->param->type, p->param->value);
794 opt=1;list_append(state->m->optional_parameters, p->param->value);
796 syntaxerror("non-optional parameter not allowed after optional parameters");
800 /* state->vars is initialized by state_new */
801 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->clsinfo)!=0) syntaxerror("Internal error");
803 for(p=params->list;p;p=p->next) {
804 new_variable(p->param->name, p->param->type);
807 static void endfunction(code_t*body)
810 if(!(state->cls->flags & CLASS_INTERFACE)) {
812 if(state->late_binding) {
813 c = abc_getlocal_0(c);
814 c = abc_pushscope(c);
816 c = code_append(c, state->initcode);
817 c = code_append(c, body);
819 /* append return if necessary */
820 if(!c || c->opcode != OPCODE_RETURNVOID &&
821 c->opcode != OPCODE_RETURNVALUE) {
822 c = abc_returnvoid(c);
824 if(state->m->body->code) syntaxerror("internal error");
825 state->m->body->code = c;
832 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
837 void breakjumpsto(code_t*c, code_t*jump)
842 if(c->opcode == OPCODE___BREAK__) {
843 c->opcode = OPCODE_JUMP;
850 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
853 return registry_getanytype();
854 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
855 return registry_getanytype();
858 return registry_getanytype();
860 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
865 return abc_coerce_a(c);
869 // cast an "any" type to a specific type. subject to
870 // runtime exceptions
871 return abc_coerce2(c, &m);
874 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
875 return abc_coerce2(c, &m);
877 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
878 return abc_coerce2(c, &m);
880 /* these are subject to overflow */
881 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
882 return abc_coerce2(c, &m);
884 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
885 return abc_coerce2(c, &m);
888 classinfo_t*supertype = from;
890 if(supertype == to) {
891 // target type is one of from's superclasses
892 return abc_coerce2(c, &m);
895 while(supertype->interfaces[t]) {
896 if(supertype->interfaces[t]==to) {
897 // to type is one of from's interfaces
898 return abc_coerce2(c, &m);
902 supertype = supertype->superclass;
904 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
906 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
908 syntaxerror("can't convert type %s to %s", from->name, to->name);
911 code_t*defaultvalue(code_t*c, classinfo_t*type)
913 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
914 c = abc_pushbyte(c, 0);
915 } else if(TYPE_IS_BOOLEAN(type)) {
916 c = abc_pushfalse(c);
923 char is_pushundefined(code_t*c)
925 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
928 void parserassert(int b)
930 if(!b) syntaxerror("internal error: assertion failed");
933 static classinfo_t* find_class(char*name)
937 c = registry_findclass(state->package, name);
939 /* try explicit imports */
940 dictentry_t* e = dict_get_slot(state->imports, name);
944 if(!strcmp(e->key, name)) {
945 c = (classinfo_t*)e->data;
950 /* try package.* imports */
951 import_list_t*l = state->wildcard_imports;
955 //printf("does package %s contain a class %s?\n", l->import->package, name);
956 c = registry_findclass(l->import->package, name);
960 /* try global package */
962 c = registry_findclass("", name);
967 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
971 [prefix code] [read instruction]
975 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
978 if(in && in->opcode == OPCODE_COERCE_A) {
979 in = code_cutlast(in);
982 syntaxerror("internal error");
984 /* chop off read instruction */
988 prefix = r->prev;r->prev = 0;
994 char use_temp_var = readbefore;
996 /* generate the write instruction, and maybe append a dup to the prefix code */
997 code_t* write = abc_nop(0);
998 if(r->opcode == OPCODE_GETPROPERTY) {
999 write->opcode = OPCODE_SETPROPERTY;
1000 multiname_t*m = (multiname_t*)r->data[0];
1001 write->data[0] = multiname_clone(m);
1002 if(m->type != QNAME && m->type != MULTINAME)
1003 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
1005 prefix = abc_dup(prefix); // we need the object, too
1008 } else if(r->opcode == OPCODE_GETSLOT) {
1009 write->opcode = OPCODE_SETSLOT;
1010 write->data[0] = r->data[0];
1012 prefix = abc_dup(prefix); // we need the object, too
1015 } else if(r->opcode == OPCODE_GETLOCAL) {
1016 write->opcode = OPCODE_SETLOCAL;
1017 write->data[0] = r->data[0];
1018 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1019 write->opcode = OPCODE_SETLOCAL_0;
1020 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1021 write->opcode = OPCODE_SETLOCAL_1;
1022 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1023 write->opcode = OPCODE_SETLOCAL_2;
1024 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1025 write->opcode = OPCODE_SETLOCAL_3;
1027 code_dump(r, 0, 0, "", stdout);
1028 syntaxerror("illegal lvalue: can't assign a value to this expression");
1035 /* with getproperty/getslot, we have to be extra careful not
1036 to execute the read code twice, as it might have side-effects
1037 (e.g. if the property is in fact a setter/getter combination)
1039 So read the value, modify it, and write it again,
1040 using prefix only once and making sure (by using a temporary
1041 register) that the return value is what we just wrote */
1042 temp = gettempvar();
1043 c = code_append(c, prefix);
1044 c = code_append(c, r);
1047 c = abc_setlocal(c, temp);
1049 c = code_append(c, middlepart);
1052 c = abc_setlocal(c, temp);
1054 c = code_append(c, write);
1055 c = abc_getlocal(c, temp);
1056 c = abc_kill(c, temp);
1058 /* if we're allowed to execute the read code twice *and*
1059 the middlepart doesn't modify the code, things are easier.
1061 code_t* r2 = code_dup(r);
1062 //c = code_append(c, prefix);
1063 parserassert(!prefix);
1064 c = code_append(c, r);
1065 c = code_append(c, middlepart);
1066 c = code_append(c, write);
1067 c = code_append(c, r2);
1070 /* even smaller version: overwrite the value without reading
1074 c = code_append(c, prefix);
1077 c = code_append(c, middlepart);
1078 c = code_append(c, write);
1079 c = code_append(c, r);
1081 temp = gettempvar();
1083 c = code_append(c, prefix);
1086 c = code_append(c, middlepart);
1088 c = abc_setlocal(c, temp);
1089 c = code_append(c, write);
1090 c = abc_getlocal(c, temp);
1103 /* ------------ code blocks / statements ---------------- */
1107 MAYBECODE: CODE {$$=$1;}
1108 MAYBECODE: {$$=code_new();}
1110 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1111 CODE: CODEPIECE {$$=$1;}
1113 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1114 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1115 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1116 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1117 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1118 CODEPIECE: ';' {$$=code_new();}
1119 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1120 CODEPIECE: VOIDEXPRESSION {$$=$1}
1121 CODEPIECE: FOR {$$=$1}
1122 CODEPIECE: WHILE {$$=$1}
1123 CODEPIECE: BREAK {$$=$1}
1124 CODEPIECE: RETURN {$$=$1}
1125 CODEPIECE: IF {$$=$1}
1126 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1127 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1129 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1130 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1131 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1133 /* ------------ variables --------------------------- */
1135 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1136 | {$$.c=abc_pushundefined(0);
1140 VAR : "const" | "var"
1141 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1143 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1144 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1146 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1148 if(variable_exists($2))
1149 syntaxerror("Variable %s already defined", $2);
1151 if(!is_subtype_of($4.t, $3)) {
1152 syntaxerror("Can't convert %s to %s", $4.t->name,
1156 int index = new_variable($2, $3);
1159 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1161 $$ = converttype($$, $4.t, $3);
1162 $$ = abc_setlocal($$, index);
1164 $$ = defaultvalue(0, $3);
1165 $$ = abc_setlocal($$, index);
1168 /* if this is a typed variable:
1169 push default value for type on stack */
1171 state->initcode = defaultvalue(state->initcode, $3);
1172 state->initcode = abc_setlocal(state->initcode, index);
1175 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1177 $$ = abc_coerce_a($$);
1178 $$ = abc_setlocal($$, index);
1184 /* that's the default for a local register, anyway
1186 state->initcode = abc_pushundefined(state->initcode);
1187 state->initcode = abc_setlocal(state->initcode, index);
1189 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1192 /* ------------ control flow ------------------------- */
1194 MAYBEELSE: %prec prec_none {$$ = code_new();}
1195 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1196 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1198 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1199 $$ = state->initcode;state->initcode=0;
1201 $$ = code_append($$, $4.c);
1202 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1204 $$ = code_append($$, $6);
1206 myjmp = $$ = abc_jump($$, 0);
1208 myif->branch = $$ = abc_label($$);
1210 $$ = code_append($$, $7);
1211 myjmp->branch = $$ = abc_label($$);
1214 $$ = killvars($$);old_state();
1217 FOR_INIT : {$$=code_new();}
1218 FOR_INIT : VARIABLE_DECLARATION
1219 FOR_INIT : VOIDEXPRESSION
1221 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1222 $$ = state->initcode;state->initcode=0;
1224 $$ = code_append($$, $4);
1225 code_t*loopstart = $$ = abc_label($$);
1226 $$ = code_append($$, $6.c);
1227 code_t*myif = $$ = abc_iffalse($$, 0);
1228 $$ = code_append($$, $10);
1229 $$ = code_append($$, $8);
1230 $$ = abc_jump($$, loopstart);
1231 code_t*out = $$ = abc_label($$);
1232 breakjumpsto($$, out);
1235 $$ = killvars($$);old_state();
1238 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1239 $$ = state->initcode;state->initcode=0;
1241 code_t*myjmp = $$ = abc_jump($$, 0);
1242 code_t*loopstart = $$ = abc_label($$);
1243 $$ = code_append($$, $6);
1244 myjmp->branch = $$ = abc_label($$);
1245 $$ = code_append($$, $4.c);
1246 $$ = abc_iftrue($$, loopstart);
1247 code_t*out = $$ = abc_label($$);
1248 breakjumpsto($$, out);
1250 $$ = killvars($$);old_state();
1254 $$ = abc___break__(0);
1257 /* ------------ packages and imports ---------------- */
1259 X_IDENTIFIER: T_IDENTIFIER
1260 | "package" {$$="package";}
1262 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1263 PACKAGE: X_IDENTIFIER {$$=$1;}
1265 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1266 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1268 IMPORT : "import" QNAME {
1271 syntaxerror("Couldn't import class\n");
1272 state_has_imports();
1273 dict_put(state->imports, c->name, c);
1276 IMPORT : "import" PACKAGE '.' '*' {
1279 state_has_imports();
1280 list_append(state->wildcard_imports, i);
1284 /* ------------ classes and interfaces (header) -------------- */
1286 MAYBE_MODIFIERS : {$$=0;}
1287 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1288 MODIFIER_LIST : MODIFIER {$$=$1;}
1289 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1291 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1292 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1293 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1294 | KW_STATIC {$$=FLAG_STATIC;}
1295 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1296 | KW_FINAL {$$=FLAG_FINAL;}
1297 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1298 | KW_NATIVE {$$=FLAG_NATIVE;}
1299 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1301 EXTENDS : {$$=registry_getobjectclass();}
1302 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1304 EXTENDS_LIST : {$$=list_new();}
1305 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1307 IMPLEMENTS_LIST : {$$=list_new();}
1308 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1310 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1311 EXTENDS IMPLEMENTS_LIST
1312 '{' {startclass($1,$3,$4,$5, 0);}
1313 MAYBE_DECLARATION_LIST
1316 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1318 '{' {startclass($1,$3,0,$4,1);}
1319 MAYBE_IDECLARATION_LIST
1322 /* ------------ classes and interfaces (body) -------------- */
1324 MAYBE_DECLARATION_LIST :
1325 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1326 DECLARATION_LIST : DECLARATION
1327 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1329 DECLARATION : SLOT_DECLARATION
1330 DECLARATION : FUNCTION_DECLARATION
1332 MAYBE_IDECLARATION_LIST :
1333 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1334 IDECLARATION_LIST : IDECLARATION
1335 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1337 IDECLARATION : "var" T_IDENTIFIER {
1338 syntaxerror("variable declarations not allowed in interfaces");
1340 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1342 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1343 syntaxerror("invalid method modifiers: interface methods always need to be public");
1345 startfunction(0,$1,$3,$4,&$6,$8);
1349 /* ------------ classes and interfaces (body, slots ) ------- */
1351 VARCONST: "var" | "const"
1353 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1355 memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
1357 info->flags = flags;
1360 namespace_t mname_ns = {flags2access(flags), ""};
1361 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1363 if(!(flags&FLAG_STATIC)) {
1366 t=abc_class_slot(state->cls, &mname, &m);
1368 t=abc_class_slot(state->cls, &mname, 0);
1370 info->slot = t->slot_id;
1374 t=abc_class_staticslot(state->cls, &mname, &m);
1376 t=abc_class_staticslot(state->cls, &mname, 0);
1378 info->slot = t->slot_id;
1380 if($5.c && !is_pushundefined($5.c)) {
1382 c = abc_getlocal_0(c);
1383 c = code_append(c, $5.c);
1384 c = converttype(c, $5.t, $4);
1385 c = abc_setslot(c, t->slot_id);
1386 if(!(flags&FLAG_STATIC))
1387 state->cls_init = code_append(state->cls_init, c);
1389 state->cls_static_init = code_append(state->cls_static_init, c);
1392 t->kind= TRAIT_CONST;
1396 /* ------------ constants -------------------------------------- */
1398 MAYBESTATICCONSTANT: {$$=0;}
1399 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1401 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1402 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1403 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1404 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1405 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1406 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1407 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1408 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1409 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1411 /* ------------ classes and interfaces (body, functions) ------- */
1413 // non-vararg version
1415 memset(&$$,0,sizeof($$));
1417 MAYBE_PARAM_LIST: PARAM_LIST {
1422 MAYBE_PARAM_LIST: "..." PARAM {
1423 memset(&$$,0,sizeof($$));
1425 list_append($$.list, $2);
1427 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1430 list_append($$.list, $4);
1434 PARAM_LIST: PARAM_LIST ',' PARAM {
1436 list_append($$.list, $3);
1439 memset(&$$,0,sizeof($$));
1440 list_append($$.list, $1);
1443 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1444 $$ = malloc(sizeof(param_t));
1449 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1450 $$ = malloc(sizeof(param_t));
1452 $$->type = TYPE_ANY;
1455 GETSET : "get" {$$=$1;}
1459 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1460 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1462 if(!state->m) syntaxerror("internal error: undefined function");
1466 /* ------------- package + class ids --------------- */
1468 CLASS: T_IDENTIFIER {
1470 /* try current package */
1471 $$ = find_class($1);
1472 if(!$$) syntaxerror("Could not find class %s\n", $1);
1475 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1476 $$ = registry_findclass($1, $3);
1477 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1480 QNAME: PACKAGEANDCLASS
1483 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1484 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1486 TYPE : QNAME {$$=$1;}
1487 | '*' {$$=registry_getanytype();}
1488 | "String" {$$=registry_getstringclass();}
1489 | "int" {$$=registry_getintclass();}
1490 | "uint" {$$=registry_getuintclass();}
1491 | "Boolean" {$$=registry_getbooleanclass();}
1492 | "Number" {$$=registry_getnumberclass();}
1494 MAYBETYPE: ':' TYPE {$$=$2;}
1497 /* ----------function calls, constructor calls ------ */
1499 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1500 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1502 MAYBE_EXPRESSION_LIST : {$$=0;}
1503 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1504 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1505 typedcode_t*t = malloc(sizeof(typedcode_t));
1507 list_append($$, t);}
1508 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1509 typedcode_t*t = malloc(sizeof(typedcode_t));
1511 list_append($$, t);}
1513 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1518 $$.c = abc_getglobalscope($$.c);
1519 $$.c = abc_getslot($$.c, $2->slot);
1521 $$.c = abc_findpropstrict2($$.c, &m);
1524 typedcode_list_t*l = $3;
1527 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1532 $$.c = abc_construct($$.c, len);
1534 $$.c = abc_constructprop2($$.c, &m, len);
1538 /* TODO: use abc_call (for calling local variables),
1539 abc_callstatic (for calling own methods)
1542 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1543 typedcode_list_t*l = $3;
1545 code_t*paramcode = 0;
1547 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1553 if($$.c->opcode == OPCODE_COERCE_A) {
1554 $$.c = code_cutlast($$.c);
1558 multiname_t*name = 0;
1559 if($$.c->opcode == OPCODE_GETPROPERTY) {
1560 name = multiname_clone($$.c->data[0]);
1561 $$.c = code_cutlast($$.c);
1562 $$.c = code_append($$.c, paramcode);
1563 $$.c = abc_callproperty2($$.c, name, len);
1564 } else if($$.c->opcode == OPCODE_GETSLOT) {
1565 int slot = (int)(ptroff_t)$$.c->data[0];
1566 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1567 if(t->kind!=TRAIT_METHOD) {
1568 //flash allows to assign closures to members.
1569 //syntaxerror("not a function");
1572 $$.c = code_cutlast($$.c);
1573 $$.c = code_append($$.c, paramcode);
1574 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1575 $$.c = abc_callproperty2($$.c, name, len);
1577 $$.c = abc_getlocal_0($$.c);
1578 $$.c = code_append($$.c, paramcode);
1579 $$.c = abc_call($$.c, len);
1584 if(TYPE_IS_FUNCTION($1.t) &&
1585 (f = registry_findmember($1.t, "call"))) {
1586 $$.t = f->return_type;
1588 $$.c = abc_coerce_a($$.c);
1593 RETURN: "return" %prec prec_none {
1594 $$ = abc_returnvoid(0);
1596 RETURN: "return" EXPRESSION {
1598 $$ = abc_returnvalue($$);
1600 // ----------------------- expression types -------------------------------------
1602 NONCOMMAEXPRESSION : E %prec prec_belowminus {$$=$1;}
1603 EXPRESSION : E %prec prec_belowminus {$$ = $1;}
1604 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1606 $$.c = cut_last_push($$.c);
1607 $$.c = code_append($$.c,$3.c);
1610 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1612 // ----------------------- expression evaluation -------------------------------------
1615 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1617 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1621 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1622 //MULTINAME(m, registry_getintclass());
1623 //$$.c = abc_coerce2($$.c, &m); // FIXME
1626 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1629 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1632 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1635 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1638 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1641 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1642 $$.t = TYPE_BOOLEAN;
1644 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1645 $$.t = TYPE_BOOLEAN;
1647 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1652 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1653 $$.t = TYPE_BOOLEAN;
1655 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1656 $$.t = TYPE_BOOLEAN;
1658 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1659 $$.t = TYPE_BOOLEAN;
1661 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1662 $$.t = TYPE_BOOLEAN;
1664 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1665 $$.t = TYPE_BOOLEAN;
1667 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1668 $$.t = TYPE_BOOLEAN;
1670 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1671 $$.t = TYPE_BOOLEAN;
1674 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1676 $$.c = converttype($$.c, $1.t, $$.t);
1677 $$.c = abc_dup($$.c);
1678 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1679 $$.c = cut_last_push($$.c);
1680 $$.c = code_append($$.c,$3.c);
1681 $$.c = converttype($$.c, $3.t, $$.t);
1682 code_t*label = $$.c = abc_label($$.c);
1683 jmp->branch = label;
1686 $$.t = join_types($1.t, $3.t, 'A');
1687 /*printf("%08x:\n",$1.t);
1688 code_dump($1.c, 0, 0, "", stdout);
1689 printf("%08x:\n",$3.t);
1690 code_dump($3.c, 0, 0, "", stdout);
1691 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1693 $$.c = converttype($$.c, $1.t, $$.t);
1694 $$.c = abc_dup($$.c);
1695 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1696 $$.c = cut_last_push($$.c);
1697 $$.c = code_append($$.c,$3.c);
1698 $$.c = converttype($$.c, $3.t, $$.t);
1699 code_t*label = $$.c = abc_label($$.c);
1700 jmp->branch = label;
1703 E : '!' E {$$.c=$2.c;
1704 $$.c = abc_not($$.c);
1705 $$.t = TYPE_BOOLEAN;
1710 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1711 $$.t = join_types($1.t, $3.t, '+');
1713 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1714 $$.t = join_types($1.t, $3.t, '%');
1716 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1717 $$.t = join_types($1.t, $3.t, '*');
1722 E : '(' E ')' {$$=$2;}
1727 $$.c = code_append($$.c, $3.c);
1729 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1730 $$.c = abc_getproperty2($$.c, &m);
1735 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1736 c=abc_multiply_i(c);
1740 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1741 $$.c = toreadwrite($1.c, c, 0, 0);
1745 code_t*c = abc_modulo($3.c);
1746 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1747 $$.c = toreadwrite($1.c, c, 0, 0);
1751 code_t*c = abc_lshift($3.c);
1752 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1753 $$.c = toreadwrite($1.c, c, 0, 0);
1757 code_t*c = abc_rshift($3.c);
1758 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1759 $$.c = toreadwrite($1.c, c, 0, 0);
1763 code_t*c = abc_urshift($3.c);
1764 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1765 $$.c = toreadwrite($1.c, c, 0, 0);
1769 code_t*c = abc_divide($3.c);
1770 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1771 $$.c = toreadwrite($1.c, c, 0, 0);
1776 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1781 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1783 $$.c = toreadwrite($1.c, c, 0, 0);
1786 E : E "-=" E { code_t*c = $3.c;
1787 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1788 c=abc_subtract_i(c);
1792 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1794 $$.c = toreadwrite($1.c, c, 0, 0);
1797 E : E '=' E { code_t*c = 0;
1798 c = code_append(c, $3.c);
1799 c = converttype(c, $3.t, $1.t);
1800 $$.c = toreadwrite($1.c, c, 1, 0);
1804 // TODO: use inclocal where appropriate
1805 E : E "++" { code_t*c = 0;
1806 classinfo_t*type = $1.t;
1807 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1808 c=abc_increment_i(c);
1814 c=converttype(c, type, $1.t);
1815 $$.c = toreadwrite($1.c, c, 0, 1);
1818 E : E "--" { code_t*c = 0;
1819 classinfo_t*type = $1.t;
1820 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1821 c=abc_decrement_i(c);
1827 c=converttype(c, type, $1.t);
1828 $$.c = toreadwrite($1.c, c, 0, 1);
1832 E : "++" E { code_t*c = 0;
1833 classinfo_t*type = $2.t;
1834 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1835 c=abc_increment_i(c);
1841 c=converttype(c, type, $2.t);
1842 $$.c = toreadwrite($2.c, c, 0, 0);
1846 E : "--" E { code_t*c = 0;
1847 classinfo_t*type = $2.t;
1848 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1849 c=abc_decrement_i(c);
1855 c=converttype(c, type, $2.t);
1856 $$.c = toreadwrite($2.c, c, 0, 0);
1860 E : E '.' T_IDENTIFIER
1862 classinfo_t*t = $1.t;
1864 if(TYPE_IS_CLASS(t)) {
1865 memberinfo_t*m = registry_findmember($1.t, "prototype");
1866 if(!m) syntaxerror("identifier '%s' not found in anonymous class", $3);
1871 memberinfo_t*f = registry_findmember(t, $3);
1873 if(f && !is_static != !(f->flags&FLAG_STATIC))
1876 if(f && f->slot && !noslot) {
1877 $$.c = abc_getslot($$.c, f->slot);
1880 namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
1881 multiname_t m = {QNAME, &ns, 0, $3};
1882 $$.c = abc_getproperty2($$.c, &m);
1884 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1885 $$.c = abc_getproperty2($$.c, &m);
1888 /* determine type */
1890 if(f->kind == MEMBER_METHOD) {
1891 $$.t = TYPE_FUNCTION(f);
1896 $$.c = abc_coerce_a($$.c);
1897 $$.t = registry_getanytype();
1900 /* when resolving a property on an unknown type, we do know the
1901 name of the property (and don't seem to need the package), but
1902 we do need to make avm2 try out all access modes */
1903 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1904 $$.c = abc_getproperty2($$.c, &m);
1905 $$.c = abc_coerce_a($$.c);
1906 $$.t = registry_getanytype();
1910 VAR_READ : T_IDENTIFIER {
1917 /* look at variables */
1918 if((i = find_variable($1, &$$.t)) >= 0) {
1919 // $1 is a local variable
1920 $$.c = abc_getlocal($$.c, i);
1922 /* look at current class' members */
1923 } else if((f = registry_findmember(state->clsinfo, $1))) {
1924 // $1 is a function in this class
1925 int var_is_static = (f->flags&FLAG_STATIC);
1926 int i_am_static = (state->minfo?(state->minfo->flags&FLAG_STATIC):FLAG_STATIC);
1927 if(var_is_static != i_am_static) {
1928 /* there doesn't seem to be any "static" way to access
1929 static properties of a class */
1930 state->late_binding = 1;
1932 namespace_t ns = {flags2access(f->flags), ""};
1933 multiname_t m = {QNAME, &ns, 0, $1};
1934 $$.c = abc_findpropstrict2($$.c, &m);
1935 $$.c = abc_getproperty2($$.c, &m);
1938 $$.c = abc_getlocal_0($$.c);
1939 $$.c = abc_getslot($$.c, f->slot);
1941 namespace_t ns = {flags2access(f->flags), ""};
1942 multiname_t m = {QNAME, &ns, 0, $1};
1943 $$.c = abc_getlocal_0($$.c);
1944 $$.c = abc_getproperty2($$.c, &m);
1947 if(f->kind == MEMBER_METHOD) {
1948 $$.t = TYPE_FUNCTION(f);
1953 /* look at classes in the current package and imported classes */
1954 } else if((a = find_class($1))) {
1956 $$.c = abc_getglobalscope($$.c);
1957 $$.c = abc_getslot($$.c, a->slot);
1960 $$.c = abc_getlex2($$.c, &m);
1962 $$.t = TYPE_CLASS(a);
1964 /* unknown object, let the avm2 resolve it */
1966 if(strcmp($1,"trace"))
1967 warning("Couldn't resolve %s, doing late binding", $1);
1968 state->late_binding = 1;
1970 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
1973 $$.c = abc_findpropstrict2($$.c, &m);
1974 $$.c = abc_getproperty2($$.c, &m);
1979 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1980 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1981 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1983 // ----------------- namespaces -------------------------------------------------
1985 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
1986 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
1987 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
1989 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER