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 code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
935 [prefix code] [read instruction]
939 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
942 if(in && in->opcode == OPCODE_COERCE_A) {
943 in = code_cutlast(in);
946 syntaxerror("internal error");
948 /* chop off read instruction */
952 prefix = r->prev;r->prev = 0;
958 char use_temp_var = readbefore;
960 /* generate the write instruction, and maybe append a dup to the prefix code */
961 code_t* write = abc_nop(0);
962 if(r->opcode == OPCODE_GETPROPERTY) {
963 write->opcode = OPCODE_SETPROPERTY;
964 multiname_t*m = (multiname_t*)r->data[0];
965 write->data[0] = multiname_clone(m);
966 if(m->type != QNAME && m->type != MULTINAME)
967 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
969 prefix = abc_dup(prefix); // we need the object, too
972 } else if(r->opcode == OPCODE_GETSLOT) {
973 write->opcode = OPCODE_SETSLOT;
974 write->data[0] = r->data[0];
976 prefix = abc_dup(prefix); // we need the object, too
979 } else if(r->opcode == OPCODE_GETLOCAL) {
980 write->opcode = OPCODE_SETLOCAL;
981 write->data[0] = r->data[0];
982 } else if(r->opcode == OPCODE_GETLOCAL_0) {
983 write->opcode = OPCODE_SETLOCAL_0;
984 } else if(r->opcode == OPCODE_GETLOCAL_1) {
985 write->opcode = OPCODE_SETLOCAL_1;
986 } else if(r->opcode == OPCODE_GETLOCAL_2) {
987 write->opcode = OPCODE_SETLOCAL_2;
988 } else if(r->opcode == OPCODE_GETLOCAL_3) {
989 write->opcode = OPCODE_SETLOCAL_3;
991 code_dump(r, 0, 0, "", stdout);
992 syntaxerror("illegal lvalue: can't assign a value to this expression");
999 /* with getproperty/getslot, we have to be extra careful not
1000 to execute the read code twice, as it might have side-effects
1001 (e.g. if the property is in fact a setter/getter combination)
1003 So read the value, modify it, and write it again,
1004 using prefix only once and making sure (by using a temporary
1005 register) that the return value is what we just wrote */
1006 temp = gettempvar();
1007 c = code_append(c, prefix);
1008 c = code_append(c, r);
1011 c = abc_setlocal(c, temp);
1013 c = code_append(c, middlepart);
1016 c = abc_setlocal(c, temp);
1018 c = code_append(c, write);
1019 c = abc_getlocal(c, temp);
1020 c = abc_kill(c, temp);
1022 /* if we're allowed to execute the read code twice *and*
1023 the middlepart doesn't modify the code, things are easier.
1025 code_t* r2 = code_dup(r);
1026 //c = code_append(c, prefix);
1027 parserassert(!prefix);
1028 c = code_append(c, r);
1029 c = code_append(c, middlepart);
1030 c = code_append(c, write);
1031 c = code_append(c, r2);
1034 /* even smaller version: overwrite the value without reading
1038 c = code_append(c, prefix);
1041 c = code_append(c, middlepart);
1042 c = code_append(c, write);
1043 c = code_append(c, r);
1045 temp = gettempvar();
1047 c = code_append(c, prefix);
1050 c = code_append(c, middlepart);
1052 c = abc_setlocal(c, temp);
1053 c = code_append(c, write);
1054 c = abc_getlocal(c, temp);
1067 /* ------------ code blocks / statements ---------------- */
1071 MAYBECODE: CODE {$$=$1;}
1072 MAYBECODE: {$$=code_new();}
1074 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1075 CODE: CODEPIECE {$$=$1;}
1077 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1078 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1079 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1080 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1081 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1082 CODEPIECE: ';' {$$=code_new();}
1083 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1084 CODEPIECE: VOIDEXPRESSION {$$=$1}
1085 CODEPIECE: FOR {$$=$1}
1086 CODEPIECE: WHILE {$$=$1}
1087 CODEPIECE: BREAK {$$=$1}
1088 CODEPIECE: RETURN {$$=$1}
1089 CODEPIECE: IF {$$=$1}
1090 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1091 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1093 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1094 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1095 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1097 /* ------------ variables --------------------------- */
1099 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1100 | {$$.c=abc_pushundefined(0);
1104 VAR : "const" | "var"
1105 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1107 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1108 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1110 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1112 if(variable_exists($2))
1113 syntaxerror("Variable %s already defined", $2);
1115 if(!is_subtype_of($4.t, $3)) {
1116 syntaxerror("Can't convert %s to %s", $4.t->name,
1120 int index = new_variable($2, $3);
1123 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1125 $$ = converttype($$, $4.t, $3);
1126 $$ = abc_setlocal($$, index);
1128 $$ = defaultvalue(0, $3);
1129 $$ = abc_setlocal($$, index);
1132 /* if this is a typed variable:
1133 push default value for type on stack */
1135 state->initcode = defaultvalue(state->initcode, $3);
1136 state->initcode = abc_setlocal(state->initcode, index);
1139 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1141 $$ = abc_coerce_a($$);
1142 $$ = abc_setlocal($$, index);
1148 /* that's the default for a local register, anyway
1150 state->initcode = abc_pushundefined(state->initcode);
1151 state->initcode = abc_setlocal(state->initcode, index);
1153 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1156 /* ------------ control flow ------------------------- */
1158 MAYBEELSE: %prec prec_none {$$ = code_new();}
1159 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1160 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1162 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1163 $$ = state->initcode;state->initcode=0;
1165 $$ = code_append($$, $4.c);
1166 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1168 $$ = code_append($$, $6);
1170 myjmp = $$ = abc_jump($$, 0);
1172 myif->branch = $$ = abc_label($$);
1174 $$ = code_append($$, $7);
1175 myjmp->branch = $$ = abc_label($$);
1178 $$ = killvars($$);old_state();
1181 FOR_INIT : {$$=code_new();}
1182 FOR_INIT : VARIABLE_DECLARATION
1183 FOR_INIT : VOIDEXPRESSION
1185 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1186 $$ = state->initcode;state->initcode=0;
1188 $$ = code_append($$, $4);
1189 code_t*loopstart = $$ = abc_label($$);
1190 $$ = code_append($$, $6.c);
1191 code_t*myif = $$ = abc_iffalse($$, 0);
1192 $$ = code_append($$, $10);
1193 $$ = code_append($$, $8);
1194 $$ = abc_jump($$, loopstart);
1195 code_t*out = $$ = abc_label($$);
1196 breakjumpsto($$, out);
1199 $$ = killvars($$);old_state();
1202 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1203 $$ = state->initcode;state->initcode=0;
1205 code_t*myjmp = $$ = abc_jump($$, 0);
1206 code_t*loopstart = $$ = abc_label($$);
1207 $$ = code_append($$, $6);
1208 myjmp->branch = $$ = abc_label($$);
1209 $$ = code_append($$, $4.c);
1210 $$ = abc_iftrue($$, loopstart);
1211 code_t*out = $$ = abc_label($$);
1212 breakjumpsto($$, out);
1214 $$ = killvars($$);old_state();
1218 $$ = abc___break__(0);
1221 /* ------------ packages and imports ---------------- */
1223 X_IDENTIFIER: T_IDENTIFIER
1224 | "package" {$$="package";}
1226 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1227 PACKAGE: X_IDENTIFIER {$$=$1;}
1229 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1230 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1232 IMPORT : "import" QNAME {
1235 syntaxerror("Couldn't import class\n");
1236 state_has_imports();
1237 dict_put(state->imports, c->name, c);
1240 IMPORT : "import" PACKAGE '.' '*' {
1243 state_has_imports();
1244 list_append(state->wildcard_imports, i);
1248 /* ------------ classes and interfaces (header) -------------- */
1250 MAYBE_MODIFIERS : {$$=0;}
1251 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1252 MODIFIER_LIST : MODIFIER {$$=$1;}
1253 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1255 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1256 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1257 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1258 | KW_STATIC {$$=FLAG_STATIC;}
1259 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1260 | KW_FINAL {$$=FLAG_FINAL;}
1261 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1262 | KW_NATIVE {$$=FLAG_NATIVE;}
1263 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1265 EXTENDS : {$$=registry_getobjectclass();}
1266 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1268 EXTENDS_LIST : {$$=list_new();}
1269 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1271 IMPLEMENTS_LIST : {$$=list_new();}
1272 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1274 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1275 EXTENDS IMPLEMENTS_LIST
1276 '{' {startclass($1,$3,$4,$5, 0);}
1277 MAYBE_DECLARATION_LIST
1280 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1282 '{' {startclass($1,$3,0,$4,1);}
1283 MAYBE_IDECLARATION_LIST
1286 /* ------------ classes and interfaces (body) -------------- */
1288 MAYBE_DECLARATION_LIST :
1289 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1290 DECLARATION_LIST : DECLARATION
1291 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1293 DECLARATION : SLOT_DECLARATION
1294 DECLARATION : FUNCTION_DECLARATION
1296 MAYBE_IDECLARATION_LIST :
1297 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1298 IDECLARATION_LIST : IDECLARATION
1299 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1301 IDECLARATION : "var" T_IDENTIFIER {
1302 syntaxerror("variable declarations not allowed in interfaces");
1304 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1306 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1307 syntaxerror("invalid method modifiers: interface methods always need to be public");
1309 startfunction(0,$1,$3,$4,&$6,$8);
1313 /* ------------ classes and interfaces (body, slots ) ------- */
1315 VARCONST: "var" | "const"
1317 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1319 memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
1321 info->flags = flags;
1324 namespace_t mname_ns = {flags2access(flags), ""};
1325 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1327 if(!(flags&FLAG_STATIC)) {
1330 t=abc_class_slot(state->cls, &mname, &m);
1332 t=abc_class_slot(state->cls, &mname, 0);
1334 info->slot = t->slot_id;
1338 t=abc_class_staticslot(state->cls, &mname, &m);
1340 t=abc_class_staticslot(state->cls, &mname, 0);
1342 info->slot = t->slot_id;
1344 if($5.c && !is_pushundefined($5.c)) {
1346 c = abc_getlocal_0(c);
1347 c = code_append(c, $5.c);
1348 c = converttype(c, $5.t, $4);
1349 c = abc_setslot(c, t->slot_id);
1350 if(!(flags&FLAG_STATIC))
1351 state->cls_init = code_append(state->cls_init, c);
1353 state->cls_static_init = code_append(state->cls_static_init, c);
1356 t->kind= TRAIT_CONST;
1360 /* ------------ constants -------------------------------------- */
1362 MAYBESTATICCONSTANT: {$$=0;}
1363 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1365 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1366 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1367 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1368 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1369 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1370 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1371 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1372 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1373 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1375 /* ------------ classes and interfaces (body, functions) ------- */
1377 // non-vararg version
1379 memset(&$$,0,sizeof($$));
1381 MAYBE_PARAM_LIST: PARAM_LIST {
1386 MAYBE_PARAM_LIST: "..." PARAM {
1387 memset(&$$,0,sizeof($$));
1389 list_append($$.list, $2);
1391 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1394 list_append($$.list, $4);
1398 PARAM_LIST: PARAM_LIST ',' PARAM {
1400 list_append($$.list, $3);
1403 memset(&$$,0,sizeof($$));
1404 list_append($$.list, $1);
1407 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1408 $$ = malloc(sizeof(param_t));
1413 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1414 $$ = malloc(sizeof(param_t));
1416 $$->type = TYPE_ANY;
1419 GETSET : "get" {$$=$1;}
1423 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1424 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1426 if(!state->m) syntaxerror("internal error: undefined function");
1430 /* ------------- package + class ids --------------- */
1432 CLASS: T_IDENTIFIER {
1434 /* try current package */
1435 $$ = registry_findclass(state->package, $1);
1437 /* try explicit imports */
1438 dictentry_t* e = dict_get_slot(state->imports, $1);
1442 if(!strcmp(e->key, $1)) {
1443 $$ = (classinfo_t*)e->data;
1448 /* try package.* imports */
1449 import_list_t*l = state->wildcard_imports;
1453 //printf("does package %s contain a class %s?\n", l->import->package, $1);
1454 $$ = registry_findclass(l->import->package, $1);
1458 /* try global package */
1460 $$ = registry_findclass("", $1);
1463 if(!$$) syntaxerror("Could not find class %s\n", $1);
1466 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1467 $$ = registry_findclass($1, $3);
1468 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1471 QNAME: PACKAGEANDCLASS
1474 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1475 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1477 TYPE : QNAME {$$=$1;}
1478 | '*' {$$=registry_getanytype();}
1479 | "String" {$$=registry_getstringclass();}
1480 | "int" {$$=registry_getintclass();}
1481 | "uint" {$$=registry_getuintclass();}
1482 | "Boolean" {$$=registry_getbooleanclass();}
1483 | "Number" {$$=registry_getnumberclass();}
1485 MAYBETYPE: ':' TYPE {$$=$2;}
1488 /* ----------function calls, constructor calls ------ */
1490 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1491 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1493 MAYBE_EXPRESSION_LIST : {$$=0;}
1494 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1495 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1496 typedcode_t*t = malloc(sizeof(typedcode_t));
1498 list_append($$, t);}
1499 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1500 typedcode_t*t = malloc(sizeof(typedcode_t));
1502 list_append($$, t);}
1504 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1509 $$.c = abc_getglobalscope($$.c);
1510 $$.c = abc_getslot($$.c, $2->slot);
1512 $$.c = abc_findpropstrict2($$.c, &m);
1515 typedcode_list_t*l = $3;
1518 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1523 $$.c = abc_construct($$.c, len);
1525 $$.c = abc_constructprop2($$.c, &m, len);
1529 /* TODO: use abc_call (for calling local variables),
1530 abc_callstatic (for calling own methods)
1533 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1534 typedcode_list_t*l = $3;
1536 code_t*paramcode = 0;
1538 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1544 if($$.c->opcode == OPCODE_COERCE_A) {
1545 $$.c = code_cutlast($$.c);
1549 multiname_t*name = 0;
1550 if($$.c->opcode == OPCODE_GETPROPERTY) {
1551 name = multiname_clone($$.c->data[0]);
1552 $$.c = code_cutlast($$.c);
1553 $$.c = code_append($$.c, paramcode);
1554 $$.c = abc_callproperty2($$.c, name, len);
1555 } else if($$.c->opcode == OPCODE_GETSLOT) {
1556 int slot = (int)(ptroff_t)$$.c->data[0];
1557 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1558 if(t->kind!=TRAIT_METHOD) {
1559 //flash allows to assign closures to members.
1560 //syntaxerror("not a function");
1563 $$.c = code_cutlast($$.c);
1564 $$.c = code_append($$.c, paramcode);
1565 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1566 $$.c = abc_callproperty2($$.c, name, len);
1568 $$.c = abc_getlocal_0($$.c);
1569 $$.c = code_append($$.c, paramcode);
1570 $$.c = abc_call($$.c, len);
1575 if(TYPE_IS_FUNCTION($1.t) &&
1576 (f = registry_findmember($1.t, "call"))) {
1577 $$.t = f->return_type;
1579 $$.c = abc_coerce_a($$.c);
1584 RETURN: "return" %prec prec_none {
1585 $$ = abc_returnvoid(0);
1587 RETURN: "return" EXPRESSION {
1589 $$ = abc_returnvalue($$);
1591 // ----------------------- expression types -------------------------------------
1593 NONCOMMAEXPRESSION : E %prec prec_belowminus {$$=$1;}
1594 EXPRESSION : E %prec prec_belowminus {$$ = $1;}
1595 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1597 $$.c = cut_last_push($$.c);
1598 $$.c = code_append($$.c,$3.c);
1601 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1603 // ----------------------- expression evaluation -------------------------------------
1606 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1608 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1612 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1613 //MULTINAME(m, registry_getintclass());
1614 //$$.c = abc_coerce2($$.c, &m); // FIXME
1617 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1620 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1623 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1626 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1629 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1632 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1633 $$.t = TYPE_BOOLEAN;
1635 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1636 $$.t = TYPE_BOOLEAN;
1638 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1643 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1644 $$.t = TYPE_BOOLEAN;
1646 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1647 $$.t = TYPE_BOOLEAN;
1649 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1650 $$.t = TYPE_BOOLEAN;
1652 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1653 $$.t = TYPE_BOOLEAN;
1655 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1656 $$.t = TYPE_BOOLEAN;
1658 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1659 $$.t = TYPE_BOOLEAN;
1661 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1662 $$.t = TYPE_BOOLEAN;
1665 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1667 $$.c = converttype($$.c, $1.t, $$.t);
1668 $$.c = abc_dup($$.c);
1669 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1670 $$.c = cut_last_push($$.c);
1671 $$.c = code_append($$.c,$3.c);
1672 $$.c = converttype($$.c, $3.t, $$.t);
1673 code_t*label = $$.c = abc_label($$.c);
1674 jmp->branch = label;
1677 $$.t = join_types($1.t, $3.t, 'A');
1678 /*printf("%08x:\n",$1.t);
1679 code_dump($1.c, 0, 0, "", stdout);
1680 printf("%08x:\n",$3.t);
1681 code_dump($3.c, 0, 0, "", stdout);
1682 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1684 $$.c = converttype($$.c, $1.t, $$.t);
1685 $$.c = abc_dup($$.c);
1686 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1687 $$.c = cut_last_push($$.c);
1688 $$.c = code_append($$.c,$3.c);
1689 $$.c = converttype($$.c, $3.t, $$.t);
1690 code_t*label = $$.c = abc_label($$.c);
1691 jmp->branch = label;
1694 E : '!' E {$$.c=$2.c;
1695 $$.c = abc_not($$.c);
1696 $$.t = TYPE_BOOLEAN;
1701 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1702 $$.t = join_types($1.t, $3.t, '+');
1704 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1705 $$.t = join_types($1.t, $3.t, '%');
1707 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1708 $$.t = join_types($1.t, $3.t, '*');
1713 E : '(' E ')' {$$=$2;}
1718 $$.c = code_append($$.c, $3.c);
1720 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1721 $$.c = abc_getproperty2($$.c, &m);
1726 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1727 c=abc_multiply_i(c);
1731 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1732 $$.c = toreadwrite($1.c, c, 0, 0);
1736 code_t*c = abc_modulo($3.c);
1737 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1738 $$.c = toreadwrite($1.c, c, 0, 0);
1742 code_t*c = abc_lshift($3.c);
1743 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1744 $$.c = toreadwrite($1.c, c, 0, 0);
1748 code_t*c = abc_rshift($3.c);
1749 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1750 $$.c = toreadwrite($1.c, c, 0, 0);
1754 code_t*c = abc_urshift($3.c);
1755 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1756 $$.c = toreadwrite($1.c, c, 0, 0);
1760 code_t*c = abc_divide($3.c);
1761 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1762 $$.c = toreadwrite($1.c, c, 0, 0);
1767 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1772 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1774 $$.c = toreadwrite($1.c, c, 0, 0);
1777 E : E "-=" E { code_t*c = $3.c;
1778 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1779 c=abc_subtract_i(c);
1783 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1785 $$.c = toreadwrite($1.c, c, 0, 0);
1788 E : E '=' E { code_t*c = 0;
1789 c = code_append(c, $3.c);
1790 c = converttype(c, $3.t, $1.t);
1791 $$.c = toreadwrite($1.c, c, 1, 0);
1795 // TODO: use inclocal where appropriate
1796 E : E "++" { code_t*c = 0;
1797 classinfo_t*type = $1.t;
1798 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1799 c=abc_increment_i(c);
1805 c=converttype(c, type, $1.t);
1806 $$.c = toreadwrite($1.c, c, 0, 1);
1809 E : E "--" { code_t*c = 0;
1810 classinfo_t*type = $1.t;
1811 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1812 c=abc_decrement_i(c);
1818 c=converttype(c, type, $1.t);
1819 $$.c = toreadwrite($1.c, c, 0, 1);
1823 E : "++" E { code_t*c = 0;
1824 classinfo_t*type = $2.t;
1825 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1826 c=abc_increment_i(c);
1832 c=converttype(c, type, $2.t);
1833 $$.c = toreadwrite($2.c, c, 0, 0);
1837 E : "--" E { code_t*c = 0;
1838 classinfo_t*type = $2.t;
1839 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1840 c=abc_decrement_i(c);
1846 c=converttype(c, type, $2.t);
1847 $$.c = toreadwrite($2.c, c, 0, 0);
1851 E : E '.' T_IDENTIFIER
1854 memberinfo_t*f = registry_findmember($$.t, $3);
1857 $$.c = abc_getslot($$.c, f->slot);
1860 namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
1861 multiname_t m = {QNAME, &ns, 0, $3};
1862 $$.c = abc_getproperty2($$.c, &m);
1864 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1865 $$.c = abc_getproperty2($$.c, &m);
1868 /* determine type */
1870 if(f->kind == MEMBER_METHOD) {
1871 $$.t = TYPE_FUNCTION(f);
1876 $$.c = abc_coerce_a($$.c);
1877 $$.t = registry_getanytype();
1880 /* when resolving a property on an unknown type, we do know the
1881 name of the property (and don't seem to need the package), but
1882 we do need to make avm2 try out all access modes */
1883 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1884 $$.c = abc_getproperty2($$.c, &m);
1885 $$.c = abc_coerce_a($$.c);
1886 $$.t = registry_getanytype();
1890 VAR_READ : T_IDENTIFIER {
1897 /* look at variables */
1898 if((i = find_variable($1, &$$.t)) >= 0) {
1899 // $1 is a local variable
1900 $$.c = abc_getlocal($$.c, i);
1902 /* look at current class' members */
1903 } else if((f = registry_findmember(state->clsinfo, $1))) {
1904 // $1 is a function in this class
1905 int var_is_static = (f->flags&FLAG_STATIC);
1906 int i_am_static = (state->minfo?(state->minfo->flags&FLAG_STATIC):FLAG_STATIC);
1907 if(var_is_static != i_am_static) {
1908 /* there doesn't seem to be any "static" way to access
1909 static properties of a class */
1910 state->late_binding = 1;
1912 namespace_t ns = {flags2access(f->flags), ""};
1913 multiname_t m = {QNAME, &ns, 0, $1};
1914 $$.c = abc_findpropstrict2($$.c, &m);
1915 $$.c = abc_getproperty2($$.c, &m);
1918 $$.c = abc_getlocal_0($$.c);
1919 $$.c = abc_getslot($$.c, f->slot);
1921 namespace_t ns = {flags2access(f->flags), ""};
1922 multiname_t m = {QNAME, &ns, 0, $1};
1923 $$.c = abc_getlocal_0($$.c);
1924 $$.c = abc_getproperty2($$.c, &m);
1927 if(f->kind == MEMBER_METHOD) {
1928 $$.t = TYPE_FUNCTION(f);
1933 /* look at classes in the current package */
1934 } else if((a = registry_findclass(state->package, $1))) {
1936 $$.c = abc_getglobalscope($$.c);
1937 $$.c = abc_getslot($$.c, a->slot);
1940 $$.c = abc_getlex2($$.c, &m);
1942 /* this is not entirely correct (this is the class itself,
1943 not an object of this class) */
1946 /* unknown object, let the avm2 resolve it */
1948 if(strcmp($1,"trace"))
1949 warning("Couldn't resolve %s, doing late binding", $1);
1950 state->late_binding = 1;
1952 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
1955 $$.c = abc_findpropstrict2($$.c, &m);
1956 $$.c = abc_getproperty2($$.c, &m);
1961 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1962 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1963 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1965 // ----------------- namespaces -------------------------------------------------
1967 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
1968 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
1969 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
1971 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER