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);
771 if(flags&FLAG_STATIC)
772 state->m = abc_class_staticmethod(state->cls, type2, &mname);
774 state->m = abc_class_method(state->cls, type2, &mname);
775 slot = state->m->trait->slot_id;
777 state->minfo = registerfunction(getset, flags, name, params, return_type, slot);
779 if(getset == KW_GET) state->m->trait->kind = TRAIT_GETTER;
780 if(getset == KW_SET) state->m->trait->kind = TRAIT_SETTER;
781 if(params->varargs) state->m->flags |= METHOD_NEED_REST;
785 for(p=params->list;p;p=p->next) {
786 if(params->varargs && !p->next) {
787 break; //varargs: omit last parameter in function signature
789 multiname_t*m = sig2mname(p->param->type);
790 list_append(state->m->parameters, m);
791 if(p->param->value) {
792 check_constant_against_type(p->param->type, p->param->value);
793 opt=1;list_append(state->m->optional_parameters, p->param->value);
795 syntaxerror("non-optional parameter not allowed after optional parameters");
799 /* state->vars is initialized by state_new */
800 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->clsinfo)!=0) syntaxerror("Internal error");
802 for(p=params->list;p;p=p->next) {
803 new_variable(p->param->name, p->param->type);
806 static void endfunction(code_t*body)
809 if(!(state->cls->flags & CLASS_INTERFACE)) {
811 if(state->late_binding) {
812 c = abc_getlocal_0(c);
813 c = abc_pushscope(c);
815 c = code_append(c, state->initcode);
816 c = code_append(c, body);
818 /* append return if necessary */
819 if(!c || c->opcode != OPCODE_RETURNVOID &&
820 c->opcode != OPCODE_RETURNVALUE) {
821 c = abc_returnvoid(c);
823 if(state->m->body->code) syntaxerror("internal error");
824 state->m->body->code = c;
831 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
836 void breakjumpsto(code_t*c, code_t*jump)
841 if(c->opcode == OPCODE___BREAK__) {
842 c->opcode = OPCODE_JUMP;
849 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
852 return registry_getanytype();
853 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
854 return registry_getanytype();
857 return registry_getanytype();
859 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
864 return abc_coerce_a(c);
868 // cast an "any" type to a specific type. subject to
869 // runtime exceptions
870 return abc_coerce2(c, &m);
873 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
874 return abc_coerce2(c, &m);
876 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
877 return abc_coerce2(c, &m);
879 /* these are subject to overflow */
880 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
881 return abc_coerce2(c, &m);
883 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
884 return abc_coerce2(c, &m);
887 classinfo_t*supertype = from;
889 if(supertype == to) {
890 // target type is one of from's superclasses
891 return abc_coerce2(c, &m);
894 while(supertype->interfaces[t]) {
895 if(supertype->interfaces[t]==to) {
896 // to type is one of from's interfaces
897 return abc_coerce2(c, &m);
901 supertype = supertype->superclass;
903 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
905 syntaxerror("can't convert type %s to %s", from->name, to->name);
908 code_t*defaultvalue(code_t*c, classinfo_t*type)
910 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
911 c = abc_pushbyte(c, 0);
912 } else if(TYPE_IS_BOOLEAN(type)) {
913 c = abc_pushfalse(c);
920 char is_pushundefined(code_t*c)
922 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
925 void parserassert(int b)
927 if(!b) syntaxerror("internal error: assertion failed");
930 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
934 [prefix code] [read instruction]
938 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
941 if(in && in->opcode == OPCODE_COERCE_A) {
942 in = code_cutlast(in);
945 syntaxerror("internal error");
947 /* chop off read instruction */
951 prefix = r->prev;r->prev = 0;
957 char use_temp_var = readbefore;
959 /* generate the write instruction, and maybe append a dup to the prefix code */
960 code_t* write = abc_nop(0);
961 if(r->opcode == OPCODE_GETPROPERTY) {
962 write->opcode = OPCODE_SETPROPERTY;
963 multiname_t*m = (multiname_t*)r->data[0];
964 write->data[0] = multiname_clone(m);
965 if(m->type != QNAME && m->type != MULTINAME)
966 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
968 prefix = abc_dup(prefix); // we need the object, too
971 } else if(r->opcode == OPCODE_GETSLOT) {
972 write->opcode = OPCODE_SETSLOT;
973 write->data[0] = r->data[0];
975 prefix = abc_dup(prefix); // we need the object, too
978 } else if(r->opcode == OPCODE_GETLOCAL) {
979 write->opcode = OPCODE_SETLOCAL;
980 write->data[0] = r->data[0];
981 } else if(r->opcode == OPCODE_GETLOCAL_0) {
982 write->opcode = OPCODE_SETLOCAL_0;
983 } else if(r->opcode == OPCODE_GETLOCAL_1) {
984 write->opcode = OPCODE_SETLOCAL_1;
985 } else if(r->opcode == OPCODE_GETLOCAL_2) {
986 write->opcode = OPCODE_SETLOCAL_2;
987 } else if(r->opcode == OPCODE_GETLOCAL_3) {
988 write->opcode = OPCODE_SETLOCAL_3;
990 code_dump(r, 0, 0, "", stdout);
991 syntaxerror("illegal lvalue: can't assign a value to this expression");
998 /* with getproperty/getslot, we have to be extra careful not
999 to execute the read code twice, as it might have side-effects
1000 (e.g. if the property is in fact a setter/getter combination)
1002 So read the value, modify it, and write it again,
1003 using prefix only once and making sure (by using a temporary
1004 register) that the return value is what we just wrote */
1005 temp = gettempvar();
1006 c = code_append(c, prefix);
1007 c = code_append(c, r);
1010 c = abc_setlocal(c, temp);
1012 c = code_append(c, middlepart);
1015 c = abc_setlocal(c, temp);
1017 c = code_append(c, write);
1018 c = abc_getlocal(c, temp);
1019 c = abc_kill(c, temp);
1021 /* if we're allowed to execute the read code twice *and*
1022 the middlepart doesn't modify the code, things are easier.
1024 code_t* r2 = code_dup(r);
1025 //c = code_append(c, prefix);
1026 parserassert(!prefix);
1027 c = code_append(c, r);
1028 c = code_append(c, middlepart);
1029 c = code_append(c, write);
1030 c = code_append(c, r2);
1033 /* even smaller version: overwrite the value without reading
1037 c = code_append(c, prefix);
1040 c = code_append(c, middlepart);
1041 c = code_append(c, write);
1042 c = code_append(c, r);
1044 temp = gettempvar();
1046 c = code_append(c, prefix);
1049 c = code_append(c, middlepart);
1051 c = abc_setlocal(c, temp);
1052 c = code_append(c, write);
1053 c = abc_getlocal(c, temp);
1066 /* ------------ code blocks / statements ---------------- */
1070 MAYBECODE: CODE {$$=$1;}
1071 MAYBECODE: {$$=code_new();}
1073 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1074 CODE: CODEPIECE {$$=$1;}
1076 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1077 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1078 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1079 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1080 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1081 CODEPIECE: ';' {$$=code_new();}
1082 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1083 CODEPIECE: VOIDEXPRESSION {$$=$1}
1084 CODEPIECE: FOR {$$=$1}
1085 CODEPIECE: WHILE {$$=$1}
1086 CODEPIECE: BREAK {$$=$1}
1087 CODEPIECE: RETURN {$$=$1}
1088 CODEPIECE: IF {$$=$1}
1089 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1090 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1092 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1093 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1094 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1096 /* ------------ variables --------------------------- */
1098 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1099 | {$$.c=abc_pushundefined(0);
1103 VAR : "const" | "var"
1104 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1106 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1107 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1109 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1111 if(variable_exists($2))
1112 syntaxerror("Variable %s already defined", $2);
1114 if(!is_subtype_of($4.t, $3)) {
1115 syntaxerror("Can't convert %s to %s", $4.t->name,
1119 int index = new_variable($2, $3);
1122 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1124 $$ = converttype($$, $4.t, $3);
1125 $$ = abc_setlocal($$, index);
1127 $$ = defaultvalue(0, $3);
1128 $$ = abc_setlocal($$, index);
1131 /* if this is a typed variable:
1132 push default value for type on stack */
1134 state->initcode = defaultvalue(state->initcode, $3);
1135 state->initcode = abc_setlocal(state->initcode, index);
1138 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1140 $$ = abc_coerce_a($$);
1141 $$ = abc_setlocal($$, index);
1147 /* that's the default for a local register, anyway
1149 state->initcode = abc_pushundefined(state->initcode);
1150 state->initcode = abc_setlocal(state->initcode, index);
1152 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1155 /* ------------ control flow ------------------------- */
1157 MAYBEELSE: %prec prec_none {$$ = code_new();}
1158 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1159 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1161 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1162 $$ = state->initcode;state->initcode=0;
1164 $$ = code_append($$, $4.c);
1165 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1167 $$ = code_append($$, $6);
1169 myjmp = $$ = abc_jump($$, 0);
1171 myif->branch = $$ = abc_label($$);
1173 $$ = code_append($$, $7);
1174 myjmp->branch = $$ = abc_label($$);
1177 $$ = killvars($$);old_state();
1180 FOR_INIT : {$$=code_new();}
1181 FOR_INIT : VARIABLE_DECLARATION
1182 FOR_INIT : VOIDEXPRESSION
1184 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1185 $$ = state->initcode;state->initcode=0;
1187 $$ = code_append($$, $4);
1188 code_t*loopstart = $$ = abc_label($$);
1189 $$ = code_append($$, $6.c);
1190 code_t*myif = $$ = abc_iffalse($$, 0);
1191 $$ = code_append($$, $10);
1192 $$ = code_append($$, $8);
1193 $$ = abc_jump($$, loopstart);
1194 code_t*out = $$ = abc_label($$);
1195 breakjumpsto($$, out);
1198 $$ = killvars($$);old_state();
1201 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1202 $$ = state->initcode;state->initcode=0;
1204 code_t*myjmp = $$ = abc_jump($$, 0);
1205 code_t*loopstart = $$ = abc_label($$);
1206 $$ = code_append($$, $6);
1207 myjmp->branch = $$ = abc_label($$);
1208 $$ = code_append($$, $4.c);
1209 $$ = abc_iftrue($$, loopstart);
1210 code_t*out = $$ = abc_label($$);
1211 breakjumpsto($$, out);
1213 $$ = killvars($$);old_state();
1217 $$ = abc___break__(0);
1220 /* ------------ packages and imports ---------------- */
1222 X_IDENTIFIER: T_IDENTIFIER
1223 | "package" {$$="package";}
1225 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1226 PACKAGE: X_IDENTIFIER {$$=$1;}
1228 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1229 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1231 IMPORT : "import" QNAME {
1234 syntaxerror("Couldn't import class\n");
1235 state_has_imports();
1236 dict_put(state->imports, c->name, c);
1239 IMPORT : "import" PACKAGE '.' '*' {
1242 state_has_imports();
1243 list_append(state->wildcard_imports, i);
1247 /* ------------ classes and interfaces (header) -------------- */
1249 MAYBE_MODIFIERS : {$$=0;}
1250 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1251 MODIFIER_LIST : MODIFIER {$$=$1;}
1252 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1254 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1255 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1256 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1257 | KW_STATIC {$$=FLAG_STATIC;}
1258 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1259 | KW_FINAL {$$=FLAG_FINAL;}
1260 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1261 | KW_NATIVE {$$=FLAG_NATIVE;}
1262 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1264 EXTENDS : {$$=registry_getobjectclass();}
1265 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1267 EXTENDS_LIST : {$$=list_new();}
1268 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1270 IMPLEMENTS_LIST : {$$=list_new();}
1271 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1273 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1274 EXTENDS IMPLEMENTS_LIST
1275 '{' {startclass($1,$3,$4,$5, 0);}
1276 MAYBE_DECLARATION_LIST
1279 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1281 '{' {startclass($1,$3,0,$4,1);}
1282 MAYBE_IDECLARATION_LIST
1285 /* ------------ classes and interfaces (body) -------------- */
1287 MAYBE_DECLARATION_LIST :
1288 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1289 DECLARATION_LIST : DECLARATION
1290 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1292 DECLARATION : SLOT_DECLARATION
1293 DECLARATION : FUNCTION_DECLARATION
1295 MAYBE_IDECLARATION_LIST :
1296 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1297 IDECLARATION_LIST : IDECLARATION
1298 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1300 IDECLARATION : "var" T_IDENTIFIER {
1301 syntaxerror("variable declarations not allowed in interfaces");
1303 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1305 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1306 syntaxerror("invalid method modifiers: interface methods always need to be public");
1308 startfunction(0,$1,$3,$4,&$6,$8);
1312 /* ------------ classes and interfaces (body, slots ) ------- */
1314 VARCONST: "var" | "const"
1316 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1318 memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
1320 info->flags = flags;
1323 namespace_t mname_ns = {flags2access(flags), ""};
1324 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1326 if(!(flags&FLAG_STATIC)) {
1329 t=abc_class_slot(state->cls, &mname, &m);
1331 t=abc_class_slot(state->cls, &mname, 0);
1333 info->slot = t->slot_id;
1337 t=abc_class_staticslot(state->cls, &mname, &m);
1339 t=abc_class_staticslot(state->cls, &mname, 0);
1341 info->slot = t->slot_id;
1343 if($5.c && !is_pushundefined($5.c)) {
1345 c = abc_getlocal_0(c);
1346 c = code_append(c, $5.c);
1347 c = converttype(c, $5.t, $4);
1348 c = abc_setslot(c, t->slot_id);
1349 if(!(flags&FLAG_STATIC))
1350 state->cls_init = code_append(state->cls_init, c);
1352 state->cls_static_init = code_append(state->cls_static_init, c);
1355 t->kind= TRAIT_CONST;
1359 /* ------------ constants -------------------------------------- */
1361 MAYBESTATICCONSTANT: {$$=0;}
1362 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1364 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1365 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1366 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1367 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1368 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1369 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1370 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1371 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1372 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1374 /* ------------ classes and interfaces (body, functions) ------- */
1376 // non-vararg version
1378 memset(&$$,0,sizeof($$));
1380 MAYBE_PARAM_LIST: PARAM_LIST {
1385 MAYBE_PARAM_LIST: "..." PARAM {
1386 memset(&$$,0,sizeof($$));
1388 list_append($$.list, $2);
1390 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1393 list_append($$.list, $4);
1397 PARAM_LIST: PARAM_LIST ',' PARAM {
1399 list_append($$.list, $3);
1402 memset(&$$,0,sizeof($$));
1403 list_append($$.list, $1);
1406 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1407 $$ = malloc(sizeof(param_t));
1412 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1413 $$ = malloc(sizeof(param_t));
1415 $$->type = TYPE_ANY;
1418 GETSET : "get" {$$=$1;}
1422 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1423 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1425 if(!state->m) syntaxerror("internal error: undefined function");
1429 /* ------------- package + class ids --------------- */
1431 CLASS: T_IDENTIFIER {
1433 /* try current package */
1434 $$ = registry_findclass(state->package, $1);
1436 /* try explicit imports */
1437 dictentry_t* e = dict_get_slot(state->imports, $1);
1441 if(!strcmp(e->key, $1)) {
1442 $$ = (classinfo_t*)e->data;
1447 /* try package.* imports */
1448 import_list_t*l = state->wildcard_imports;
1452 //printf("does package %s contain a class %s?\n", l->import->package, $1);
1453 $$ = registry_findclass(l->import->package, $1);
1457 /* try global package */
1459 $$ = registry_findclass("", $1);
1462 if(!$$) syntaxerror("Could not find class %s\n", $1);
1465 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1466 $$ = registry_findclass($1, $3);
1467 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1470 QNAME: PACKAGEANDCLASS
1473 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1474 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1476 TYPE : QNAME {$$=$1;}
1477 | '*' {$$=registry_getanytype();}
1478 | "String" {$$=registry_getstringclass();}
1479 | "int" {$$=registry_getintclass();}
1480 | "uint" {$$=registry_getuintclass();}
1481 | "Boolean" {$$=registry_getbooleanclass();}
1482 | "Number" {$$=registry_getnumberclass();}
1484 MAYBETYPE: ':' TYPE {$$=$2;}
1487 /* ----------function calls, constructor calls ------ */
1489 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1490 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1492 MAYBE_EXPRESSION_LIST : {$$=0;}
1493 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1494 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1495 typedcode_t*t = malloc(sizeof(typedcode_t));
1497 list_append($$, t);}
1498 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1499 typedcode_t*t = malloc(sizeof(typedcode_t));
1501 list_append($$, t);}
1503 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1507 /* TODO: why do we have to *find* our own classes? */
1508 $$.c = abc_findpropstrict2($$.c, &m);
1510 typedcode_list_t*l = $3;
1513 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1517 $$.c = abc_constructprop2($$.c, &m, len);
1521 /* TODO: use abc_call (for calling local variables),
1522 abc_callstatic (for calling own methods)
1525 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1526 typedcode_list_t*l = $3;
1528 code_t*paramcode = 0;
1530 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1536 if($$.c->opcode == OPCODE_COERCE_A) {
1537 $$.c = code_cutlast($$.c);
1541 multiname_t*name = 0;
1542 if($$.c->opcode == OPCODE_GETPROPERTY) {
1543 name = multiname_clone($$.c->data[0]);
1544 $$.c = code_cutlast($$.c);
1545 $$.c = code_append($$.c, paramcode);
1546 $$.c = abc_callproperty2($$.c, name, len);
1547 } else if($$.c->opcode == OPCODE_GETSLOT) {
1548 int slot = (int)(ptroff_t)$$.c->data[0];
1549 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1550 if(t->kind!=TRAIT_METHOD) {
1551 //flash allows to assign closures to members.
1552 //syntaxerror("not a function");
1555 $$.c = code_cutlast($$.c);
1556 $$.c = code_append($$.c, paramcode);
1557 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1558 $$.c = abc_callproperty2($$.c, name, len);
1560 $$.c = abc_getlocal_0($$.c);
1561 $$.c = code_append($$.c, paramcode);
1562 $$.c = abc_call($$.c, len);
1567 if(TYPE_IS_FUNCTION($1.t) &&
1568 (f = registry_findmember($1.t, "call"))) {
1569 $$.t = f->return_type;
1571 $$.c = abc_coerce_a($$.c);
1576 RETURN: "return" %prec prec_none {
1577 $$ = abc_returnvoid(0);
1579 RETURN: "return" EXPRESSION {
1581 $$ = abc_returnvalue($$);
1583 // ----------------------- expression types -------------------------------------
1585 NONCOMMAEXPRESSION : E %prec prec_belowminus {$$=$1;}
1586 EXPRESSION : E %prec prec_belowminus {$$ = $1;}
1587 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1589 $$.c = cut_last_push($$.c);
1590 $$.c = code_append($$.c,$3.c);
1593 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1595 // ----------------------- expression evaluation -------------------------------------
1598 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1600 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1604 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1605 //MULTINAME(m, registry_getintclass());
1606 //$$.c = abc_coerce2($$.c, &m); // FIXME
1609 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1612 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1615 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1618 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1621 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1624 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1625 $$.t = TYPE_BOOLEAN;
1627 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1628 $$.t = TYPE_BOOLEAN;
1630 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1635 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1636 $$.t = TYPE_BOOLEAN;
1638 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1639 $$.t = TYPE_BOOLEAN;
1641 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1642 $$.t = TYPE_BOOLEAN;
1644 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1645 $$.t = TYPE_BOOLEAN;
1647 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1648 $$.t = TYPE_BOOLEAN;
1650 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1651 $$.t = TYPE_BOOLEAN;
1653 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1654 $$.t = TYPE_BOOLEAN;
1657 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1659 $$.c = converttype($$.c, $1.t, $$.t);
1660 $$.c = abc_dup($$.c);
1661 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1662 $$.c = cut_last_push($$.c);
1663 $$.c = code_append($$.c,$3.c);
1664 $$.c = converttype($$.c, $3.t, $$.t);
1665 code_t*label = $$.c = abc_label($$.c);
1666 jmp->branch = label;
1669 $$.t = join_types($1.t, $3.t, 'A');
1670 /*printf("%08x:\n",$1.t);
1671 code_dump($1.c, 0, 0, "", stdout);
1672 printf("%08x:\n",$3.t);
1673 code_dump($3.c, 0, 0, "", stdout);
1674 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1676 $$.c = converttype($$.c, $1.t, $$.t);
1677 $$.c = abc_dup($$.c);
1678 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1679 $$.c = cut_last_push($$.c);
1680 $$.c = code_append($$.c,$3.c);
1681 $$.c = converttype($$.c, $3.t, $$.t);
1682 code_t*label = $$.c = abc_label($$.c);
1683 jmp->branch = label;
1686 E : '!' E {$$.c=$2.c;
1687 $$.c = abc_not($$.c);
1688 $$.t = TYPE_BOOLEAN;
1693 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1694 $$.t = join_types($1.t, $3.t, '+');
1696 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1697 $$.t = join_types($1.t, $3.t, '%');
1699 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1700 $$.t = join_types($1.t, $3.t, '*');
1705 E : '(' E ')' {$$=$2;}
1710 $$.c = code_append($$.c, $3.c);
1712 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1713 $$.c = abc_getproperty2($$.c, &m);
1718 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1719 c=abc_multiply_i(c);
1723 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1724 $$.c = toreadwrite($1.c, c, 0, 0);
1728 code_t*c = abc_modulo($3.c);
1729 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1730 $$.c = toreadwrite($1.c, c, 0, 0);
1734 code_t*c = abc_lshift($3.c);
1735 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1736 $$.c = toreadwrite($1.c, c, 0, 0);
1740 code_t*c = abc_rshift($3.c);
1741 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1742 $$.c = toreadwrite($1.c, c, 0, 0);
1746 code_t*c = abc_urshift($3.c);
1747 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1748 $$.c = toreadwrite($1.c, c, 0, 0);
1752 code_t*c = abc_divide($3.c);
1753 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1754 $$.c = toreadwrite($1.c, c, 0, 0);
1759 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1764 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1766 $$.c = toreadwrite($1.c, c, 0, 0);
1769 E : E "-=" E { code_t*c = $3.c;
1770 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1771 c=abc_subtract_i(c);
1775 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1777 $$.c = toreadwrite($1.c, c, 0, 0);
1780 E : E '=' E { code_t*c = 0;
1781 c = code_append(c, $3.c);
1782 c = converttype(c, $3.t, $1.t);
1783 $$.c = toreadwrite($1.c, c, 1, 0);
1787 // TODO: use inclocal where appropriate
1788 E : E "++" { code_t*c = 0;
1789 classinfo_t*type = $1.t;
1790 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1791 c=abc_increment_i(c);
1797 c=converttype(c, type, $1.t);
1798 $$.c = toreadwrite($1.c, c, 0, 1);
1801 E : E "--" { code_t*c = 0;
1802 classinfo_t*type = $1.t;
1803 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1804 c=abc_decrement_i(c);
1810 c=converttype(c, type, $1.t);
1811 $$.c = toreadwrite($1.c, c, 0, 1);
1815 E : "++" E { code_t*c = 0;
1816 classinfo_t*type = $2.t;
1817 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1818 c=abc_increment_i(c);
1824 c=converttype(c, type, $2.t);
1825 $$.c = toreadwrite($2.c, c, 0, 0);
1829 E : "--" E { code_t*c = 0;
1830 classinfo_t*type = $2.t;
1831 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1832 c=abc_decrement_i(c);
1838 c=converttype(c, type, $2.t);
1839 $$.c = toreadwrite($2.c, c, 0, 0);
1843 E : E '.' T_IDENTIFIER
1846 memberinfo_t*f = registry_findmember($$.t, $3);
1849 $$.c = abc_getslot($$.c, f->slot);
1852 namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
1853 multiname_t m = {QNAME, &ns, 0, $3};
1854 $$.c = abc_getproperty2($$.c, &m);
1856 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1857 $$.c = abc_getproperty2($$.c, &m);
1860 /* determine type */
1862 if(f->kind == MEMBER_METHOD) {
1863 $$.t = TYPE_FUNCTION(f);
1868 $$.c = abc_coerce_a($$.c);
1869 $$.t = registry_getanytype();
1872 /* when resolving a property on an unknown type, we do know the
1873 name of the property (and don't seem to need the package), but
1874 we do need to make avm2 try out all access modes */
1875 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1876 $$.c = abc_getproperty2($$.c, &m);
1877 $$.c = abc_coerce_a($$.c);
1878 $$.t = registry_getanytype();
1882 VAR_READ : T_IDENTIFIER {
1887 if((i = find_variable($1, &$$.t)) >= 0) {
1888 // $1 is a local variable
1889 $$.c = abc_getlocal($$.c, i);
1890 } else if(f = registry_findmember(state->clsinfo, $1)) {
1891 // $1 is a function in this class
1892 int var_is_static = (f->flags&FLAG_STATIC);
1893 int i_am_static = (state->minfo?(state->minfo->flags&FLAG_STATIC):FLAG_STATIC);
1894 if(var_is_static != i_am_static) {
1895 /* there doesn't seem to be any "static" way to access
1896 static properties of a class */
1897 state->late_binding = 1;
1899 namespace_t ns = {flags2access(f->flags), ""};
1900 multiname_t m = {QNAME, &ns, 0, $1};
1901 $$.c = abc_findpropstrict2($$.c, &m);
1902 $$.c = abc_getproperty2($$.c, &m);
1905 $$.c = abc_getlocal_0($$.c);
1906 $$.c = abc_getslot($$.c, f->slot);
1908 namespace_t ns = {flags2access(f->flags), ""};
1909 multiname_t m = {QNAME, &ns, 0, $1};
1910 $$.c = abc_getlocal_0($$.c);
1911 $$.c = abc_getproperty2($$.c, &m);
1914 if(f->kind == MEMBER_METHOD) {
1915 $$.t = TYPE_FUNCTION(f);
1920 // let the avm2 resolve $1
1921 if(strcmp($1,"trace"))
1922 warning("Couldn't resolve %s, doing late binding", $1);
1923 state->late_binding = 1;
1925 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
1928 $$.c = abc_findpropstrict2($$.c, &m);
1929 $$.c = abc_getproperty2($$.c, &m);
1934 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1935 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1936 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1938 // ----------------- namespaces -------------------------------------------------
1940 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
1941 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
1942 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
1944 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER