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_NEE "!=="
117 %token<token> T_LE "<="
118 %token<token> T_GE ">="
119 %token<token> T_DIVBY "/="
120 %token<token> T_MODBY "%="
121 %token<token> T_MULBY "*="
122 %token<token> T_PLUSBY "+="
123 %token<token> T_MINUSBY "-="
124 %token<token> T_SHRBY ">>="
125 %token<token> T_SHLBY "<<="
126 %token<token> T_USHRBY ">>>="
127 %token<token> T_OROR "||"
128 %token<token> T_ANDAND "&&"
129 %token<token> T_COLONCOLON "::"
130 %token<token> T_MINUSMINUS "--"
131 %token<token> T_PLUSPLUS "++"
132 %token<token> T_DOTDOT ".."
133 %token<token> T_DOTDOTDOT "..."
134 %token<token> T_SHL "<<"
135 %token<token> T_USHR ">>>"
136 %token<token> T_SHR ">>"
138 %type <id> X_IDENTIFIER PACKAGE
139 %type <token> VARCONST
141 %type <code> CODEPIECE
142 %type <code> CODEBLOCK MAYBECODE
143 %type <token> PACKAGE_DECLARATION
144 %type <token> FUNCTION_DECLARATION
145 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
146 %type <token> CLASS_DECLARATION
147 %type <token> NAMESPACE_DECLARATION
148 %type <token> INTERFACE_DECLARATION
149 %type <code> VOIDEXPRESSION
150 %type <value> EXPRESSION NONCOMMAEXPRESSION
151 %type <value> MAYBEEXPRESSION
152 %type <value> E DELETE
153 %type <value> CONSTANT
154 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
155 %type <token> USE_NAMESPACE
156 %type <code> FOR_INIT
158 %type <classinfo> MAYBETYPE
161 %type <params> PARAM_LIST
162 %type <params> MAYBE_PARAM_LIST
163 %type <flags> MAYBE_MODIFIERS
164 %type <flags> MODIFIER_LIST
165 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
166 %type <classinfo_list> IMPLEMENTS_LIST
167 %type <classinfo> EXTENDS
168 %type <classinfo_list> EXTENDS_LIST
169 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
170 %type <classinfo_list> QNAME_LIST
171 %type <classinfo> TYPE
173 //%type <token> VARIABLE
174 %type <value> VAR_READ
176 //%type <token> T_IDENTIFIER
177 %type <token> MODIFIER
178 %type <value> FUNCTIONCALL
179 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
181 // precedence: from low to high
185 %left below_semicolon
188 %nonassoc below_assignment // for ?:, contrary to spec
189 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
196 %nonassoc "==" "!=" "===" "!=="
198 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
199 %left "<<" ">>" ">>>"
203 %left plusplus_prefix minusminus_prefix '~' '!' "delete" "typeof" //FIXME: *unary* + - should be here, too
205 %left '[' ']' '{' "new" '.' ".." "::"
206 %nonassoc T_IDENTIFIER
211 // needed for "return" precedence:
212 %nonassoc T_STRING T_REGEXP
213 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
214 %nonassoc "false" "true" "null"
219 static int yyerror(char*s)
221 syntaxerror("%s", s);
223 static char* concat3str(const char* t1, const char* t2, const char* t3)
228 char*text = malloc(l1+l2+l3+1);
229 memcpy(text , t1, l1);
230 memcpy(text+l1, t2, l2);
231 memcpy(text+l1+l2, t3, l3);
236 typedef struct _import {
240 DECLARE_LIST(import);
242 typedef struct _state {
250 /* code that needs to be executed at the start of
251 a method (like initializing local registers) */
254 import_list_t*wildcard_imports;
256 char has_own_imports;
262 code_t*cls_static_init;
272 typedef struct _global {
276 static global_t*global = 0;
277 static state_t* state = 0;
281 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
283 /* warning: list length of namespace set is undefined */
284 #define MULTINAME_LATE(m, access, package) \
285 namespace_t m##_ns = {access, package}; \
286 namespace_set_t m##_nsset; \
287 namespace_list_t m##_l;m##_l.next = 0; \
288 m##_nsset.namespaces = &m##_l; \
289 m##_nsset = m##_nsset; \
290 m##_l.namespace = &m##_ns; \
291 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
293 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
294 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
295 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
296 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
297 static namespace_list_t nl4 = {&ns4,0};
298 static namespace_list_t nl3 = {&ns3,&nl4};
299 static namespace_list_t nl2 = {&ns2,&nl3};
300 static namespace_list_t nl1 = {&ns1,&nl2};
301 static namespace_set_t nopackage_namespace_set = {&nl1};
303 static state_list_t*state_stack=0;
305 static void init_globals()
307 global = rfx_calloc(sizeof(global_t));
310 static void new_state()
313 NEW(state_list_t, sl);
315 state_t*oldstate = state;
317 memcpy(s, state, sizeof(state_t)); //shallow copy
318 sl->next = state_stack;
321 s->imports = dict_new();
326 state->vars = dict_new();
328 state->has_own_imports = 0;
330 static void state_has_imports()
332 state->wildcard_imports = list_clone(state->wildcard_imports);
333 state->imports = dict_clone(state->imports);
334 state->has_own_imports = 1;
337 static void old_state()
339 if(!state_stack || !state_stack->next)
340 syntaxerror("invalid nesting");
341 state_t*oldstate = state;
342 state_list_t*old = state_stack;
343 state_stack = state_stack->next;
345 state = state_stack->state;
346 /*if(state->initcode) {
347 printf("residual initcode\n");
348 code_dump(state->initcode, 0, 0, "", stdout);
350 if(oldstate->has_own_imports) {
351 list_free(oldstate->wildcard_imports);
352 dict_destroy(oldstate->imports);oldstate->imports=0;
354 state->initcode = code_append(state->initcode, oldstate->initcode);
356 void initialize_state()
361 state->file = abc_file_new();
362 state->file->flags &= ~ABCFILE_LAZY;
364 state->init = abc_initscript(state->file, 0);
365 code_t*c = state->init->method->body->code;
367 c = abc_getlocal_0(c);
368 c = abc_pushscope(c);
370 /* findpropstrict doesn't just return a scope object- it
371 also makes it "active" somehow. Push local_0 on the
372 scope stack and read it back with findpropstrict, it'll
373 contain properties like "trace". Trying to find the same
374 property on a "vanilla" local_0 yields only a "undefined" */
375 //c = abc_findpropstrict(c, "[package]::trace");
377 /*c = abc_getlocal_0(c);
378 c = abc_findpropstrict(c, "[package]::trace");
380 c = abc_setlocal_1(c);
382 c = abc_pushbyte(c, 0);
383 c = abc_setlocal_2(c);
385 code_t*xx = c = abc_label(c);
386 c = abc_findpropstrict(c, "[package]::trace");
387 c = abc_pushstring(c, "prop:");
388 c = abc_hasnext2(c, 1, 2);
390 c = abc_setlocal_3(c);
391 c = abc_callpropvoid(c, "[package]::trace", 2);
392 c = abc_getlocal_3(c);
394 c = abc_iftrue(c,xx);*/
396 c = abc_findpropstrict(c, "[package]::trace");
397 c = abc_pushstring(c, "[entering global init function]");
398 c = abc_callpropvoid(c, "[package]::trace", 1);
400 state->init->method->body->code = c;
402 void* finalize_state()
404 if(state->level!=1) {
405 syntaxerror("unexpected end of file");
407 abc_method_body_t*m = state->init->method->body;
410 __ findpropstrict(m, "[package]::trace");
411 __ pushstring(m, "[leaving global init function]");
412 __ callpropvoid(m, "[package]::trace", 1);
418 static void startpackage(char*name)
421 syntaxerror("Packages can not be nested.");
424 /*printf("entering package \"%s\"\n", name);*/
425 state->package = name;
427 static void endpackage()
429 /*printf("leaving package \"%s\"\n", state->package);*/
434 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
437 syntaxerror("inner classes now allowed");
442 classinfo_list_t*mlist=0;
443 /*printf("entering class %s\n", name);
444 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
446 printf(" extends: %s.%s\n", extends->package, extends->name);
447 printf(" implements (%d): ", list_length(implements));
448 for(mlist=implements;mlist;mlist=mlist->next) {
449 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
454 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
455 syntaxerror("invalid modifier(s)");
457 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
458 syntaxerror("public and internal not supported at the same time.");
460 /* create the class name, together with the proper attributes */
464 if(!(flags&FLAG_PUBLIC) && !state->package) {
465 access = ACCESS_PRIVATE; package = current_filename;
466 } else if(!(flags&FLAG_PUBLIC) && state->package) {
467 access = ACCESS_PACKAGEINTERNAL; package = state->package;
468 } else if(state->package) {
469 access = ACCESS_PACKAGE; package = state->package;
471 syntaxerror("public classes only allowed inside a package");
474 if(registry_findclass(package, classname)) {
475 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
478 /* build info struct */
479 int num_interfaces = (list_length(implements));
480 state->clsinfo = classinfo_register(access, package, classname, num_interfaces);
481 state->clsinfo->superclass = extends;
483 classinfo_list_t*l = implements;
484 for(l=implements;l;l=l->next) {
485 state->clsinfo->interfaces[pos++] = l->classinfo;
488 MULTINAME(classname2,state->clsinfo);
490 multiname_t*extends2 = sig2mname(extends);
493 state->cls_init = abc_getlocal_0(state->cls_init);
494 state->cls_init = abc_constructsuper(state->cls_init, 0);
497 state->cls = abc_class_new(state->file, &classname2, extends2);
498 if(flags&FLAG_FINAL) abc_class_final(state->cls);
499 if(flags&FLAG_DYNAMIC) abc_class_sealed(state->cls);
500 if(interface) abc_class_interface(state->cls);
502 for(mlist=implements;mlist;mlist=mlist->next) {
503 MULTINAME(m, mlist->classinfo);
504 abc_class_add_interface(state->cls, &m);
507 /* now write the construction code for this class */
508 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
510 abc_method_body_t*m = state->init->method->body;
511 __ getglobalscope(m);
512 classinfo_t*s = extends;
517 //TODO: take a look at the current scope stack, maybe
518 // we can re-use something
523 multiname_t*s2 = sig2mname(s);
525 multiname_destroy(s2);
527 __ pushscope(m); count++;
528 m->code = m->code->prev->prev; // invert
530 /* continue appending after last op end */
531 while(m->code && m->code->next) m->code = m->code->next;
533 /* TODO: if this is one of *our* classes, we can also
534 do a getglobalscope/getslot <nr> (which references
535 the init function's slots) */
537 __ getlex2(m, extends2);
539 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
540 stack is not the superclass */
541 __ pushscope(m);count++;
544 /* notice: we get a verify error #1107 if the top element on the scope
545 stack is not the global object */
547 __ pushscope(m);count++;
549 __ newclass(m,state->cls);
553 __ setslot(m, slotindex);
555 /* flash.display.MovieClip handling */
556 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
557 if(state->package && state->package[0]) {
558 globalclass = concat3str(state->package, ".", classname);
560 globalclass = strdup(classname);
563 multiname_destroy(extends2);
566 static void endclass()
568 if(state->cls_init) {
569 if(!state->cls->constructor) {
570 abc_method_t*m = abc_class_constructor(state->cls, 0);
571 m->body->code = code_append(m->body->code, state->cls_init);
572 m->body->code = abc_returnvoid(m->body->code);
574 code_t*c = state->cls->constructor->body->code;
575 c = code_append(state->cls_init, c);
576 state->cls->constructor->body->code = c;
580 if(state->cls_static_init) {
581 if(!state->cls->static_constructor) {
582 abc_method_t*m = abc_class_staticconstructor(state->cls, 0);
583 m->body->code = code_append(m->body->code, state->cls_static_init);
584 m->body->code = abc_returnvoid(m->body->code);
586 state->cls->static_constructor->body->code =
587 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
594 typedef struct _variable {
599 static int find_variable(char*name, classinfo_t**m)
601 state_list_t* s = state_stack;
603 variable_t*v = dict_lookup(s->state->vars, name);
614 static int find_variable_safe(char*name, classinfo_t**m)
616 int i = find_variable(name, m);
618 syntaxerror("undefined variable: %s", name);
621 static char variable_exists(char*name)
623 return dict_lookup(state->vars, name)!=0;
625 static int new_variable(char*name, classinfo_t*type)
628 v->index = global->variable_count;
630 dict_put(state->vars, name, v);
631 return global->variable_count++;
633 #define TEMPVARNAME "__as3_temp__"
634 static int gettempvar()
636 int i = find_variable(TEMPVARNAME, 0);
638 return new_variable(TEMPVARNAME, 0);
644 code_t* killvars(code_t*c)
647 for(t=0;t<state->vars->hashsize;t++) {
648 dictentry_t*e =state->vars->slots[t];
650 variable_t*v = (variable_t*)e->data;
651 //do this always, otherwise register types don't match
652 //in the verifier when doing nested loops
653 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
654 c = abc_kill(c, v->index);
662 static void check_constant_against_type(classinfo_t*t, constant_t*c)
664 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
665 if(TYPE_IS_NUMBER(t)) {
666 xassert(c->type == CONSTANT_FLOAT
667 || c->type == CONSTANT_INT
668 || c->type == CONSTANT_UINT);
669 } else if(TYPE_IS_UINT(t)) {
670 xassert(c->type == CONSTANT_UINT ||
671 (c->type == CONSTANT_INT && c->i>0));
672 } else if(TYPE_IS_INT(t)) {
673 xassert(c->type == CONSTANT_INT);
674 } else if(TYPE_IS_BOOLEAN(t)) {
675 xassert(c->type == CONSTANT_TRUE
676 || c->type == CONSTANT_FALSE);
680 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
682 memberinfo_t*minfo = 0;
683 if(getset != KW_GET && getset != KW_SET) {
684 if(registry_findmember(state->clsinfo, name)) {
685 syntaxerror("class already contains a member/method called '%s'", name);
687 minfo = memberinfo_register(state->clsinfo, name, MEMBER_METHOD);
688 minfo->return_type = return_type;
689 // getslot on a member slot only returns "undefined", so no need
690 // to actually store these
691 //state->minfo->slot = state->m->method->trait->slot_id;
693 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
697 else if(params->list)
698 type = params->list->param->type;
699 if((minfo=registry_findmember(state->clsinfo, name))) {
700 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
701 syntaxerror("class already contains a member or method called '%s'", name);
703 syntaxerror("getter/setter for '%s' already defined", name);
704 /* make a setter or getter into a getset */
709 if(type && minfo->type != type)
710 syntaxerror("different type in getter and setter");
712 minfo = memberinfo_register(state->clsinfo, name, gs);
715 /* can't assign a slot as getter and setter might have different slots */
716 //minfo->slot = slot;
718 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
719 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
720 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
721 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
722 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
726 static int flags2access(int flags)
729 if(flags&FLAG_PUBLIC) {
730 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
731 access = ACCESS_PACKAGE;
732 } else if(flags&FLAG_PRIVATE) {
733 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
734 access = ACCESS_PRIVATE;
735 } else if(flags&FLAG_PROTECTED) {
736 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
737 access = ACCESS_PROTECTED;
739 access = ACCESS_PACKAGEINTERNAL;
744 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
745 params_t*params, classinfo_t*return_type)
749 global->variable_count = 0;
750 state->function = name;
753 syntaxerror("not able to start another method scope");
756 namespace_t mname_ns = {flags2access(flags), ""};
757 multiname_t mname = {QNAME, &mname_ns, 0, name};
759 multiname_t*type2 = sig2mname(return_type);
761 if(!strcmp(state->clsinfo->name,name)) {
762 state->m = abc_class_constructor(state->cls, type2);
763 name = "__as3_constructor__";
765 if(flags&FLAG_STATIC)
766 state->m = abc_class_staticmethod(state->cls, type2, &mname);
768 state->m = abc_class_method(state->cls, type2, &mname);
769 slot = state->m->trait->slot_id;
771 state->minfo = registerfunction(getset, flags, name, params, return_type, slot);
773 if(getset == KW_GET) state->m->trait->kind = TRAIT_GETTER;
774 if(getset == KW_SET) state->m->trait->kind = TRAIT_SETTER;
775 if(params->varargs) state->m->flags |= METHOD_NEED_REST;
779 for(p=params->list;p;p=p->next) {
780 if(params->varargs && !p->next) {
781 break; //varargs: omit last parameter in function signature
783 multiname_t*m = sig2mname(p->param->type);
784 list_append(state->m->parameters, m);
785 if(p->param->value) {
786 check_constant_against_type(p->param->type, p->param->value);
787 opt=1;list_append(state->m->optional_parameters, p->param->value);
789 syntaxerror("non-optional parameter not allowed after optional parameters");
793 /* state->vars is initialized by state_new */
794 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->clsinfo)!=0) syntaxerror("Internal error");
796 for(p=params->list;p;p=p->next) {
797 new_variable(p->param->name, p->param->type);
800 static void endfunction(code_t*body)
803 if(!(state->cls->flags & CLASS_INTERFACE)) {
805 if(state->late_binding) {
806 c = abc_getlocal_0(c);
807 c = abc_pushscope(c);
809 c = code_append(c, state->initcode);
810 c = code_append(c, body);
812 /* append return if necessary */
813 if(!c || c->opcode != OPCODE_RETURNVOID &&
814 c->opcode != OPCODE_RETURNVALUE) {
815 c = abc_returnvoid(c);
817 if(state->m->body->code) syntaxerror("internal error");
818 state->m->body->code = c;
825 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
830 void breakjumpsto(code_t*c, code_t*jump)
835 if(c->opcode == OPCODE___BREAK__) {
836 c->opcode = OPCODE_JUMP;
843 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
846 return registry_getanytype();
847 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
848 return registry_getanytype();
851 return registry_getanytype();
853 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
858 return abc_coerce_a(c);
862 // cast an "any" type to a specific type. subject to
863 // runtime exceptions
864 return abc_coerce2(c, &m);
867 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
868 return abc_coerce2(c, &m);
870 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
871 return abc_coerce2(c, &m);
873 /* these are subject to overflow */
874 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
875 return abc_coerce2(c, &m);
877 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
878 return abc_coerce2(c, &m);
881 classinfo_t*supertype = from;
883 if(supertype == to) {
884 // target type is one of from's superclasses
885 return abc_coerce2(c, &m);
888 while(supertype->interfaces[t]) {
889 if(supertype->interfaces[t]==to) {
890 // to type is one of from's interfaces
891 return abc_coerce2(c, &m);
895 supertype = supertype->superclass;
897 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
899 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
901 syntaxerror("can't convert type %s to %s", from->name, to->name);
904 code_t*defaultvalue(code_t*c, classinfo_t*type)
906 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
907 c = abc_pushbyte(c, 0);
908 } else if(TYPE_IS_BOOLEAN(type)) {
909 c = abc_pushfalse(c);
916 char is_pushundefined(code_t*c)
918 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
921 void parserassert(int b)
923 if(!b) syntaxerror("internal error: assertion failed");
926 static classinfo_t* find_class(char*name)
930 c = registry_findclass(state->package, name);
932 /* try explicit imports */
933 dictentry_t* e = dict_get_slot(state->imports, name);
937 if(!strcmp(e->key, name)) {
938 c = (classinfo_t*)e->data;
943 /* try package.* imports */
944 import_list_t*l = state->wildcard_imports;
948 //printf("does package %s contain a class %s?\n", l->import->package, name);
949 c = registry_findclass(l->import->package, name);
953 /* try global package */
955 c = registry_findclass("", name);
960 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
964 [prefix code] [read instruction]
968 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
971 if(in && in->opcode == OPCODE_COERCE_A) {
972 in = code_cutlast(in);
975 syntaxerror("internal error");
977 /* chop off read instruction */
981 prefix = r->prev;r->prev = 0;
987 char use_temp_var = readbefore;
989 /* generate the write instruction, and maybe append a dup to the prefix code */
990 code_t* write = abc_nop(0);
991 if(r->opcode == OPCODE_GETPROPERTY) {
992 write->opcode = OPCODE_SETPROPERTY;
993 multiname_t*m = (multiname_t*)r->data[0];
994 write->data[0] = multiname_clone(m);
995 if(m->type == QNAME || m->type == MULTINAME) {
997 prefix = abc_dup(prefix); // we need the object, too
1000 } else if(m->type == MULTINAMEL) {
1002 /* dupping two values on the stack requires 5 operations and one register-
1003 couldn't adobe just have given us a dup2? */
1004 int temp = gettempvar();
1005 prefix = abc_setlocal(prefix, temp);
1006 prefix = abc_dup(prefix);
1007 prefix = abc_getlocal(prefix, temp);
1008 prefix = abc_swap(prefix);
1009 prefix = abc_getlocal(prefix, temp);
1013 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1015 } else if(r->opcode == OPCODE_GETSLOT) {
1016 write->opcode = OPCODE_SETSLOT;
1017 write->data[0] = r->data[0];
1019 prefix = abc_dup(prefix); // we need the object, too
1022 } else if(r->opcode == OPCODE_GETLOCAL) {
1023 write->opcode = OPCODE_SETLOCAL;
1024 write->data[0] = r->data[0];
1025 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1026 write->opcode = OPCODE_SETLOCAL_0;
1027 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1028 write->opcode = OPCODE_SETLOCAL_1;
1029 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1030 write->opcode = OPCODE_SETLOCAL_2;
1031 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1032 write->opcode = OPCODE_SETLOCAL_3;
1034 code_dump(r, 0, 0, "", stdout);
1035 syntaxerror("illegal lvalue: can't assign a value to this expression");
1042 /* with getproperty/getslot, we have to be extra careful not
1043 to execute the read code twice, as it might have side-effects
1044 (e.g. if the property is in fact a setter/getter combination)
1046 So read the value, modify it, and write it again,
1047 using prefix only once and making sure (by using a temporary
1048 register) that the return value is what we just wrote */
1049 temp = gettempvar();
1050 c = code_append(c, prefix);
1051 c = code_append(c, r);
1054 c = abc_setlocal(c, temp);
1056 c = code_append(c, middlepart);
1059 c = abc_setlocal(c, temp);
1061 c = code_append(c, write);
1062 c = abc_getlocal(c, temp);
1063 c = abc_kill(c, temp);
1065 /* if we're allowed to execute the read code twice *and*
1066 the middlepart doesn't modify the code, things are easier.
1068 code_t* r2 = code_dup(r);
1069 //c = code_append(c, prefix);
1070 parserassert(!prefix);
1071 c = code_append(c, r);
1072 c = code_append(c, middlepart);
1073 c = code_append(c, write);
1074 c = code_append(c, r2);
1077 /* even smaller version: overwrite the value without reading
1081 c = code_append(c, prefix);
1084 c = code_append(c, middlepart);
1085 c = code_append(c, write);
1086 c = code_append(c, r);
1088 temp = gettempvar();
1090 c = code_append(c, prefix);
1093 c = code_append(c, middlepart);
1095 c = abc_setlocal(c, temp);
1096 c = code_append(c, write);
1097 c = abc_getlocal(c, temp);
1104 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1105 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1112 /* ------------ code blocks / statements ---------------- */
1116 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1117 MAYBECODE: {$$=code_new();}
1119 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1120 CODE: CODEPIECE {$$=$1;}
1122 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1123 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1124 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1125 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1126 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1127 CODEPIECE: ';' {$$=code_new();}
1128 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1129 CODEPIECE: VOIDEXPRESSION {$$=$1}
1130 CODEPIECE: FOR {$$=$1}
1131 CODEPIECE: WHILE {$$=$1}
1132 CODEPIECE: BREAK {$$=$1}
1133 CODEPIECE: RETURN {$$=$1}
1134 CODEPIECE: IF {$$=$1}
1135 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1136 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1138 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1139 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1140 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1142 /* ------------ variables --------------------------- */
1144 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1145 | {$$.c=abc_pushundefined(0);
1149 VAR : "const" | "var"
1150 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1152 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1153 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1155 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1157 if(variable_exists($2))
1158 syntaxerror("Variable %s already defined", $2);
1160 if(!is_subtype_of($4.t, $3)) {
1161 syntaxerror("Can't convert %s to %s", $4.t->name,
1165 int index = new_variable($2, $3);
1168 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1170 $$ = converttype($$, $4.t, $3);
1171 $$ = abc_setlocal($$, index);
1173 $$ = defaultvalue(0, $3);
1174 $$ = abc_setlocal($$, index);
1177 /* if this is a typed variable:
1178 push default value for type on stack */
1180 state->initcode = defaultvalue(state->initcode, $3);
1181 state->initcode = abc_setlocal(state->initcode, index);
1184 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1186 $$ = abc_coerce_a($$);
1187 $$ = abc_setlocal($$, index);
1193 /* that's the default for a local register, anyway
1195 state->initcode = abc_pushundefined(state->initcode);
1196 state->initcode = abc_setlocal(state->initcode, index);
1198 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1201 /* ------------ control flow ------------------------- */
1203 MAYBEELSE: %prec below_else {$$ = code_new();}
1204 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1205 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1207 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1208 $$ = state->initcode;state->initcode=0;
1210 $$ = code_append($$, $4.c);
1211 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1213 $$ = code_append($$, $6);
1215 myjmp = $$ = abc_jump($$, 0);
1217 myif->branch = $$ = abc_label($$);
1219 $$ = code_append($$, $7);
1220 myjmp->branch = $$ = abc_label($$);
1223 $$ = killvars($$);old_state();
1226 FOR_INIT : {$$=code_new();}
1227 FOR_INIT : VARIABLE_DECLARATION
1228 FOR_INIT : VOIDEXPRESSION
1230 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1231 $$ = state->initcode;state->initcode=0;
1233 $$ = code_append($$, $4);
1234 code_t*loopstart = $$ = abc_label($$);
1235 $$ = code_append($$, $6.c);
1236 code_t*myif = $$ = abc_iffalse($$, 0);
1237 $$ = code_append($$, $10);
1238 $$ = code_append($$, $8);
1239 $$ = abc_jump($$, loopstart);
1240 code_t*out = $$ = abc_label($$);
1241 breakjumpsto($$, out);
1244 $$ = killvars($$);old_state();
1247 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1248 $$ = state->initcode;state->initcode=0;
1250 code_t*myjmp = $$ = abc_jump($$, 0);
1251 code_t*loopstart = $$ = abc_label($$);
1252 $$ = code_append($$, $6);
1253 myjmp->branch = $$ = abc_label($$);
1254 $$ = code_append($$, $4.c);
1255 $$ = abc_iftrue($$, loopstart);
1256 code_t*out = $$ = abc_label($$);
1257 breakjumpsto($$, out);
1259 $$ = killvars($$);old_state();
1263 $$ = abc___break__(0);
1266 /* ------------ packages and imports ---------------- */
1268 X_IDENTIFIER: T_IDENTIFIER
1269 | "package" {$$="package";}
1271 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1272 PACKAGE: X_IDENTIFIER {$$=$1;}
1274 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1275 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1277 IMPORT : "import" QNAME {
1280 syntaxerror("Couldn't import class\n");
1281 state_has_imports();
1282 dict_put(state->imports, c->name, c);
1285 IMPORT : "import" PACKAGE '.' '*' {
1288 state_has_imports();
1289 list_append(state->wildcard_imports, i);
1293 /* ------------ classes and interfaces (header) -------------- */
1295 MAYBE_MODIFIERS : {$$=0;}
1296 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1297 MODIFIER_LIST : MODIFIER {$$=$1;}
1298 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1300 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1301 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1302 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1303 | KW_STATIC {$$=FLAG_STATIC;}
1304 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1305 | KW_FINAL {$$=FLAG_FINAL;}
1306 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1307 | KW_NATIVE {$$=FLAG_NATIVE;}
1308 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1310 EXTENDS : {$$=registry_getobjectclass();}
1311 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1313 EXTENDS_LIST : {$$=list_new();}
1314 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1316 IMPLEMENTS_LIST : {$$=list_new();}
1317 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1319 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1320 EXTENDS IMPLEMENTS_LIST
1321 '{' {startclass($1,$3,$4,$5, 0);}
1322 MAYBE_DECLARATION_LIST
1325 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1327 '{' {startclass($1,$3,0,$4,1);}
1328 MAYBE_IDECLARATION_LIST
1331 /* ------------ classes and interfaces (body) -------------- */
1333 MAYBE_DECLARATION_LIST :
1334 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1335 DECLARATION_LIST : DECLARATION
1336 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1338 DECLARATION : SLOT_DECLARATION
1339 DECLARATION : FUNCTION_DECLARATION
1341 MAYBE_IDECLARATION_LIST :
1342 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1343 IDECLARATION_LIST : IDECLARATION
1344 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1346 IDECLARATION : "var" T_IDENTIFIER {
1347 syntaxerror("variable declarations not allowed in interfaces");
1349 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1351 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1352 syntaxerror("invalid method modifiers: interface methods always need to be public");
1354 startfunction(0,$1,$3,$4,&$6,$8);
1358 /* ------------ classes and interfaces (body, slots ) ------- */
1360 VARCONST: "var" | "const"
1362 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1364 memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
1366 info->flags = flags;
1369 namespace_t mname_ns = {flags2access(flags), ""};
1370 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1372 if(!(flags&FLAG_STATIC)) {
1375 t=abc_class_slot(state->cls, &mname, &m);
1377 t=abc_class_slot(state->cls, &mname, 0);
1379 info->slot = t->slot_id;
1383 t=abc_class_staticslot(state->cls, &mname, &m);
1385 t=abc_class_staticslot(state->cls, &mname, 0);
1387 info->slot = t->slot_id;
1389 if($5.c && !is_pushundefined($5.c)) {
1391 c = abc_getlocal_0(c);
1392 c = code_append(c, $5.c);
1393 c = converttype(c, $5.t, $4);
1394 c = abc_setslot(c, t->slot_id);
1395 if(!(flags&FLAG_STATIC))
1396 state->cls_init = code_append(state->cls_init, c);
1398 state->cls_static_init = code_append(state->cls_static_init, c);
1401 t->kind= TRAIT_CONST;
1405 /* ------------ constants -------------------------------------- */
1407 MAYBESTATICCONSTANT: {$$=0;}
1408 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1410 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1411 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1412 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1413 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1414 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1415 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1416 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1417 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1418 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1420 /* ------------ classes and interfaces (body, functions) ------- */
1422 // non-vararg version
1424 memset(&$$,0,sizeof($$));
1426 MAYBE_PARAM_LIST: PARAM_LIST {
1431 MAYBE_PARAM_LIST: "..." PARAM {
1432 memset(&$$,0,sizeof($$));
1434 list_append($$.list, $2);
1436 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1439 list_append($$.list, $4);
1443 PARAM_LIST: PARAM_LIST ',' PARAM {
1445 list_append($$.list, $3);
1448 memset(&$$,0,sizeof($$));
1449 list_append($$.list, $1);
1452 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1453 $$ = malloc(sizeof(param_t));
1458 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1459 $$ = malloc(sizeof(param_t));
1461 $$->type = TYPE_ANY;
1464 GETSET : "get" {$$=$1;}
1468 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1469 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1471 if(!state->m) syntaxerror("internal error: undefined function");
1475 /* ------------- package + class ids --------------- */
1477 CLASS: T_IDENTIFIER {
1479 /* try current package */
1480 $$ = find_class($1);
1481 if(!$$) syntaxerror("Could not find class %s\n", $1);
1484 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1485 $$ = registry_findclass($1, $3);
1486 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1489 QNAME: PACKAGEANDCLASS
1492 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1493 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1495 TYPE : QNAME {$$=$1;}
1496 | '*' {$$=registry_getanytype();}
1498 | "String" {$$=registry_getstringclass();}
1499 | "int" {$$=registry_getintclass();}
1500 | "uint" {$$=registry_getuintclass();}
1501 | "Boolean" {$$=registry_getbooleanclass();}
1502 | "Number" {$$=registry_getnumberclass();}
1505 MAYBETYPE: ':' TYPE {$$=$2;}
1508 /* ----------function calls, delete, constructor calls ------ */
1510 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1511 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1513 MAYBE_EXPRESSION_LIST : {$$=0;}
1514 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1515 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1516 typedcode_t*t = malloc(sizeof(typedcode_t));
1518 list_append($$, t);}
1519 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1520 typedcode_t*t = malloc(sizeof(typedcode_t));
1522 list_append($$, t);}
1524 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1529 $$.c = abc_getglobalscope($$.c);
1530 $$.c = abc_getslot($$.c, $2->slot);
1532 $$.c = abc_findpropstrict2($$.c, &m);
1535 typedcode_list_t*l = $3;
1538 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1543 $$.c = abc_construct($$.c, len);
1545 $$.c = abc_constructprop2($$.c, &m, len);
1549 /* TODO: use abc_call (for calling local variables),
1550 abc_callstatic (for calling own methods)
1553 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1554 typedcode_list_t*l = $3;
1556 code_t*paramcode = 0;
1558 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1564 if($$.c->opcode == OPCODE_COERCE_A) {
1565 $$.c = code_cutlast($$.c);
1569 multiname_t*name = 0;
1570 if($$.c->opcode == OPCODE_GETPROPERTY) {
1571 name = multiname_clone($$.c->data[0]);
1572 $$.c = code_cutlast($$.c);
1573 $$.c = code_append($$.c, paramcode);
1574 $$.c = abc_callproperty2($$.c, name, len);
1575 } else if($$.c->opcode == OPCODE_GETSLOT) {
1576 int slot = (int)(ptroff_t)$$.c->data[0];
1577 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1578 if(t->kind!=TRAIT_METHOD) {
1579 //flash allows to assign closures to members.
1580 //syntaxerror("not a function");
1583 $$.c = code_cutlast($$.c);
1584 $$.c = code_append($$.c, paramcode);
1585 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1586 $$.c = abc_callproperty2($$.c, name, len);
1588 $$.c = abc_getlocal_0($$.c);
1589 $$.c = code_append($$.c, paramcode);
1590 $$.c = abc_call($$.c, len);
1595 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1596 $$.t = $1.t->function->return_type;
1598 $$.c = abc_coerce_a($$.c);
1603 DELETE: "delete" E {
1605 if($$.c->opcode == OPCODE_COERCE_A) {
1606 $$.c = code_cutlast($$.c);
1608 multiname_t*name = 0;
1609 if($$.c->opcode == OPCODE_GETPROPERTY) {
1610 $$.c->opcode = OPCODE_DELETEPROPERTY;
1611 } else if($$.c->opcode == OPCODE_GETSLOT) {
1612 int slot = (int)(ptroff_t)$$.c->data[0];
1613 multiname_t*name = abc_class_find_slotid(state->cls,slot)->name;
1614 $$.c = code_cutlast($$.c);
1615 $$.c = abc_deleteproperty2($$.c, name);
1617 $$.c = abc_getlocal_0($$.c);
1618 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1619 $$.c = abc_deleteproperty2($$.c, &m);
1621 $$.t = TYPE_BOOLEAN;
1624 RETURN: "return" %prec prec_none {
1625 $$ = abc_returnvoid(0);
1627 RETURN: "return" EXPRESSION {
1629 $$ = abc_returnvalue($$);
1632 // ----------------------- expression types -------------------------------------
1634 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1635 EXPRESSION : E %prec below_minus {$$ = $1;}
1636 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1638 $$.c = cut_last_push($$.c);
1639 $$.c = code_append($$.c,$3.c);
1642 VOIDEXPRESSION : EXPRESSION %prec below_minus {$$=cut_last_push($1.c);}
1644 // ----------------------- expression evaluation -------------------------------------
1647 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1649 E : DELETE {$$ = $1;}
1650 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1654 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1655 //MULTINAME(m, registry_getintclass());
1656 //$$.c = abc_coerce2($$.c, &m); // FIXME
1659 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1662 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1665 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1668 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1671 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1674 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1675 $$.t = TYPE_BOOLEAN;
1677 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1678 $$.t = TYPE_BOOLEAN;
1680 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1685 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1686 $$.t = TYPE_BOOLEAN;
1688 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1689 $$.t = TYPE_BOOLEAN;
1691 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1692 $$.t = TYPE_BOOLEAN;
1694 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1695 $$.t = TYPE_BOOLEAN;
1697 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1698 $$.t = TYPE_BOOLEAN;
1700 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1701 $$.t = TYPE_BOOLEAN;
1703 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1704 $$.t = TYPE_BOOLEAN;
1706 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1707 $$.t = TYPE_BOOLEAN;
1710 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1712 $$.c = converttype($$.c, $1.t, $$.t);
1713 $$.c = abc_dup($$.c);
1714 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1715 $$.c = cut_last_push($$.c);
1716 $$.c = code_append($$.c,$3.c);
1717 $$.c = converttype($$.c, $3.t, $$.t);
1718 code_t*label = $$.c = abc_label($$.c);
1719 jmp->branch = label;
1722 $$.t = join_types($1.t, $3.t, 'A');
1723 /*printf("%08x:\n",$1.t);
1724 code_dump($1.c, 0, 0, "", stdout);
1725 printf("%08x:\n",$3.t);
1726 code_dump($3.c, 0, 0, "", stdout);
1727 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1729 $$.c = converttype($$.c, $1.t, $$.t);
1730 $$.c = abc_dup($$.c);
1731 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1732 $$.c = cut_last_push($$.c);
1733 $$.c = code_append($$.c,$3.c);
1734 $$.c = converttype($$.c, $3.t, $$.t);
1735 code_t*label = $$.c = abc_label($$.c);
1736 jmp->branch = label;
1739 E : '!' E {$$.c=$2.c;
1740 $$.c = abc_not($$.c);
1741 $$.t = TYPE_BOOLEAN;
1744 E : '~' E {$$.c=$2.c;
1745 $$.c = abc_bitnot($$.c);
1749 E : E '&' E {$$.c = code_append($1.c,$3.c);
1750 $$.c = abc_bitand($$.c);
1754 E : E '^' E {$$.c = code_append($1.c,$3.c);
1755 $$.c = abc_bitxor($$.c);
1759 E : E '|' E {$$.c = code_append($1.c,$3.c);
1760 $$.c = abc_bitor($$.c);
1764 E : E '-' E {$$.c = code_append($1.c,$3.c);
1765 if(BOTH_INT($1,$3)) {
1766 $$.c = abc_subtract_i($$.c);
1769 $$.c = abc_subtract($$.c);
1773 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1774 $$.c = abc_rshift($$.c);
1777 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1778 $$.c = abc_urshift($$.c);
1781 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1782 $$.c = abc_lshift($$.c);
1786 E : E '/' E {$$.c = code_append($1.c,$3.c);
1787 $$.c = abc_divide($$.c);
1790 E : E '+' E {$$.c = code_append($1.c,$3.c);
1791 $$.c = abc_add($$.c);
1794 E : E '%' E {$$.c = code_append($1.c,$3.c);
1795 $$.c = abc_modulo($$.c);
1798 E : E '*' E {$$.c = code_append($1.c,$3.c);
1799 if(BOTH_INT($1,$3)) {
1800 $$.c = abc_multiply_i($$.c);
1803 $$.c = abc_multiply($$.c);
1808 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1809 if(use_astype && TYPE_IS_CLASS($3.t)) {
1810 MULTINAME(m,$3.t->cls);
1811 $$.c = abc_astype2($1.c, &m);
1814 $$.c = code_append($1.c, $3.c);
1815 $$.c = abc_astypelate($$.c);
1820 E : E "is" E {$$.c = code_append($1.c, $3.c);
1821 $$.c = abc_istypelate($$.c);
1822 $$.t = TYPE_BOOLEAN;
1825 E : '(' E ')' {$$=$2;}
1829 $$.c=abc_negate_i($$.c);
1832 $$.c=abc_negate($$.c);
1839 $$.c = code_append($$.c, $3.c);
1841 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1842 $$.c = abc_getproperty2($$.c, &m);
1843 $$.t = 0; // array elements have unknown type
1848 if(BOTH_INT($1,$3)) {
1849 c=abc_multiply_i(c);
1853 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1854 $$.c = toreadwrite($1.c, c, 0, 0);
1859 code_t*c = abc_modulo($3.c);
1860 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1861 $$.c = toreadwrite($1.c, c, 0, 0);
1865 code_t*c = abc_lshift($3.c);
1866 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1867 $$.c = toreadwrite($1.c, c, 0, 0);
1871 code_t*c = abc_rshift($3.c);
1872 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1873 $$.c = toreadwrite($1.c, c, 0, 0);
1877 code_t*c = abc_urshift($3.c);
1878 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1879 $$.c = toreadwrite($1.c, c, 0, 0);
1883 code_t*c = abc_divide($3.c);
1884 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1885 $$.c = toreadwrite($1.c, c, 0, 0);
1890 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1895 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1897 $$.c = toreadwrite($1.c, c, 0, 0);
1900 E : E "-=" E { code_t*c = $3.c;
1901 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1902 c=abc_subtract_i(c);
1906 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1908 $$.c = toreadwrite($1.c, c, 0, 0);
1911 E : E '=' E { code_t*c = 0;
1912 c = code_append(c, $3.c);
1913 c = converttype(c, $3.t, $1.t);
1914 $$.c = toreadwrite($1.c, c, 1, 0);
1918 E : E '?' E ':' E %prec below_assignment {
1920 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
1921 $$.c = code_append($$.c, $3.c);
1922 code_t*j2 = $$.c = abc_jump($$.c, 0);
1923 $$.c = j1->branch = abc_label($$.c);
1924 $$.c = code_append($$.c, $5.c);
1925 $$.c = j2->branch = abc_label($$.c);
1926 $$.t = join_types($3.t,$5.t,'?');
1929 // TODO: use inclocal where appropriate
1930 E : E "++" { code_t*c = 0;
1931 classinfo_t*type = $1.t;
1932 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1933 c=abc_increment_i(c);
1939 c=converttype(c, type, $1.t);
1940 $$.c = toreadwrite($1.c, c, 0, 1);
1943 E : E "--" { code_t*c = 0;
1944 classinfo_t*type = $1.t;
1945 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1946 c=abc_decrement_i(c);
1952 c=converttype(c, type, $1.t);
1953 $$.c = toreadwrite($1.c, c, 0, 1);
1957 E : "++" %prec plusplus_prefix E { code_t*c = 0;
1958 classinfo_t*type = $2.t;
1959 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1960 c=abc_increment_i(c);
1966 c=converttype(c, type, $2.t);
1967 $$.c = toreadwrite($2.c, c, 0, 0);
1971 E : "--" %prec minusminus_prefix E { code_t*c = 0;
1972 classinfo_t*type = $2.t;
1973 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1974 c=abc_decrement_i(c);
1980 c=converttype(c, type, $2.t);
1981 $$.c = toreadwrite($2.c, c, 0, 0);
1985 E : E '.' T_IDENTIFIER
1987 classinfo_t*t = $1.t;
1989 if(TYPE_IS_CLASS(t)) {
1990 memberinfo_t*m = registry_findmember($1.t, "prototype");
1991 if(!m) syntaxerror("identifier '%s' not found in anonymous class", $3);
1996 memberinfo_t*f = registry_findmember(t, $3);
1998 if(f && !is_static != !(f->flags&FLAG_STATIC))
2001 if(f && f->slot && !noslot) {
2002 $$.c = abc_getslot($$.c, f->slot);
2005 namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
2006 multiname_t m = {QNAME, &ns, 0, $3};
2007 $$.c = abc_getproperty2($$.c, &m);
2009 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2010 $$.c = abc_getproperty2($$.c, &m);
2013 /* determine type */
2015 if(f->kind == MEMBER_METHOD) {
2016 $$.t = TYPE_FUNCTION(f);
2021 $$.c = abc_coerce_a($$.c);
2022 $$.t = registry_getanytype();
2025 /* when resolving a property on an unknown type, we do know the
2026 name of the property (and don't seem to need the package), but
2027 we do need to make avm2 try out all access modes */
2028 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2029 $$.c = abc_getproperty2($$.c, &m);
2030 $$.c = abc_coerce_a($$.c);
2031 $$.t = registry_getanytype();
2035 VAR_READ : T_IDENTIFIER {
2042 /* look at variables */
2043 if((i = find_variable($1, &$$.t)) >= 0) {
2044 // $1 is a local variable
2045 $$.c = abc_getlocal($$.c, i);
2047 /* look at current class' members */
2048 } else if((f = registry_findmember(state->clsinfo, $1))) {
2049 // $1 is a function in this class
2050 int var_is_static = (f->flags&FLAG_STATIC);
2051 int i_am_static = (state->minfo?(state->minfo->flags&FLAG_STATIC):FLAG_STATIC);
2052 if(var_is_static != i_am_static) {
2053 /* there doesn't seem to be any "static" way to access
2054 static properties of a class */
2055 state->late_binding = 1;
2057 namespace_t ns = {flags2access(f->flags), ""};
2058 multiname_t m = {QNAME, &ns, 0, $1};
2059 $$.c = abc_findpropstrict2($$.c, &m);
2060 $$.c = abc_getproperty2($$.c, &m);
2063 $$.c = abc_getlocal_0($$.c);
2064 $$.c = abc_getslot($$.c, f->slot);
2066 namespace_t ns = {flags2access(f->flags), ""};
2067 multiname_t m = {QNAME, &ns, 0, $1};
2068 $$.c = abc_getlocal_0($$.c);
2069 $$.c = abc_getproperty2($$.c, &m);
2072 if(f->kind == MEMBER_METHOD) {
2073 $$.t = TYPE_FUNCTION(f);
2078 /* look at classes in the current package and imported classes */
2079 } else if((a = find_class($1))) {
2081 $$.c = abc_getglobalscope($$.c);
2082 $$.c = abc_getslot($$.c, a->slot);
2085 $$.c = abc_getlex2($$.c, &m);
2087 $$.t = TYPE_CLASS(a);
2089 /* unknown object, let the avm2 resolve it */
2091 if(strcmp($1,"trace"))
2092 warning("Couldn't resolve %s, doing late binding", $1);
2093 state->late_binding = 1;
2095 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2098 $$.c = abc_findpropstrict2($$.c, &m);
2099 $$.c = abc_getproperty2($$.c, &m);
2104 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2105 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2106 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2108 // ----------------- namespaces -------------------------------------------------
2110 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2111 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2112 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2114 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER