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_DELETE "delete"
107 %token<token> KW_IF "if"
108 %token<token> KW_ELSE "else"
109 %token<token> KW_BREAK "break"
110 %token<token> KW_IS "is"
111 %token<token> KW_AS "as"
113 %token<token> T_EQEQ "=="
114 %token<token> T_EQEQEQ "==="
115 %token<token> T_NE "!="
116 %token<token> T_LE "<="
117 %token<token> T_GE ">="
118 %token<token> T_DIVBY "/="
119 %token<token> T_MODBY "%="
120 %token<token> T_MULBY "*="
121 %token<token> T_PLUSBY "+="
122 %token<token> T_MINUSBY "-="
123 %token<token> T_SHRBY ">>="
124 %token<token> T_SHLBY "<<="
125 %token<token> T_USHRBY ">>>="
126 %token<token> T_OROR "||"
127 %token<token> T_ANDAND "&&"
128 %token<token> T_COLONCOLON "::"
129 %token<token> T_MINUSMINUS "--"
130 %token<token> T_PLUSPLUS "++"
131 %token<token> T_DOTDOT ".."
132 %token<token> T_DOTDOTDOT "..."
133 %token<token> T_SHL "<<"
134 %token<token> T_USHR ">>>"
135 %token<token> T_SHR ">>"
137 %type <id> X_IDENTIFIER PACKAGE
138 %type <token> VARCONST
140 %type <code> CODEPIECE
141 %type <code> CODEBLOCK MAYBECODE
142 %type <token> PACKAGE_DECLARATION
143 %type <token> FUNCTION_DECLARATION
144 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
145 %type <token> CLASS_DECLARATION
146 %type <token> NAMESPACE_DECLARATION
147 %type <token> INTERFACE_DECLARATION
148 %type <code> VOIDEXPRESSION
149 %type <value> EXPRESSION NONCOMMAEXPRESSION
150 %type <value> MAYBEEXPRESSION
151 %type <value> E DELETE
152 %type <value> CONSTANT
153 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
154 %type <token> USE_NAMESPACE
155 %type <code> FOR_INIT
157 %type <classinfo> MAYBETYPE
160 %type <params> PARAM_LIST
161 %type <params> MAYBE_PARAM_LIST
162 %type <flags> MAYBE_MODIFIERS
163 %type <flags> MODIFIER_LIST
164 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
165 %type <classinfo_list> IMPLEMENTS_LIST
166 %type <classinfo> EXTENDS
167 %type <classinfo_list> EXTENDS_LIST
168 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
169 %type <classinfo_list> QNAME_LIST
170 %type <classinfo> TYPE
172 //%type <token> VARIABLE
173 %type <value> VAR_READ
175 //%type <token> T_IDENTIFIER
176 %type <token> MODIFIER
177 %type <value> FUNCTIONCALL
178 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
180 // precedence: from low to high
184 %left below_semicolon
187 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
194 %nonassoc "==" "!=" "===" "!=="
195 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
196 %left "<<" ">>" ">>>"
200 %left plusplus_prefix minusminus_prefix '~' '!' "delete" "typeof" //FIXME: *unary* + - should be here, too
203 %left '[' ']' '{' "new" '.' ".." "::"
204 %nonassoc T_IDENTIFIER
209 // needed for "return" precedence:
210 %nonassoc T_STRING T_REGEXP
211 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
212 %nonassoc "false" "true" "null"
217 static int yyerror(char*s)
219 syntaxerror("%s", s);
221 static char* concat3str(const char* t1, const char* t2, const char* t3)
226 char*text = malloc(l1+l2+l3+1);
227 memcpy(text , t1, l1);
228 memcpy(text+l1, t2, l2);
229 memcpy(text+l1+l2, t3, l3);
234 typedef struct _import {
238 DECLARE_LIST(import);
240 typedef struct _state {
248 /* code that needs to be executed at the start of
249 a method (like initializing local registers) */
252 import_list_t*wildcard_imports;
254 char has_own_imports;
260 code_t*cls_static_init;
270 typedef struct _global {
274 static global_t*global = 0;
275 static state_t* state = 0;
279 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
281 /* warning: list length of namespace set is undefined */
282 #define MULTINAME_LATE(m, access, package) \
283 namespace_t m##_ns = {access, package}; \
284 namespace_set_t m##_nsset; \
285 namespace_list_t m##_l;m##_l.next = 0; \
286 m##_nsset.namespaces = &m##_l; \
287 m##_nsset = m##_nsset; \
288 m##_l.namespace = &m##_ns; \
289 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
291 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
292 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
293 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
294 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
295 static namespace_list_t nl4 = {&ns4,0};
296 static namespace_list_t nl3 = {&ns3,&nl4};
297 static namespace_list_t nl2 = {&ns2,&nl3};
298 static namespace_list_t nl1 = {&ns1,&nl2};
299 static namespace_set_t nopackage_namespace_set = {&nl1};
301 static state_list_t*state_stack=0;
303 static void init_globals()
305 global = rfx_calloc(sizeof(global_t));
308 static void new_state()
311 NEW(state_list_t, sl);
313 state_t*oldstate = state;
315 memcpy(s, state, sizeof(state_t)); //shallow copy
316 sl->next = state_stack;
319 s->imports = dict_new();
324 state->vars = dict_new();
326 state->has_own_imports = 0;
328 static void state_has_imports()
330 state->wildcard_imports = list_clone(state->wildcard_imports);
331 state->imports = dict_clone(state->imports);
332 state->has_own_imports = 1;
335 static void old_state()
337 if(!state_stack || !state_stack->next)
338 syntaxerror("invalid nesting");
339 state_t*oldstate = state;
340 state_list_t*old = state_stack;
341 state_stack = state_stack->next;
343 state = state_stack->state;
344 /*if(state->initcode) {
345 printf("residual initcode\n");
346 code_dump(state->initcode, 0, 0, "", stdout);
348 if(oldstate->has_own_imports) {
349 list_free(oldstate->wildcard_imports);
350 dict_destroy(oldstate->imports);oldstate->imports=0;
352 state->initcode = code_append(state->initcode, oldstate->initcode);
354 void initialize_state()
359 state->file = abc_file_new();
360 state->file->flags &= ~ABCFILE_LAZY;
362 state->init = abc_initscript(state->file, 0);
363 code_t*c = state->init->method->body->code;
365 c = abc_getlocal_0(c);
366 c = abc_pushscope(c);
368 /* findpropstrict doesn't just return a scope object- it
369 also makes it "active" somehow. Push local_0 on the
370 scope stack and read it back with findpropstrict, it'll
371 contain properties like "trace". Trying to find the same
372 property on a "vanilla" local_0 yields only a "undefined" */
373 //c = abc_findpropstrict(c, "[package]::trace");
375 /*c = abc_getlocal_0(c);
376 c = abc_findpropstrict(c, "[package]::trace");
378 c = abc_setlocal_1(c);
380 c = abc_pushbyte(c, 0);
381 c = abc_setlocal_2(c);
383 code_t*xx = c = abc_label(c);
384 c = abc_findpropstrict(c, "[package]::trace");
385 c = abc_pushstring(c, "prop:");
386 c = abc_hasnext2(c, 1, 2);
388 c = abc_setlocal_3(c);
389 c = abc_callpropvoid(c, "[package]::trace", 2);
390 c = abc_getlocal_3(c);
392 c = abc_iftrue(c,xx);*/
394 c = abc_findpropstrict(c, "[package]::trace");
395 c = abc_pushstring(c, "[entering global init function]");
396 c = abc_callpropvoid(c, "[package]::trace", 1);
398 state->init->method->body->code = c;
400 void* finalize_state()
402 if(state->level!=1) {
403 syntaxerror("unexpected end of file");
405 abc_method_body_t*m = state->init->method->body;
408 __ findpropstrict(m, "[package]::trace");
409 __ pushstring(m, "[leaving global init function]");
410 __ callpropvoid(m, "[package]::trace", 1);
416 static void startpackage(char*name)
419 syntaxerror("Packages can not be nested.");
422 /*printf("entering package \"%s\"\n", name);*/
423 state->package = name;
425 static void endpackage()
427 /*printf("leaving package \"%s\"\n", state->package);*/
432 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
435 syntaxerror("inner classes now allowed");
440 classinfo_list_t*mlist=0;
441 /*printf("entering class %s\n", name);
442 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
444 printf(" extends: %s.%s\n", extends->package, extends->name);
445 printf(" implements (%d): ", list_length(implements));
446 for(mlist=implements;mlist;mlist=mlist->next) {
447 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
452 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
453 syntaxerror("invalid modifier(s)");
455 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
456 syntaxerror("public and internal not supported at the same time.");
458 /* create the class name, together with the proper attributes */
462 if(!(flags&FLAG_PUBLIC) && !state->package) {
463 access = ACCESS_PRIVATE; package = current_filename;
464 } else if(!(flags&FLAG_PUBLIC) && state->package) {
465 access = ACCESS_PACKAGEINTERNAL; package = state->package;
466 } else if(state->package) {
467 access = ACCESS_PACKAGE; package = state->package;
469 syntaxerror("public classes only allowed inside a package");
472 if(registry_findclass(package, classname)) {
473 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
476 /* build info struct */
477 int num_interfaces = (list_length(implements));
478 state->clsinfo = classinfo_register(access, package, classname, num_interfaces);
479 state->clsinfo->superclass = extends;
481 classinfo_list_t*l = implements;
482 for(l=implements;l;l=l->next) {
483 state->clsinfo->interfaces[pos++] = l->classinfo;
486 MULTINAME(classname2,state->clsinfo);
488 multiname_t*extends2 = sig2mname(extends);
491 state->cls_init = abc_getlocal_0(state->cls_init);
492 state->cls_init = abc_constructsuper(state->cls_init, 0);
495 state->cls = abc_class_new(state->file, &classname2, extends2);
496 if(flags&FLAG_FINAL) abc_class_final(state->cls);
497 if(flags&FLAG_DYNAMIC) abc_class_sealed(state->cls);
498 if(interface) abc_class_interface(state->cls);
500 for(mlist=implements;mlist;mlist=mlist->next) {
501 MULTINAME(m, mlist->classinfo);
502 abc_class_add_interface(state->cls, &m);
505 /* now write the construction code for this class */
506 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
508 abc_method_body_t*m = state->init->method->body;
509 __ getglobalscope(m);
510 classinfo_t*s = extends;
515 //TODO: take a look at the current scope stack, maybe
516 // we can re-use something
521 multiname_t*s2 = sig2mname(s);
523 multiname_destroy(s2);
525 __ pushscope(m); count++;
526 m->code = m->code->prev->prev; // invert
528 /* continue appending after last op end */
529 while(m->code && m->code->next) m->code = m->code->next;
531 /* TODO: if this is one of *our* classes, we can also
532 do a getglobalscope/getslot <nr> (which references
533 the init function's slots) */
535 __ getlex2(m, extends2);
537 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
538 stack is not the superclass */
539 __ pushscope(m);count++;
542 /* notice: we get a verify error #1107 if the top element on the scope
543 stack is not the global object */
545 __ pushscope(m);count++;
547 __ newclass(m,state->cls);
551 __ setslot(m, slotindex);
553 /* flash.display.MovieClip handling */
554 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
555 if(state->package && state->package[0]) {
556 globalclass = concat3str(state->package, ".", classname);
558 globalclass = strdup(classname);
561 multiname_destroy(extends2);
564 static void endclass()
566 if(state->cls_init) {
567 if(!state->cls->constructor) {
568 abc_method_t*m = abc_class_constructor(state->cls, 0);
569 m->body->code = code_append(m->body->code, state->cls_init);
570 m->body->code = abc_returnvoid(m->body->code);
572 code_t*c = state->cls->constructor->body->code;
573 c = code_append(state->cls_init, c);
574 state->cls->constructor->body->code = c;
578 if(state->cls_static_init) {
579 if(!state->cls->static_constructor) {
580 abc_method_t*m = abc_class_staticconstructor(state->cls, 0);
581 m->body->code = code_append(m->body->code, state->cls_static_init);
582 m->body->code = abc_returnvoid(m->body->code);
584 state->cls->static_constructor->body->code =
585 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
592 typedef struct _variable {
597 static int find_variable(char*name, classinfo_t**m)
599 state_list_t* s = state_stack;
601 variable_t*v = dict_lookup(s->state->vars, name);
612 static int find_variable_safe(char*name, classinfo_t**m)
614 int i = find_variable(name, m);
616 syntaxerror("undefined variable: %s", name);
619 static char variable_exists(char*name)
621 return dict_lookup(state->vars, name)!=0;
623 static int new_variable(char*name, classinfo_t*type)
626 v->index = global->variable_count;
628 dict_put(state->vars, name, v);
629 return global->variable_count++;
631 #define TEMPVARNAME "__as3_temp__"
632 static int gettempvar()
634 int i = find_variable(TEMPVARNAME, 0);
636 return new_variable(TEMPVARNAME, 0);
642 code_t* killvars(code_t*c)
645 for(t=0;t<state->vars->hashsize;t++) {
646 dictentry_t*e =state->vars->slots[t];
648 variable_t*v = (variable_t*)e->data;
649 //do this always, otherwise register types don't match
650 //in the verifier when doing nested loops
651 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
652 c = abc_kill(c, v->index);
660 static void check_constant_against_type(classinfo_t*t, constant_t*c)
662 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
663 if(TYPE_IS_NUMBER(t)) {
664 xassert(c->type == CONSTANT_FLOAT
665 || c->type == CONSTANT_INT
666 || c->type == CONSTANT_UINT);
667 } else if(TYPE_IS_UINT(t)) {
668 xassert(c->type == CONSTANT_UINT ||
669 (c->type == CONSTANT_INT && c->i>0));
670 } else if(TYPE_IS_INT(t)) {
671 xassert(c->type == CONSTANT_INT);
672 } else if(TYPE_IS_BOOLEAN(t)) {
673 xassert(c->type == CONSTANT_TRUE
674 || c->type == CONSTANT_FALSE);
678 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
680 memberinfo_t*minfo = 0;
681 if(getset != KW_GET && getset != KW_SET) {
682 if(registry_findmember(state->clsinfo, name)) {
683 syntaxerror("class already contains a member/method called '%s'", name);
685 minfo = memberinfo_register(state->clsinfo, name, MEMBER_METHOD);
686 minfo->return_type = return_type;
687 // getslot on a member slot only returns "undefined", so no need
688 // to actually store these
689 //state->minfo->slot = state->m->method->trait->slot_id;
691 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
695 else if(params->list)
696 type = params->list->param->type;
697 if((minfo=registry_findmember(state->clsinfo, name))) {
698 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
699 syntaxerror("class already contains a member or method called '%s'", name);
701 syntaxerror("getter/setter for '%s' already defined", name);
702 /* make a setter or getter into a getset */
707 if(type && minfo->type != type)
708 syntaxerror("different type in getter and setter");
710 minfo = memberinfo_register(state->clsinfo, name, gs);
713 /* can't assign a slot as getter and setter might have different slots */
714 //minfo->slot = slot;
716 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
717 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
718 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
719 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
720 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
724 static int flags2access(int flags)
727 if(flags&FLAG_PUBLIC) {
728 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
729 access = ACCESS_PACKAGE;
730 } else if(flags&FLAG_PRIVATE) {
731 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
732 access = ACCESS_PRIVATE;
733 } else if(flags&FLAG_PROTECTED) {
734 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
735 access = ACCESS_PROTECTED;
737 access = ACCESS_PACKAGEINTERNAL;
742 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
743 params_t*params, classinfo_t*return_type)
747 global->variable_count = 0;
748 state->function = name;
751 syntaxerror("not able to start another method scope");
754 namespace_t mname_ns = {flags2access(flags), ""};
755 multiname_t mname = {QNAME, &mname_ns, 0, name};
757 multiname_t*type2 = sig2mname(return_type);
759 if(!strcmp(state->clsinfo->name,name)) {
760 state->m = abc_class_constructor(state->cls, type2);
761 name = "__as3_constructor__";
763 if(flags&FLAG_STATIC)
764 state->m = abc_class_staticmethod(state->cls, type2, &mname);
766 state->m = abc_class_method(state->cls, type2, &mname);
767 slot = state->m->trait->slot_id;
769 state->minfo = registerfunction(getset, flags, name, params, return_type, slot);
771 if(getset == KW_GET) state->m->trait->kind = TRAIT_GETTER;
772 if(getset == KW_SET) state->m->trait->kind = TRAIT_SETTER;
773 if(params->varargs) state->m->flags |= METHOD_NEED_REST;
777 for(p=params->list;p;p=p->next) {
778 if(params->varargs && !p->next) {
779 break; //varargs: omit last parameter in function signature
781 multiname_t*m = sig2mname(p->param->type);
782 list_append(state->m->parameters, m);
783 if(p->param->value) {
784 check_constant_against_type(p->param->type, p->param->value);
785 opt=1;list_append(state->m->optional_parameters, p->param->value);
787 syntaxerror("non-optional parameter not allowed after optional parameters");
791 /* state->vars is initialized by state_new */
792 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->clsinfo)!=0) syntaxerror("Internal error");
794 for(p=params->list;p;p=p->next) {
795 new_variable(p->param->name, p->param->type);
798 static void endfunction(code_t*body)
801 if(!(state->cls->flags & CLASS_INTERFACE)) {
803 if(state->late_binding) {
804 c = abc_getlocal_0(c);
805 c = abc_pushscope(c);
807 c = code_append(c, state->initcode);
808 c = code_append(c, body);
810 /* append return if necessary */
811 if(!c || c->opcode != OPCODE_RETURNVOID &&
812 c->opcode != OPCODE_RETURNVALUE) {
813 c = abc_returnvoid(c);
815 if(state->m->body->code) syntaxerror("internal error");
816 state->m->body->code = c;
823 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
828 void breakjumpsto(code_t*c, code_t*jump)
833 if(c->opcode == OPCODE___BREAK__) {
834 c->opcode = OPCODE_JUMP;
841 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
844 return registry_getanytype();
845 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
846 return registry_getanytype();
849 return registry_getanytype();
851 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
856 return abc_coerce_a(c);
860 // cast an "any" type to a specific type. subject to
861 // runtime exceptions
862 return abc_coerce2(c, &m);
865 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
866 return abc_coerce2(c, &m);
868 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
869 return abc_coerce2(c, &m);
871 /* these are subject to overflow */
872 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
873 return abc_coerce2(c, &m);
875 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
876 return abc_coerce2(c, &m);
879 classinfo_t*supertype = from;
881 if(supertype == to) {
882 // target type is one of from's superclasses
883 return abc_coerce2(c, &m);
886 while(supertype->interfaces[t]) {
887 if(supertype->interfaces[t]==to) {
888 // to type is one of from's interfaces
889 return abc_coerce2(c, &m);
893 supertype = supertype->superclass;
895 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
897 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
899 syntaxerror("can't convert type %s to %s", from->name, to->name);
902 code_t*defaultvalue(code_t*c, classinfo_t*type)
904 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
905 c = abc_pushbyte(c, 0);
906 } else if(TYPE_IS_BOOLEAN(type)) {
907 c = abc_pushfalse(c);
914 char is_pushundefined(code_t*c)
916 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
919 void parserassert(int b)
921 if(!b) syntaxerror("internal error: assertion failed");
924 static classinfo_t* find_class(char*name)
928 c = registry_findclass(state->package, name);
930 /* try explicit imports */
931 dictentry_t* e = dict_get_slot(state->imports, name);
935 if(!strcmp(e->key, name)) {
936 c = (classinfo_t*)e->data;
941 /* try package.* imports */
942 import_list_t*l = state->wildcard_imports;
946 //printf("does package %s contain a class %s?\n", l->import->package, name);
947 c = registry_findclass(l->import->package, name);
951 /* try global package */
953 c = registry_findclass("", name);
958 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
962 [prefix code] [read instruction]
966 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
969 if(in && in->opcode == OPCODE_COERCE_A) {
970 in = code_cutlast(in);
973 syntaxerror("internal error");
975 /* chop off read instruction */
979 prefix = r->prev;r->prev = 0;
985 char use_temp_var = readbefore;
987 /* generate the write instruction, and maybe append a dup to the prefix code */
988 code_t* write = abc_nop(0);
989 if(r->opcode == OPCODE_GETPROPERTY) {
990 write->opcode = OPCODE_SETPROPERTY;
991 multiname_t*m = (multiname_t*)r->data[0];
992 write->data[0] = multiname_clone(m);
993 if(m->type == QNAME || m->type == MULTINAME) {
995 prefix = abc_dup(prefix); // we need the object, too
998 } else if(m->type == MULTINAMEL) {
1000 /* dupping two values on the stack requires 5 operations and one register-
1001 couldn't adobe just have given us a dup2? */
1002 int temp = gettempvar();
1003 prefix = abc_setlocal(prefix, temp);
1004 prefix = abc_dup(prefix);
1005 prefix = abc_getlocal(prefix, temp);
1006 prefix = abc_swap(prefix);
1007 prefix = abc_getlocal(prefix, temp);
1011 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1013 } else if(r->opcode == OPCODE_GETSLOT) {
1014 write->opcode = OPCODE_SETSLOT;
1015 write->data[0] = r->data[0];
1017 prefix = abc_dup(prefix); // we need the object, too
1020 } else if(r->opcode == OPCODE_GETLOCAL) {
1021 write->opcode = OPCODE_SETLOCAL;
1022 write->data[0] = r->data[0];
1023 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1024 write->opcode = OPCODE_SETLOCAL_0;
1025 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1026 write->opcode = OPCODE_SETLOCAL_1;
1027 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1028 write->opcode = OPCODE_SETLOCAL_2;
1029 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1030 write->opcode = OPCODE_SETLOCAL_3;
1032 code_dump(r, 0, 0, "", stdout);
1033 syntaxerror("illegal lvalue: can't assign a value to this expression");
1040 /* with getproperty/getslot, we have to be extra careful not
1041 to execute the read code twice, as it might have side-effects
1042 (e.g. if the property is in fact a setter/getter combination)
1044 So read the value, modify it, and write it again,
1045 using prefix only once and making sure (by using a temporary
1046 register) that the return value is what we just wrote */
1047 temp = gettempvar();
1048 c = code_append(c, prefix);
1049 c = code_append(c, r);
1052 c = abc_setlocal(c, temp);
1054 c = code_append(c, middlepart);
1057 c = abc_setlocal(c, temp);
1059 c = code_append(c, write);
1060 c = abc_getlocal(c, temp);
1061 c = abc_kill(c, temp);
1063 /* if we're allowed to execute the read code twice *and*
1064 the middlepart doesn't modify the code, things are easier.
1066 code_t* r2 = code_dup(r);
1067 //c = code_append(c, prefix);
1068 parserassert(!prefix);
1069 c = code_append(c, r);
1070 c = code_append(c, middlepart);
1071 c = code_append(c, write);
1072 c = code_append(c, r2);
1075 /* even smaller version: overwrite the value without reading
1079 c = code_append(c, prefix);
1082 c = code_append(c, middlepart);
1083 c = code_append(c, write);
1084 c = code_append(c, r);
1086 temp = gettempvar();
1088 c = code_append(c, prefix);
1091 c = code_append(c, middlepart);
1093 c = abc_setlocal(c, temp);
1094 c = code_append(c, write);
1095 c = abc_getlocal(c, temp);
1102 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1103 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1110 /* ------------ code blocks / statements ---------------- */
1114 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1115 MAYBECODE: {$$=code_new();}
1117 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1118 CODE: CODEPIECE {$$=$1;}
1120 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1121 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1122 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1123 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1124 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1125 CODEPIECE: ';' {$$=code_new();}
1126 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1127 CODEPIECE: VOIDEXPRESSION {$$=$1}
1128 CODEPIECE: FOR {$$=$1}
1129 CODEPIECE: WHILE {$$=$1}
1130 CODEPIECE: BREAK {$$=$1}
1131 CODEPIECE: RETURN {$$=$1}
1132 CODEPIECE: IF {$$=$1}
1133 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1134 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1136 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1137 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1138 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1140 /* ------------ variables --------------------------- */
1142 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1143 | {$$.c=abc_pushundefined(0);
1147 VAR : "const" | "var"
1148 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1150 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1151 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1153 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1155 if(variable_exists($2))
1156 syntaxerror("Variable %s already defined", $2);
1158 if(!is_subtype_of($4.t, $3)) {
1159 syntaxerror("Can't convert %s to %s", $4.t->name,
1163 int index = new_variable($2, $3);
1166 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1168 $$ = converttype($$, $4.t, $3);
1169 $$ = abc_setlocal($$, index);
1171 $$ = defaultvalue(0, $3);
1172 $$ = abc_setlocal($$, index);
1175 /* if this is a typed variable:
1176 push default value for type on stack */
1178 state->initcode = defaultvalue(state->initcode, $3);
1179 state->initcode = abc_setlocal(state->initcode, index);
1182 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1184 $$ = abc_coerce_a($$);
1185 $$ = abc_setlocal($$, index);
1191 /* that's the default for a local register, anyway
1193 state->initcode = abc_pushundefined(state->initcode);
1194 state->initcode = abc_setlocal(state->initcode, index);
1196 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1199 /* ------------ control flow ------------------------- */
1201 MAYBEELSE: %prec below_else {$$ = code_new();}
1202 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1203 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1205 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1206 $$ = state->initcode;state->initcode=0;
1208 $$ = code_append($$, $4.c);
1209 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1211 $$ = code_append($$, $6);
1213 myjmp = $$ = abc_jump($$, 0);
1215 myif->branch = $$ = abc_label($$);
1217 $$ = code_append($$, $7);
1218 myjmp->branch = $$ = abc_label($$);
1221 $$ = killvars($$);old_state();
1224 FOR_INIT : {$$=code_new();}
1225 FOR_INIT : VARIABLE_DECLARATION
1226 FOR_INIT : VOIDEXPRESSION
1228 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1229 $$ = state->initcode;state->initcode=0;
1231 $$ = code_append($$, $4);
1232 code_t*loopstart = $$ = abc_label($$);
1233 $$ = code_append($$, $6.c);
1234 code_t*myif = $$ = abc_iffalse($$, 0);
1235 $$ = code_append($$, $10);
1236 $$ = code_append($$, $8);
1237 $$ = abc_jump($$, loopstart);
1238 code_t*out = $$ = abc_label($$);
1239 breakjumpsto($$, out);
1242 $$ = killvars($$);old_state();
1245 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1246 $$ = state->initcode;state->initcode=0;
1248 code_t*myjmp = $$ = abc_jump($$, 0);
1249 code_t*loopstart = $$ = abc_label($$);
1250 $$ = code_append($$, $6);
1251 myjmp->branch = $$ = abc_label($$);
1252 $$ = code_append($$, $4.c);
1253 $$ = abc_iftrue($$, loopstart);
1254 code_t*out = $$ = abc_label($$);
1255 breakjumpsto($$, out);
1257 $$ = killvars($$);old_state();
1261 $$ = abc___break__(0);
1264 /* ------------ packages and imports ---------------- */
1266 X_IDENTIFIER: T_IDENTIFIER
1267 | "package" {$$="package";}
1269 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1270 PACKAGE: X_IDENTIFIER {$$=$1;}
1272 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1273 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1275 IMPORT : "import" QNAME {
1278 syntaxerror("Couldn't import class\n");
1279 state_has_imports();
1280 dict_put(state->imports, c->name, c);
1283 IMPORT : "import" PACKAGE '.' '*' {
1286 state_has_imports();
1287 list_append(state->wildcard_imports, i);
1291 /* ------------ classes and interfaces (header) -------------- */
1293 MAYBE_MODIFIERS : {$$=0;}
1294 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1295 MODIFIER_LIST : MODIFIER {$$=$1;}
1296 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1298 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1299 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1300 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1301 | KW_STATIC {$$=FLAG_STATIC;}
1302 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1303 | KW_FINAL {$$=FLAG_FINAL;}
1304 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1305 | KW_NATIVE {$$=FLAG_NATIVE;}
1306 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1308 EXTENDS : {$$=registry_getobjectclass();}
1309 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1311 EXTENDS_LIST : {$$=list_new();}
1312 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1314 IMPLEMENTS_LIST : {$$=list_new();}
1315 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1317 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1318 EXTENDS IMPLEMENTS_LIST
1319 '{' {startclass($1,$3,$4,$5, 0);}
1320 MAYBE_DECLARATION_LIST
1323 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1325 '{' {startclass($1,$3,0,$4,1);}
1326 MAYBE_IDECLARATION_LIST
1329 /* ------------ classes and interfaces (body) -------------- */
1331 MAYBE_DECLARATION_LIST :
1332 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1333 DECLARATION_LIST : DECLARATION
1334 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1336 DECLARATION : SLOT_DECLARATION
1337 DECLARATION : FUNCTION_DECLARATION
1339 MAYBE_IDECLARATION_LIST :
1340 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1341 IDECLARATION_LIST : IDECLARATION
1342 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1344 IDECLARATION : "var" T_IDENTIFIER {
1345 syntaxerror("variable declarations not allowed in interfaces");
1347 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1349 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1350 syntaxerror("invalid method modifiers: interface methods always need to be public");
1352 startfunction(0,$1,$3,$4,&$6,$8);
1356 /* ------------ classes and interfaces (body, slots ) ------- */
1358 VARCONST: "var" | "const"
1360 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1362 memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
1364 info->flags = flags;
1367 namespace_t mname_ns = {flags2access(flags), ""};
1368 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1370 if(!(flags&FLAG_STATIC)) {
1373 t=abc_class_slot(state->cls, &mname, &m);
1375 t=abc_class_slot(state->cls, &mname, 0);
1377 info->slot = t->slot_id;
1381 t=abc_class_staticslot(state->cls, &mname, &m);
1383 t=abc_class_staticslot(state->cls, &mname, 0);
1385 info->slot = t->slot_id;
1387 if($5.c && !is_pushundefined($5.c)) {
1389 c = abc_getlocal_0(c);
1390 c = code_append(c, $5.c);
1391 c = converttype(c, $5.t, $4);
1392 c = abc_setslot(c, t->slot_id);
1393 if(!(flags&FLAG_STATIC))
1394 state->cls_init = code_append(state->cls_init, c);
1396 state->cls_static_init = code_append(state->cls_static_init, c);
1399 t->kind= TRAIT_CONST;
1403 /* ------------ constants -------------------------------------- */
1405 MAYBESTATICCONSTANT: {$$=0;}
1406 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1408 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1409 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1410 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1411 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1412 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1413 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1414 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1415 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1416 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1418 /* ------------ classes and interfaces (body, functions) ------- */
1420 // non-vararg version
1422 memset(&$$,0,sizeof($$));
1424 MAYBE_PARAM_LIST: PARAM_LIST {
1429 MAYBE_PARAM_LIST: "..." PARAM {
1430 memset(&$$,0,sizeof($$));
1432 list_append($$.list, $2);
1434 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1437 list_append($$.list, $4);
1441 PARAM_LIST: PARAM_LIST ',' PARAM {
1443 list_append($$.list, $3);
1446 memset(&$$,0,sizeof($$));
1447 list_append($$.list, $1);
1450 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1451 $$ = malloc(sizeof(param_t));
1456 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1457 $$ = malloc(sizeof(param_t));
1459 $$->type = TYPE_ANY;
1462 GETSET : "get" {$$=$1;}
1466 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1467 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1469 if(!state->m) syntaxerror("internal error: undefined function");
1473 /* ------------- package + class ids --------------- */
1475 CLASS: T_IDENTIFIER {
1477 /* try current package */
1478 $$ = find_class($1);
1479 if(!$$) syntaxerror("Could not find class %s\n", $1);
1482 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1483 $$ = registry_findclass($1, $3);
1484 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1487 QNAME: PACKAGEANDCLASS
1490 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1491 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1493 TYPE : QNAME {$$=$1;}
1494 | '*' {$$=registry_getanytype();}
1495 | "String" {$$=registry_getstringclass();}
1496 | "int" {$$=registry_getintclass();}
1497 | "uint" {$$=registry_getuintclass();}
1498 | "Boolean" {$$=registry_getbooleanclass();}
1499 | "Number" {$$=registry_getnumberclass();}
1501 MAYBETYPE: ':' TYPE {$$=$2;}
1504 /* ----------function calls, delete, constructor calls ------ */
1506 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1507 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1509 MAYBE_EXPRESSION_LIST : {$$=0;}
1510 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1511 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1512 typedcode_t*t = malloc(sizeof(typedcode_t));
1514 list_append($$, t);}
1515 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1516 typedcode_t*t = malloc(sizeof(typedcode_t));
1518 list_append($$, t);}
1520 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1525 $$.c = abc_getglobalscope($$.c);
1526 $$.c = abc_getslot($$.c, $2->slot);
1528 $$.c = abc_findpropstrict2($$.c, &m);
1531 typedcode_list_t*l = $3;
1534 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1539 $$.c = abc_construct($$.c, len);
1541 $$.c = abc_constructprop2($$.c, &m, len);
1545 /* TODO: use abc_call (for calling local variables),
1546 abc_callstatic (for calling own methods)
1549 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1550 typedcode_list_t*l = $3;
1552 code_t*paramcode = 0;
1554 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1560 if($$.c->opcode == OPCODE_COERCE_A) {
1561 $$.c = code_cutlast($$.c);
1565 multiname_t*name = 0;
1566 if($$.c->opcode == OPCODE_GETPROPERTY) {
1567 name = multiname_clone($$.c->data[0]);
1568 $$.c = code_cutlast($$.c);
1569 $$.c = code_append($$.c, paramcode);
1570 $$.c = abc_callproperty2($$.c, name, len);
1571 } else if($$.c->opcode == OPCODE_GETSLOT) {
1572 int slot = (int)(ptroff_t)$$.c->data[0];
1573 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1574 if(t->kind!=TRAIT_METHOD) {
1575 //flash allows to assign closures to members.
1576 //syntaxerror("not a function");
1579 $$.c = code_cutlast($$.c);
1580 $$.c = code_append($$.c, paramcode);
1581 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1582 $$.c = abc_callproperty2($$.c, name, len);
1584 $$.c = abc_getlocal_0($$.c);
1585 $$.c = code_append($$.c, paramcode);
1586 $$.c = abc_call($$.c, len);
1591 if(TYPE_IS_FUNCTION($1.t) &&
1592 (f = registry_findmember($1.t, "call"))) {
1593 $$.t = f->return_type;
1595 $$.c = abc_coerce_a($$.c);
1600 DELETE: "delete" E {
1602 if($$.c->opcode == OPCODE_COERCE_A) {
1603 $$.c = code_cutlast($$.c);
1605 multiname_t*name = 0;
1606 if($$.c->opcode == OPCODE_GETPROPERTY) {
1607 $$.c->opcode = OPCODE_DELETEPROPERTY;
1608 } else if($$.c->opcode == OPCODE_GETSLOT) {
1609 int slot = (int)(ptroff_t)$$.c->data[0];
1610 multiname_t*name = abc_class_find_slotid(state->cls,slot)->name;
1611 $$.c = code_cutlast($$.c);
1612 $$.c = abc_deleteproperty2($$.c, name);
1614 $$.c = abc_getlocal_0($$.c);
1615 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1616 $$.c = abc_deleteproperty2($$.c, &m);
1618 $$.t = TYPE_BOOLEAN;
1621 RETURN: "return" %prec prec_none {
1622 $$ = abc_returnvoid(0);
1624 RETURN: "return" EXPRESSION {
1626 $$ = abc_returnvalue($$);
1629 // ----------------------- expression types -------------------------------------
1631 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1632 EXPRESSION : E %prec below_minus {$$ = $1;}
1633 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1635 $$.c = cut_last_push($$.c);
1636 $$.c = code_append($$.c,$3.c);
1639 VOIDEXPRESSION : EXPRESSION %prec below_minus {$$=cut_last_push($1.c);}
1641 // ----------------------- expression evaluation -------------------------------------
1644 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1646 E : DELETE {$$ = $1;}
1647 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1651 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1652 //MULTINAME(m, registry_getintclass());
1653 //$$.c = abc_coerce2($$.c, &m); // FIXME
1656 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1659 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1662 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1665 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1668 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1671 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1672 $$.t = TYPE_BOOLEAN;
1674 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1675 $$.t = TYPE_BOOLEAN;
1677 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1682 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1683 $$.t = TYPE_BOOLEAN;
1685 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1686 $$.t = TYPE_BOOLEAN;
1688 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1689 $$.t = TYPE_BOOLEAN;
1691 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1692 $$.t = TYPE_BOOLEAN;
1694 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1695 $$.t = TYPE_BOOLEAN;
1697 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1698 $$.t = TYPE_BOOLEAN;
1700 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1701 $$.t = TYPE_BOOLEAN;
1704 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1706 $$.c = converttype($$.c, $1.t, $$.t);
1707 $$.c = abc_dup($$.c);
1708 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1709 $$.c = cut_last_push($$.c);
1710 $$.c = code_append($$.c,$3.c);
1711 $$.c = converttype($$.c, $3.t, $$.t);
1712 code_t*label = $$.c = abc_label($$.c);
1713 jmp->branch = label;
1716 $$.t = join_types($1.t, $3.t, 'A');
1717 /*printf("%08x:\n",$1.t);
1718 code_dump($1.c, 0, 0, "", stdout);
1719 printf("%08x:\n",$3.t);
1720 code_dump($3.c, 0, 0, "", stdout);
1721 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1723 $$.c = converttype($$.c, $1.t, $$.t);
1724 $$.c = abc_dup($$.c);
1725 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1726 $$.c = cut_last_push($$.c);
1727 $$.c = code_append($$.c,$3.c);
1728 $$.c = converttype($$.c, $3.t, $$.t);
1729 code_t*label = $$.c = abc_label($$.c);
1730 jmp->branch = label;
1733 E : '!' E {$$.c=$2.c;
1734 $$.c = abc_not($$.c);
1735 $$.t = TYPE_BOOLEAN;
1738 E : '~' E {$$.c=$2.c;
1739 $$.c = abc_bitnot($$.c);
1743 E : E '&' E {$$.c = code_append($1.c,$3.c);
1744 $$.c = abc_bitand($$.c);
1748 E : E '|' E {$$.c = code_append($1.c,$3.c);
1749 $$.c = abc_bitor($$.c);
1753 E : E '-' E {$$.c = code_append($1.c,$3.c);
1754 if(BOTH_INT($1,$3)) {
1755 $$.c = abc_subtract_i($$.c);
1758 $$.c = abc_subtract($$.c);
1762 E : E '/' E {$$.c = code_append($1.c,$3.c);
1763 $$.c = abc_divide($$.c);
1766 E : E '+' E {$$.c = code_append($1.c,$3.c);
1767 $$.c = abc_add($$.c);
1770 E : E '%' E {$$.c = code_append($1.c,$3.c);
1771 $$.c = abc_modulo($$.c);
1774 E : E '*' E {$$.c = code_append($1.c,$3.c);
1775 if(BOTH_INT($1,$3)) {
1776 $$.c = abc_multiply_i($$.c);
1779 $$.c = abc_multiply($$.c);
1786 E : '(' E ')' {$$=$2;}
1790 $$.c=abc_negate_i($$.c);
1793 $$.c=abc_negate($$.c);
1800 $$.c = code_append($$.c, $3.c);
1802 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1803 $$.c = abc_getproperty2($$.c, &m);
1804 $$.t = 0; // array elements have unknown type
1809 if(BOTH_INT($1,$3)) {
1810 c=abc_multiply_i(c);
1814 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1815 $$.c = toreadwrite($1.c, c, 0, 0);
1819 code_t*c = abc_modulo($3.c);
1820 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1821 $$.c = toreadwrite($1.c, c, 0, 0);
1825 code_t*c = abc_lshift($3.c);
1826 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1827 $$.c = toreadwrite($1.c, c, 0, 0);
1831 code_t*c = abc_rshift($3.c);
1832 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1833 $$.c = toreadwrite($1.c, c, 0, 0);
1837 code_t*c = abc_urshift($3.c);
1838 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1839 $$.c = toreadwrite($1.c, c, 0, 0);
1843 code_t*c = abc_divide($3.c);
1844 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1845 $$.c = toreadwrite($1.c, c, 0, 0);
1850 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1855 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1857 $$.c = toreadwrite($1.c, c, 0, 0);
1860 E : E "-=" E { code_t*c = $3.c;
1861 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1862 c=abc_subtract_i(c);
1866 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1868 $$.c = toreadwrite($1.c, c, 0, 0);
1871 E : E '=' E { code_t*c = 0;
1872 c = code_append(c, $3.c);
1873 c = converttype(c, $3.t, $1.t);
1874 $$.c = toreadwrite($1.c, c, 1, 0);
1878 // TODO: use inclocal where appropriate
1879 E : E "++" { code_t*c = 0;
1880 classinfo_t*type = $1.t;
1881 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1882 c=abc_increment_i(c);
1888 c=converttype(c, type, $1.t);
1889 $$.c = toreadwrite($1.c, c, 0, 1);
1892 E : E "--" { code_t*c = 0;
1893 classinfo_t*type = $1.t;
1894 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1895 c=abc_decrement_i(c);
1901 c=converttype(c, type, $1.t);
1902 $$.c = toreadwrite($1.c, c, 0, 1);
1906 E : "++" %prec plusplus_prefix E { code_t*c = 0;
1907 classinfo_t*type = $2.t;
1908 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1909 c=abc_increment_i(c);
1915 c=converttype(c, type, $2.t);
1916 $$.c = toreadwrite($2.c, c, 0, 0);
1920 E : "--" %prec minusminus_prefix E { code_t*c = 0;
1921 classinfo_t*type = $2.t;
1922 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1923 c=abc_decrement_i(c);
1929 c=converttype(c, type, $2.t);
1930 $$.c = toreadwrite($2.c, c, 0, 0);
1934 E : E '.' T_IDENTIFIER
1936 classinfo_t*t = $1.t;
1938 if(TYPE_IS_CLASS(t)) {
1939 memberinfo_t*m = registry_findmember($1.t, "prototype");
1940 if(!m) syntaxerror("identifier '%s' not found in anonymous class", $3);
1945 memberinfo_t*f = registry_findmember(t, $3);
1947 if(f && !is_static != !(f->flags&FLAG_STATIC))
1950 if(f && f->slot && !noslot) {
1951 $$.c = abc_getslot($$.c, f->slot);
1954 namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
1955 multiname_t m = {QNAME, &ns, 0, $3};
1956 $$.c = abc_getproperty2($$.c, &m);
1958 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1959 $$.c = abc_getproperty2($$.c, &m);
1962 /* determine type */
1964 if(f->kind == MEMBER_METHOD) {
1965 $$.t = TYPE_FUNCTION(f);
1970 $$.c = abc_coerce_a($$.c);
1971 $$.t = registry_getanytype();
1974 /* when resolving a property on an unknown type, we do know the
1975 name of the property (and don't seem to need the package), but
1976 we do need to make avm2 try out all access modes */
1977 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1978 $$.c = abc_getproperty2($$.c, &m);
1979 $$.c = abc_coerce_a($$.c);
1980 $$.t = registry_getanytype();
1984 VAR_READ : T_IDENTIFIER {
1991 /* look at variables */
1992 if((i = find_variable($1, &$$.t)) >= 0) {
1993 // $1 is a local variable
1994 $$.c = abc_getlocal($$.c, i);
1996 /* look at current class' members */
1997 } else if((f = registry_findmember(state->clsinfo, $1))) {
1998 // $1 is a function in this class
1999 int var_is_static = (f->flags&FLAG_STATIC);
2000 int i_am_static = (state->minfo?(state->minfo->flags&FLAG_STATIC):FLAG_STATIC);
2001 if(var_is_static != i_am_static) {
2002 /* there doesn't seem to be any "static" way to access
2003 static properties of a class */
2004 state->late_binding = 1;
2006 namespace_t ns = {flags2access(f->flags), ""};
2007 multiname_t m = {QNAME, &ns, 0, $1};
2008 $$.c = abc_findpropstrict2($$.c, &m);
2009 $$.c = abc_getproperty2($$.c, &m);
2012 $$.c = abc_getlocal_0($$.c);
2013 $$.c = abc_getslot($$.c, f->slot);
2015 namespace_t ns = {flags2access(f->flags), ""};
2016 multiname_t m = {QNAME, &ns, 0, $1};
2017 $$.c = abc_getlocal_0($$.c);
2018 $$.c = abc_getproperty2($$.c, &m);
2021 if(f->kind == MEMBER_METHOD) {
2022 $$.t = TYPE_FUNCTION(f);
2027 /* look at classes in the current package and imported classes */
2028 } else if((a = find_class($1))) {
2030 $$.c = abc_getglobalscope($$.c);
2031 $$.c = abc_getslot($$.c, a->slot);
2034 $$.c = abc_getlex2($$.c, &m);
2036 $$.t = TYPE_CLASS(a);
2038 /* unknown object, let the avm2 resolve it */
2040 if(strcmp($1,"trace"))
2041 warning("Couldn't resolve %s, doing late binding", $1);
2042 state->late_binding = 1;
2044 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2047 $$.c = abc_findpropstrict2($$.c, &m);
2048 $$.c = abc_getproperty2($$.c, &m);
2053 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2054 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2055 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2057 // ----------------- namespaces -------------------------------------------------
2059 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2060 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2061 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2063 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER