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 syntaxerror("can't convert type %s to %s", from->name, to->name);
909 code_t*defaultvalue(code_t*c, classinfo_t*type)
911 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
912 c = abc_pushbyte(c, 0);
913 } else if(TYPE_IS_BOOLEAN(type)) {
914 c = abc_pushfalse(c);
921 char is_pushundefined(code_t*c)
923 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
926 void parserassert(int b)
928 if(!b) syntaxerror("internal error: assertion failed");
931 static classinfo_t* find_class(char*name)
935 c = registry_findclass(state->package, name);
937 /* try explicit imports */
938 dictentry_t* e = dict_get_slot(state->imports, name);
942 if(!strcmp(e->key, name)) {
943 c = (classinfo_t*)e->data;
948 /* try package.* imports */
949 import_list_t*l = state->wildcard_imports;
953 //printf("does package %s contain a class %s?\n", l->import->package, name);
954 c = registry_findclass(l->import->package, name);
958 /* try global package */
960 c = registry_findclass("", name);
965 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
969 [prefix code] [read instruction]
973 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
976 if(in && in->opcode == OPCODE_COERCE_A) {
977 in = code_cutlast(in);
980 syntaxerror("internal error");
982 /* chop off read instruction */
986 prefix = r->prev;r->prev = 0;
992 char use_temp_var = readbefore;
994 /* generate the write instruction, and maybe append a dup to the prefix code */
995 code_t* write = abc_nop(0);
996 if(r->opcode == OPCODE_GETPROPERTY) {
997 write->opcode = OPCODE_SETPROPERTY;
998 multiname_t*m = (multiname_t*)r->data[0];
999 write->data[0] = multiname_clone(m);
1000 if(m->type != QNAME && m->type != MULTINAME)
1001 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
1003 prefix = abc_dup(prefix); // we need the object, too
1006 } else if(r->opcode == OPCODE_GETSLOT) {
1007 write->opcode = OPCODE_SETSLOT;
1008 write->data[0] = r->data[0];
1010 prefix = abc_dup(prefix); // we need the object, too
1013 } else if(r->opcode == OPCODE_GETLOCAL) {
1014 write->opcode = OPCODE_SETLOCAL;
1015 write->data[0] = r->data[0];
1016 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1017 write->opcode = OPCODE_SETLOCAL_0;
1018 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1019 write->opcode = OPCODE_SETLOCAL_1;
1020 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1021 write->opcode = OPCODE_SETLOCAL_2;
1022 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1023 write->opcode = OPCODE_SETLOCAL_3;
1025 code_dump(r, 0, 0, "", stdout);
1026 syntaxerror("illegal lvalue: can't assign a value to this expression");
1033 /* with getproperty/getslot, we have to be extra careful not
1034 to execute the read code twice, as it might have side-effects
1035 (e.g. if the property is in fact a setter/getter combination)
1037 So read the value, modify it, and write it again,
1038 using prefix only once and making sure (by using a temporary
1039 register) that the return value is what we just wrote */
1040 temp = gettempvar();
1041 c = code_append(c, prefix);
1042 c = code_append(c, r);
1045 c = abc_setlocal(c, temp);
1047 c = code_append(c, middlepart);
1050 c = abc_setlocal(c, temp);
1052 c = code_append(c, write);
1053 c = abc_getlocal(c, temp);
1054 c = abc_kill(c, temp);
1056 /* if we're allowed to execute the read code twice *and*
1057 the middlepart doesn't modify the code, things are easier.
1059 code_t* r2 = code_dup(r);
1060 //c = code_append(c, prefix);
1061 parserassert(!prefix);
1062 c = code_append(c, r);
1063 c = code_append(c, middlepart);
1064 c = code_append(c, write);
1065 c = code_append(c, r2);
1068 /* even smaller version: overwrite the value without reading
1072 c = code_append(c, prefix);
1075 c = code_append(c, middlepart);
1076 c = code_append(c, write);
1077 c = code_append(c, r);
1079 temp = gettempvar();
1081 c = code_append(c, prefix);
1084 c = code_append(c, middlepart);
1086 c = abc_setlocal(c, temp);
1087 c = code_append(c, write);
1088 c = abc_getlocal(c, temp);
1101 /* ------------ code blocks / statements ---------------- */
1105 MAYBECODE: CODE {$$=$1;}
1106 MAYBECODE: {$$=code_new();}
1108 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1109 CODE: CODEPIECE {$$=$1;}
1111 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1112 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1113 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1114 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1115 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1116 CODEPIECE: ';' {$$=code_new();}
1117 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1118 CODEPIECE: VOIDEXPRESSION {$$=$1}
1119 CODEPIECE: FOR {$$=$1}
1120 CODEPIECE: WHILE {$$=$1}
1121 CODEPIECE: BREAK {$$=$1}
1122 CODEPIECE: RETURN {$$=$1}
1123 CODEPIECE: IF {$$=$1}
1124 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1125 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1127 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1128 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1129 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1131 /* ------------ variables --------------------------- */
1133 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1134 | {$$.c=abc_pushundefined(0);
1138 VAR : "const" | "var"
1139 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1141 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1142 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1144 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1146 if(variable_exists($2))
1147 syntaxerror("Variable %s already defined", $2);
1149 if(!is_subtype_of($4.t, $3)) {
1150 syntaxerror("Can't convert %s to %s", $4.t->name,
1154 int index = new_variable($2, $3);
1157 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1159 $$ = converttype($$, $4.t, $3);
1160 $$ = abc_setlocal($$, index);
1162 $$ = defaultvalue(0, $3);
1163 $$ = abc_setlocal($$, index);
1166 /* if this is a typed variable:
1167 push default value for type on stack */
1169 state->initcode = defaultvalue(state->initcode, $3);
1170 state->initcode = abc_setlocal(state->initcode, index);
1173 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1175 $$ = abc_coerce_a($$);
1176 $$ = abc_setlocal($$, index);
1182 /* that's the default for a local register, anyway
1184 state->initcode = abc_pushundefined(state->initcode);
1185 state->initcode = abc_setlocal(state->initcode, index);
1187 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1190 /* ------------ control flow ------------------------- */
1192 MAYBEELSE: %prec prec_none {$$ = code_new();}
1193 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1194 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1196 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1197 $$ = state->initcode;state->initcode=0;
1199 $$ = code_append($$, $4.c);
1200 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1202 $$ = code_append($$, $6);
1204 myjmp = $$ = abc_jump($$, 0);
1206 myif->branch = $$ = abc_label($$);
1208 $$ = code_append($$, $7);
1209 myjmp->branch = $$ = abc_label($$);
1212 $$ = killvars($$);old_state();
1215 FOR_INIT : {$$=code_new();}
1216 FOR_INIT : VARIABLE_DECLARATION
1217 FOR_INIT : VOIDEXPRESSION
1219 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1220 $$ = state->initcode;state->initcode=0;
1222 $$ = code_append($$, $4);
1223 code_t*loopstart = $$ = abc_label($$);
1224 $$ = code_append($$, $6.c);
1225 code_t*myif = $$ = abc_iffalse($$, 0);
1226 $$ = code_append($$, $10);
1227 $$ = code_append($$, $8);
1228 $$ = abc_jump($$, loopstart);
1229 code_t*out = $$ = abc_label($$);
1230 breakjumpsto($$, out);
1233 $$ = killvars($$);old_state();
1236 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1237 $$ = state->initcode;state->initcode=0;
1239 code_t*myjmp = $$ = abc_jump($$, 0);
1240 code_t*loopstart = $$ = abc_label($$);
1241 $$ = code_append($$, $6);
1242 myjmp->branch = $$ = abc_label($$);
1243 $$ = code_append($$, $4.c);
1244 $$ = abc_iftrue($$, loopstart);
1245 code_t*out = $$ = abc_label($$);
1246 breakjumpsto($$, out);
1248 $$ = killvars($$);old_state();
1252 $$ = abc___break__(0);
1255 /* ------------ packages and imports ---------------- */
1257 X_IDENTIFIER: T_IDENTIFIER
1258 | "package" {$$="package";}
1260 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1261 PACKAGE: X_IDENTIFIER {$$=$1;}
1263 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1264 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1266 IMPORT : "import" QNAME {
1269 syntaxerror("Couldn't import class\n");
1270 state_has_imports();
1271 dict_put(state->imports, c->name, c);
1274 IMPORT : "import" PACKAGE '.' '*' {
1277 state_has_imports();
1278 list_append(state->wildcard_imports, i);
1282 /* ------------ classes and interfaces (header) -------------- */
1284 MAYBE_MODIFIERS : {$$=0;}
1285 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1286 MODIFIER_LIST : MODIFIER {$$=$1;}
1287 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1289 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1290 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1291 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1292 | KW_STATIC {$$=FLAG_STATIC;}
1293 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1294 | KW_FINAL {$$=FLAG_FINAL;}
1295 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1296 | KW_NATIVE {$$=FLAG_NATIVE;}
1297 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1299 EXTENDS : {$$=registry_getobjectclass();}
1300 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1302 EXTENDS_LIST : {$$=list_new();}
1303 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1305 IMPLEMENTS_LIST : {$$=list_new();}
1306 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1308 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1309 EXTENDS IMPLEMENTS_LIST
1310 '{' {startclass($1,$3,$4,$5, 0);}
1311 MAYBE_DECLARATION_LIST
1314 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1316 '{' {startclass($1,$3,0,$4,1);}
1317 MAYBE_IDECLARATION_LIST
1320 /* ------------ classes and interfaces (body) -------------- */
1322 MAYBE_DECLARATION_LIST :
1323 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1324 DECLARATION_LIST : DECLARATION
1325 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1327 DECLARATION : SLOT_DECLARATION
1328 DECLARATION : FUNCTION_DECLARATION
1330 MAYBE_IDECLARATION_LIST :
1331 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1332 IDECLARATION_LIST : IDECLARATION
1333 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1335 IDECLARATION : "var" T_IDENTIFIER {
1336 syntaxerror("variable declarations not allowed in interfaces");
1338 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1340 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1341 syntaxerror("invalid method modifiers: interface methods always need to be public");
1343 startfunction(0,$1,$3,$4,&$6,$8);
1347 /* ------------ classes and interfaces (body, slots ) ------- */
1349 VARCONST: "var" | "const"
1351 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1353 memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
1355 info->flags = flags;
1358 namespace_t mname_ns = {flags2access(flags), ""};
1359 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1361 if(!(flags&FLAG_STATIC)) {
1364 t=abc_class_slot(state->cls, &mname, &m);
1366 t=abc_class_slot(state->cls, &mname, 0);
1368 info->slot = t->slot_id;
1372 t=abc_class_staticslot(state->cls, &mname, &m);
1374 t=abc_class_staticslot(state->cls, &mname, 0);
1376 info->slot = t->slot_id;
1378 if($5.c && !is_pushundefined($5.c)) {
1380 c = abc_getlocal_0(c);
1381 c = code_append(c, $5.c);
1382 c = converttype(c, $5.t, $4);
1383 c = abc_setslot(c, t->slot_id);
1384 if(!(flags&FLAG_STATIC))
1385 state->cls_init = code_append(state->cls_init, c);
1387 state->cls_static_init = code_append(state->cls_static_init, c);
1390 t->kind= TRAIT_CONST;
1394 /* ------------ constants -------------------------------------- */
1396 MAYBESTATICCONSTANT: {$$=0;}
1397 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1399 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1400 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1401 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1402 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1403 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1404 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1405 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1406 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1407 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1409 /* ------------ classes and interfaces (body, functions) ------- */
1411 // non-vararg version
1413 memset(&$$,0,sizeof($$));
1415 MAYBE_PARAM_LIST: PARAM_LIST {
1420 MAYBE_PARAM_LIST: "..." PARAM {
1421 memset(&$$,0,sizeof($$));
1423 list_append($$.list, $2);
1425 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1428 list_append($$.list, $4);
1432 PARAM_LIST: PARAM_LIST ',' PARAM {
1434 list_append($$.list, $3);
1437 memset(&$$,0,sizeof($$));
1438 list_append($$.list, $1);
1441 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1442 $$ = malloc(sizeof(param_t));
1447 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1448 $$ = malloc(sizeof(param_t));
1450 $$->type = TYPE_ANY;
1453 GETSET : "get" {$$=$1;}
1457 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1458 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1460 if(!state->m) syntaxerror("internal error: undefined function");
1464 /* ------------- package + class ids --------------- */
1466 CLASS: T_IDENTIFIER {
1468 /* try current package */
1469 $$ = find_class($1);
1470 if(!$$) syntaxerror("Could not find class %s\n", $1);
1473 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1474 $$ = registry_findclass($1, $3);
1475 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1478 QNAME: PACKAGEANDCLASS
1481 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1482 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1484 TYPE : QNAME {$$=$1;}
1485 | '*' {$$=registry_getanytype();}
1486 | "String" {$$=registry_getstringclass();}
1487 | "int" {$$=registry_getintclass();}
1488 | "uint" {$$=registry_getuintclass();}
1489 | "Boolean" {$$=registry_getbooleanclass();}
1490 | "Number" {$$=registry_getnumberclass();}
1492 MAYBETYPE: ':' TYPE {$$=$2;}
1495 /* ----------function calls, constructor calls ------ */
1497 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1498 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1500 MAYBE_EXPRESSION_LIST : {$$=0;}
1501 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1502 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1503 typedcode_t*t = malloc(sizeof(typedcode_t));
1505 list_append($$, t);}
1506 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1507 typedcode_t*t = malloc(sizeof(typedcode_t));
1509 list_append($$, t);}
1511 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1516 $$.c = abc_getglobalscope($$.c);
1517 $$.c = abc_getslot($$.c, $2->slot);
1519 $$.c = abc_findpropstrict2($$.c, &m);
1522 typedcode_list_t*l = $3;
1525 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1530 $$.c = abc_construct($$.c, len);
1532 $$.c = abc_constructprop2($$.c, &m, len);
1536 /* TODO: use abc_call (for calling local variables),
1537 abc_callstatic (for calling own methods)
1540 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1541 typedcode_list_t*l = $3;
1543 code_t*paramcode = 0;
1545 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1551 if($$.c->opcode == OPCODE_COERCE_A) {
1552 $$.c = code_cutlast($$.c);
1556 multiname_t*name = 0;
1557 if($$.c->opcode == OPCODE_GETPROPERTY) {
1558 name = multiname_clone($$.c->data[0]);
1559 $$.c = code_cutlast($$.c);
1560 $$.c = code_append($$.c, paramcode);
1561 $$.c = abc_callproperty2($$.c, name, len);
1562 } else if($$.c->opcode == OPCODE_GETSLOT) {
1563 int slot = (int)(ptroff_t)$$.c->data[0];
1564 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1565 if(t->kind!=TRAIT_METHOD) {
1566 //flash allows to assign closures to members.
1567 //syntaxerror("not a function");
1570 $$.c = code_cutlast($$.c);
1571 $$.c = code_append($$.c, paramcode);
1572 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1573 $$.c = abc_callproperty2($$.c, name, len);
1575 $$.c = abc_getlocal_0($$.c);
1576 $$.c = code_append($$.c, paramcode);
1577 $$.c = abc_call($$.c, len);
1582 if(TYPE_IS_FUNCTION($1.t) &&
1583 (f = registry_findmember($1.t, "call"))) {
1584 $$.t = f->return_type;
1586 $$.c = abc_coerce_a($$.c);
1591 RETURN: "return" %prec prec_none {
1592 $$ = abc_returnvoid(0);
1594 RETURN: "return" EXPRESSION {
1596 $$ = abc_returnvalue($$);
1598 // ----------------------- expression types -------------------------------------
1600 NONCOMMAEXPRESSION : E %prec prec_belowminus {$$=$1;}
1601 EXPRESSION : E %prec prec_belowminus {$$ = $1;}
1602 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1604 $$.c = cut_last_push($$.c);
1605 $$.c = code_append($$.c,$3.c);
1608 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1610 // ----------------------- expression evaluation -------------------------------------
1613 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1615 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1619 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1620 //MULTINAME(m, registry_getintclass());
1621 //$$.c = abc_coerce2($$.c, &m); // FIXME
1624 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1627 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1630 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1633 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1636 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1639 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1640 $$.t = TYPE_BOOLEAN;
1642 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1643 $$.t = TYPE_BOOLEAN;
1645 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1650 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1651 $$.t = TYPE_BOOLEAN;
1653 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1654 $$.t = TYPE_BOOLEAN;
1656 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1657 $$.t = TYPE_BOOLEAN;
1659 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1660 $$.t = TYPE_BOOLEAN;
1662 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1663 $$.t = TYPE_BOOLEAN;
1665 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1666 $$.t = TYPE_BOOLEAN;
1668 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1669 $$.t = TYPE_BOOLEAN;
1672 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1674 $$.c = converttype($$.c, $1.t, $$.t);
1675 $$.c = abc_dup($$.c);
1676 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1677 $$.c = cut_last_push($$.c);
1678 $$.c = code_append($$.c,$3.c);
1679 $$.c = converttype($$.c, $3.t, $$.t);
1680 code_t*label = $$.c = abc_label($$.c);
1681 jmp->branch = label;
1684 $$.t = join_types($1.t, $3.t, 'A');
1685 /*printf("%08x:\n",$1.t);
1686 code_dump($1.c, 0, 0, "", stdout);
1687 printf("%08x:\n",$3.t);
1688 code_dump($3.c, 0, 0, "", stdout);
1689 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1691 $$.c = converttype($$.c, $1.t, $$.t);
1692 $$.c = abc_dup($$.c);
1693 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1694 $$.c = cut_last_push($$.c);
1695 $$.c = code_append($$.c,$3.c);
1696 $$.c = converttype($$.c, $3.t, $$.t);
1697 code_t*label = $$.c = abc_label($$.c);
1698 jmp->branch = label;
1701 E : '!' E {$$.c=$2.c;
1702 $$.c = abc_not($$.c);
1703 $$.t = TYPE_BOOLEAN;
1708 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1709 $$.t = join_types($1.t, $3.t, '+');
1711 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1712 $$.t = join_types($1.t, $3.t, '%');
1714 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1715 $$.t = join_types($1.t, $3.t, '*');
1720 E : '(' E ')' {$$=$2;}
1725 $$.c = code_append($$.c, $3.c);
1727 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1728 $$.c = abc_getproperty2($$.c, &m);
1733 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1734 c=abc_multiply_i(c);
1738 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1739 $$.c = toreadwrite($1.c, c, 0, 0);
1743 code_t*c = abc_modulo($3.c);
1744 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1745 $$.c = toreadwrite($1.c, c, 0, 0);
1749 code_t*c = abc_lshift($3.c);
1750 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1751 $$.c = toreadwrite($1.c, c, 0, 0);
1755 code_t*c = abc_rshift($3.c);
1756 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1757 $$.c = toreadwrite($1.c, c, 0, 0);
1761 code_t*c = abc_urshift($3.c);
1762 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1763 $$.c = toreadwrite($1.c, c, 0, 0);
1767 code_t*c = abc_divide($3.c);
1768 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1769 $$.c = toreadwrite($1.c, c, 0, 0);
1774 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1779 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1781 $$.c = toreadwrite($1.c, c, 0, 0);
1784 E : E "-=" E { code_t*c = $3.c;
1785 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1786 c=abc_subtract_i(c);
1790 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1792 $$.c = toreadwrite($1.c, c, 0, 0);
1795 E : E '=' E { code_t*c = 0;
1796 c = code_append(c, $3.c);
1797 c = converttype(c, $3.t, $1.t);
1798 $$.c = toreadwrite($1.c, c, 1, 0);
1802 // TODO: use inclocal where appropriate
1803 E : E "++" { code_t*c = 0;
1804 classinfo_t*type = $1.t;
1805 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1806 c=abc_increment_i(c);
1812 c=converttype(c, type, $1.t);
1813 $$.c = toreadwrite($1.c, c, 0, 1);
1816 E : E "--" { code_t*c = 0;
1817 classinfo_t*type = $1.t;
1818 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1819 c=abc_decrement_i(c);
1825 c=converttype(c, type, $1.t);
1826 $$.c = toreadwrite($1.c, c, 0, 1);
1830 E : "++" E { code_t*c = 0;
1831 classinfo_t*type = $2.t;
1832 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1833 c=abc_increment_i(c);
1839 c=converttype(c, type, $2.t);
1840 $$.c = toreadwrite($2.c, c, 0, 0);
1844 E : "--" E { code_t*c = 0;
1845 classinfo_t*type = $2.t;
1846 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1847 c=abc_decrement_i(c);
1853 c=converttype(c, type, $2.t);
1854 $$.c = toreadwrite($2.c, c, 0, 0);
1858 E : E '.' T_IDENTIFIER
1860 classinfo_t*t = $1.t;
1862 if(TYPE_IS_CLASS(t)) {
1863 memberinfo_t*m = registry_findmember($1.t, "prototype");
1864 if(!m) syntaxerror("identifier '%s' not found in anonymous class", $3);
1869 memberinfo_t*f = registry_findmember(t, $3);
1871 if(f && !is_static != !(f->flags&FLAG_STATIC))
1874 if(f && f->slot && !noslot) {
1875 $$.c = abc_getslot($$.c, f->slot);
1878 namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
1879 multiname_t m = {QNAME, &ns, 0, $3};
1880 $$.c = abc_getproperty2($$.c, &m);
1882 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1883 $$.c = abc_getproperty2($$.c, &m);
1886 /* determine type */
1888 if(f->kind == MEMBER_METHOD) {
1889 $$.t = TYPE_FUNCTION(f);
1894 $$.c = abc_coerce_a($$.c);
1895 $$.t = registry_getanytype();
1898 /* when resolving a property on an unknown type, we do know the
1899 name of the property (and don't seem to need the package), but
1900 we do need to make avm2 try out all access modes */
1901 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1902 $$.c = abc_getproperty2($$.c, &m);
1903 $$.c = abc_coerce_a($$.c);
1904 $$.t = registry_getanytype();
1908 VAR_READ : T_IDENTIFIER {
1915 /* look at variables */
1916 if((i = find_variable($1, &$$.t)) >= 0) {
1917 // $1 is a local variable
1918 $$.c = abc_getlocal($$.c, i);
1920 /* look at current class' members */
1921 } else if((f = registry_findmember(state->clsinfo, $1))) {
1922 // $1 is a function in this class
1923 int var_is_static = (f->flags&FLAG_STATIC);
1924 int i_am_static = (state->minfo?(state->minfo->flags&FLAG_STATIC):FLAG_STATIC);
1925 if(var_is_static != i_am_static) {
1926 /* there doesn't seem to be any "static" way to access
1927 static properties of a class */
1928 state->late_binding = 1;
1930 namespace_t ns = {flags2access(f->flags), ""};
1931 multiname_t m = {QNAME, &ns, 0, $1};
1932 $$.c = abc_findpropstrict2($$.c, &m);
1933 $$.c = abc_getproperty2($$.c, &m);
1936 $$.c = abc_getlocal_0($$.c);
1937 $$.c = abc_getslot($$.c, f->slot);
1939 namespace_t ns = {flags2access(f->flags), ""};
1940 multiname_t m = {QNAME, &ns, 0, $1};
1941 $$.c = abc_getlocal_0($$.c);
1942 $$.c = abc_getproperty2($$.c, &m);
1945 if(f->kind == MEMBER_METHOD) {
1946 $$.t = TYPE_FUNCTION(f);
1951 /* look at classes in the current package and imported classes */
1952 } else if((a = find_class($1))) {
1954 $$.c = abc_getglobalscope($$.c);
1955 $$.c = abc_getslot($$.c, a->slot);
1958 $$.c = abc_getlex2($$.c, &m);
1960 $$.t = TYPE_CLASS(a);
1962 /* unknown object, let the avm2 resolve it */
1964 if(strcmp($1,"trace"))
1965 warning("Couldn't resolve %s, doing late binding", $1);
1966 state->late_binding = 1;
1968 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
1971 $$.c = abc_findpropstrict2($$.c, &m);
1972 $$.c = abc_getproperty2($$.c, &m);
1977 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1978 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1979 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1981 // ----------------- namespaces -------------------------------------------------
1983 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
1984 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
1985 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
1987 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER