3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
30 #include "tokenizer.h"
42 enum yytokentype token;
45 classinfo_t*classinfo;
46 classinfo_list_t*classinfo_list;
49 unsigned int number_uint;
53 typedcode_list_t*value_list;
62 %token<id> T_IDENTIFIER
64 %token<token> T_REGEXP
66 %token<number_int> T_INT
67 %token<number_uint> T_UINT
68 %token<number_uint> T_BYTE
69 %token<number_uint> T_SHORT
70 %token<number_float> T_FLOAT
72 %token<token> KW_IMPLEMENTS
73 %token<token> KW_NAMESPACE "namespace"
74 %token<token> KW_PACKAGE "package"
75 %token<token> KW_PROTECTED
76 %token<token> KW_PUBLIC
77 %token<token> KW_PRIVATE
78 %token<token> KW_USE "use"
79 %token<token> KW_INTERNAL
80 %token<token> KW_NEW "new"
81 %token<token> KW_NATIVE
82 %token<token> KW_FUNCTION "function"
83 %token<token> KW_FOR "for"
84 %token<token> KW_CLASS "class"
85 %token<token> KW_CONST "const"
86 %token<token> KW_SET "set"
87 %token<token> KW_STATIC
88 %token<token> KW_IMPORT "import"
89 %token<token> KW_RETURN "return"
90 %token<token> KW_INTERFACE "interface"
91 %token<token> KW_NULL "null"
92 %token<token> KW_VAR "var"
93 %token<token> KW_DYNAMIC
94 %token<token> KW_OVERRIDE
95 %token<token> KW_FINAL
96 %token<token> KW_GET "get"
97 %token<token> KW_EXTENDS
98 %token<token> KW_FALSE "false"
99 %token<token> KW_TRUE "true"
100 %token<token> KW_BOOLEAN "Boolean"
101 %token<token> KW_UINT "uint"
102 %token<token> KW_INT "int"
103 %token<token> KW_WHILE "while"
104 %token<token> KW_NUMBER "Number"
105 %token<token> KW_STRING "String"
106 %token<token> KW_IF "if"
107 %token<token> KW_ELSE "else"
108 %token<token> KW_BREAK "break"
109 %token<token> KW_IS "is"
110 %token<token> KW_AS "as"
112 %token<token> T_EQEQ "=="
113 %token<token> T_EQEQEQ "==="
114 %token<token> T_NE "!="
115 %token<token> T_LE "<="
116 %token<token> T_GE ">="
117 %token<token> T_DIVBY "/="
118 %token<token> T_MODBY "%="
119 %token<token> T_MULBY "*="
120 %token<token> T_PLUSBY "+="
121 %token<token> T_MINUSBY "-="
122 %token<token> T_SHRBY ">>="
123 %token<token> T_SHLBY "<<="
124 %token<token> T_USHRBY ">>>="
125 %token<token> T_OROR "||"
126 %token<token> T_ANDAND "&&"
127 %token<token> T_COLONCOLON "::"
128 %token<token> T_MINUSMINUS "--"
129 %token<token> T_PLUSPLUS "++"
130 %token<token> T_DOTDOT ".."
131 %token<token> T_DOTDOTDOT "..."
132 %token<token> T_SHL "<<"
133 %token<token> T_USHR ">>>"
134 %token<token> T_SHR ">>"
135 %token<token> T_SEMICOLON ';'
136 %token<token> T_STAR '*'
137 %token<token> T_DOT '.'
139 %type <id> X_IDENTIFIER PACKAGE
140 %type <token> VARCONST
142 %type <code> CODEPIECE
143 %type <code> CODEBLOCK MAYBECODE
144 %type <token> PACKAGE_DECLARATION
145 %type <token> FUNCTION_DECLARATION
146 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
147 %type <token> CLASS_DECLARATION
148 %type <token> NAMESPACE_DECLARATION
149 %type <token> INTERFACE_DECLARATION
150 %type <code> VOIDEXPRESSION
151 %type <value> EXPRESSION NONCOMMAEXPRESSION
152 %type <value> MAYBEEXPRESSION
154 %type <value> CONSTANT
155 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
156 %type <token> USE_NAMESPACE
157 %type <code> FOR_INIT
159 %type <classinfo> MAYBETYPE
162 %type <params> PARAM_LIST
163 %type <params> MAYBE_PARAM_LIST
164 %type <flags> MAYBE_MODIFIERS
165 %type <flags> MODIFIER_LIST
166 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
167 %type <classinfo_list> IMPLEMENTS_LIST
168 %type <classinfo> EXTENDS
169 %type <classinfo_list> EXTENDS_LIST
170 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
171 %type <classinfo_list> QNAME_LIST
172 %type <classinfo> TYPE
174 //%type <token> VARIABLE
175 %type <value> VAR_READ
177 //%type <token> T_IDENTIFIER
178 %type <token> MODIFIER
179 %type <value> FUNCTIONCALL
180 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
182 // precedence: from low to high
183 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
187 %right '=' "/=" "%=" "*=" "+=" "-=" ">>=" "<<=" ">>>="
193 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
195 %left prec_belowminus
210 %nonassoc T_IDENTIFIER
211 %left below_semicolon
216 // needed for "return" precedence:
217 %nonassoc T_STRING T_REGEXP
218 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
219 %nonassoc "new" "false" "true" "null"
226 static int yyerror(char*s)
228 syntaxerror("%s", s);
230 static char* concat3str(const char* t1, const char* t2, const char* t3)
235 char*text = malloc(l1+l2+l3+1);
236 memcpy(text , t1, l1);
237 memcpy(text+l1, t2, l2);
238 memcpy(text+l1+l2, t3, l3);
243 typedef struct _import {
247 DECLARE_LIST(import);
249 typedef struct _state {
257 /* code that needs to be executed at the start of
258 a method (like initializing local registers) */
261 import_list_t*wildcard_imports;
263 char has_own_imports;
269 code_t*cls_static_init;
279 typedef struct _global {
283 static global_t*global = 0;
284 static state_t* state = 0;
288 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
290 /* warning: list length of namespace set is undefined */
291 #define MULTINAME_LATE(m, access, package) \
292 namespace_t m##_ns = {access, package}; \
293 namespace_set_t m##_nsset; \
294 namespace_list_t m##_l;m##_l.next = 0; \
295 m##_nsset.namespaces = &m##_l; \
296 m##_nsset = m##_nsset; \
297 m##_l.namespace = &m##_ns; \
298 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
300 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
301 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
302 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
303 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
304 static namespace_list_t nl4 = {&ns4,0};
305 static namespace_list_t nl3 = {&ns3,&nl4};
306 static namespace_list_t nl2 = {&ns2,&nl3};
307 static namespace_list_t nl1 = {&ns1,&nl2};
308 static namespace_set_t nopackage_namespace_set = {&nl1};
310 static state_list_t*state_stack=0;
312 static void init_globals()
314 global = rfx_calloc(sizeof(global_t));
317 static void new_state()
320 NEW(state_list_t, sl);
322 state_t*oldstate = state;
324 memcpy(s, state, sizeof(state_t)); //shallow copy
325 sl->next = state_stack;
328 s->imports = dict_new();
333 state->vars = dict_new();
335 state->has_own_imports = 0;
337 static void state_has_imports()
339 state->wildcard_imports = list_clone(state->wildcard_imports);
340 state->imports = dict_clone(state->imports);
341 state->has_own_imports = 1;
344 static void old_state()
346 if(!state_stack || !state_stack->next)
347 syntaxerror("invalid nesting");
348 state_t*oldstate = state;
349 state_list_t*old = state_stack;
350 state_stack = state_stack->next;
352 state = state_stack->state;
353 /*if(state->initcode) {
354 printf("residual initcode\n");
355 code_dump(state->initcode, 0, 0, "", stdout);
357 if(oldstate->has_own_imports) {
358 list_free(oldstate->wildcard_imports);
359 dict_destroy(oldstate->imports);oldstate->imports=0;
361 state->initcode = code_append(state->initcode, oldstate->initcode);
363 void initialize_state()
368 state->file = abc_file_new();
369 state->file->flags &= ~ABCFILE_LAZY;
371 state->init = abc_initscript(state->file, 0);
372 code_t*c = state->init->method->body->code;
374 c = abc_getlocal_0(c);
375 c = abc_pushscope(c);
377 /* findpropstrict doesn't just return a scope object- it
378 also makes it "active" somehow. Push local_0 on the
379 scope stack and read it back with findpropstrict, it'll
380 contain properties like "trace". Trying to find the same
381 property on a "vanilla" local_0 yields only a "undefined" */
382 //c = abc_findpropstrict(c, "[package]::trace");
384 /*c = abc_getlocal_0(c);
385 c = abc_findpropstrict(c, "[package]::trace");
387 c = abc_setlocal_1(c);
389 c = abc_pushbyte(c, 0);
390 c = abc_setlocal_2(c);
392 code_t*xx = c = abc_label(c);
393 c = abc_findpropstrict(c, "[package]::trace");
394 c = abc_pushstring(c, "prop:");
395 c = abc_hasnext2(c, 1, 2);
397 c = abc_setlocal_3(c);
398 c = abc_callpropvoid(c, "[package]::trace", 2);
399 c = abc_getlocal_3(c);
401 c = abc_iftrue(c,xx);*/
403 c = abc_findpropstrict(c, "[package]::trace");
404 c = abc_pushstring(c, "[entering global init function]");
405 c = abc_callpropvoid(c, "[package]::trace", 1);
407 state->init->method->body->code = c;
409 void* finalize_state()
411 if(state->level!=1) {
412 syntaxerror("unexpected end of file");
414 abc_method_body_t*m = state->init->method->body;
417 __ findpropstrict(m, "[package]::trace");
418 __ pushstring(m, "[leaving global init function]");
419 __ callpropvoid(m, "[package]::trace", 1);
425 static void startpackage(char*name)
428 syntaxerror("Packages can not be nested.");
431 /*printf("entering package \"%s\"\n", name);*/
432 state->package = name;
434 static void endpackage()
436 /*printf("leaving package \"%s\"\n", state->package);*/
441 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
444 syntaxerror("inner classes now allowed");
449 classinfo_list_t*mlist=0;
450 /*printf("entering class %s\n", name);
451 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
453 printf(" extends: %s.%s\n", extends->package, extends->name);
454 printf(" implements (%d): ", list_length(implements));
455 for(mlist=implements;mlist;mlist=mlist->next) {
456 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
461 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
462 syntaxerror("invalid modifier(s)");
464 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
465 syntaxerror("public and internal not supported at the same time.");
467 /* create the class name, together with the proper attributes */
471 if(!(flags&FLAG_PUBLIC) && !state->package) {
472 access = ACCESS_PRIVATE; package = current_filename;
473 } else if(!(flags&FLAG_PUBLIC) && state->package) {
474 access = ACCESS_PACKAGEINTERNAL; package = state->package;
475 } else if(state->package) {
476 access = ACCESS_PACKAGE; package = state->package;
478 syntaxerror("public classes only allowed inside a package");
481 if(registry_findclass(package, classname)) {
482 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
485 /* build info struct */
486 int num_interfaces = (list_length(implements));
487 state->clsinfo = classinfo_register(access, package, classname, num_interfaces);
488 state->clsinfo->superclass = extends;
490 classinfo_list_t*l = implements;
491 for(l=implements;l;l=l->next) {
492 state->clsinfo->interfaces[pos++] = l->classinfo;
495 MULTINAME(classname2,state->clsinfo);
497 multiname_t*extends2 = sig2mname(extends);
500 state->cls_init = abc_getlocal_0(state->cls_init);
501 state->cls_init = abc_constructsuper(state->cls_init, 0);
504 state->cls = abc_class_new(state->file, &classname2, extends2);
505 if(flags&FLAG_FINAL) abc_class_final(state->cls);
506 if(flags&FLAG_DYNAMIC) abc_class_sealed(state->cls);
507 if(interface) abc_class_interface(state->cls);
509 for(mlist=implements;mlist;mlist=mlist->next) {
510 MULTINAME(m, mlist->classinfo);
511 abc_class_add_interface(state->cls, &m);
514 /* now write the construction code for this class */
515 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
517 abc_method_body_t*m = state->init->method->body;
518 __ getglobalscope(m);
519 classinfo_t*s = extends;
524 //TODO: take a look at the current scope stack, maybe
525 // we can re-use something
530 multiname_t*s2 = sig2mname(s);
532 multiname_destroy(s2);
534 __ pushscope(m); count++;
535 m->code = m->code->prev->prev; // invert
537 /* continue appending after last op end */
538 while(m->code && m->code->next) m->code = m->code->next;
540 /* TODO: if this is one of *our* classes, we can also
541 do a getglobalscope/getslot <nr> (which references
542 the init function's slots) */
544 __ getlex2(m, extends2);
546 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
547 stack is not the superclass */
548 __ pushscope(m);count++;
551 /* notice: we get a verify error #1107 if the top element on the scope
552 stack is not the global object */
554 __ pushscope(m);count++;
556 __ newclass(m,state->cls);
560 __ setslot(m, slotindex);
562 /* flash.display.MovieClip handling */
563 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
564 if(state->package && state->package[0]) {
565 globalclass = concat3str(state->package, ".", classname);
567 globalclass = strdup(classname);
570 multiname_destroy(extends2);
573 static void endclass()
575 if(state->cls_init) {
576 if(!state->cls->constructor) {
577 abc_method_t*m = abc_class_constructor(state->cls, 0);
578 m->body->code = code_append(m->body->code, state->cls_init);
579 m->body->code = abc_returnvoid(m->body->code);
581 code_t*c = state->cls->constructor->body->code;
582 c = code_append(state->cls_init, c);
583 state->cls->constructor->body->code = c;
587 if(state->cls_static_init) {
588 if(!state->cls->static_constructor) {
589 abc_method_t*m = abc_class_staticconstructor(state->cls, 0);
590 m->body->code = code_append(m->body->code, state->cls_static_init);
591 m->body->code = abc_returnvoid(m->body->code);
593 state->cls->static_constructor->body->code =
594 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
601 typedef struct _variable {
606 static int find_variable(char*name, classinfo_t**m)
608 state_list_t* s = state_stack;
610 variable_t*v = dict_lookup(s->state->vars, name);
621 static int find_variable_safe(char*name, classinfo_t**m)
623 int i = find_variable(name, m);
625 syntaxerror("undefined variable: %s", name);
628 static char variable_exists(char*name)
630 return dict_lookup(state->vars, name)!=0;
632 static int new_variable(char*name, classinfo_t*type)
635 v->index = global->variable_count;
637 dict_put(state->vars, name, v);
638 return global->variable_count++;
640 #define TEMPVARNAME "__as3_temp__"
641 static int gettempvar()
643 int i = find_variable(TEMPVARNAME, 0);
645 return new_variable(TEMPVARNAME, 0);
651 code_t* killvars(code_t*c)
654 for(t=0;t<state->vars->hashsize;t++) {
655 dictentry_t*e =state->vars->slots[t];
657 variable_t*v = (variable_t*)e->data;
658 //do this always, otherwise register types don't match
659 //in the verifier when doing nested loops
660 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
661 c = abc_kill(c, v->index);
669 static void check_constant_against_type(classinfo_t*t, constant_t*c)
671 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
672 if(TYPE_IS_NUMBER(t)) {
673 xassert(c->type == CONSTANT_FLOAT
674 || c->type == CONSTANT_INT
675 || c->type == CONSTANT_UINT);
676 } else if(TYPE_IS_UINT(t)) {
677 xassert(c->type == CONSTANT_UINT ||
678 (c->type == CONSTANT_INT && c->i>0));
679 } else if(TYPE_IS_INT(t)) {
680 xassert(c->type == CONSTANT_INT);
681 } else if(TYPE_IS_BOOLEAN(t)) {
682 xassert(c->type == CONSTANT_TRUE
683 || c->type == CONSTANT_FALSE);
687 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
689 memberinfo_t*minfo = 0;
690 if(getset != KW_GET && getset != KW_SET) {
691 if(registry_findmember(state->clsinfo, name)) {
692 syntaxerror("class already contains a member/method called '%s'", name);
694 minfo = memberinfo_register(state->clsinfo, name, MEMBER_METHOD);
695 minfo->return_type = return_type;
696 // getslot on a member slot only returns "undefined", so no need
697 // to actually store these
698 //state->minfo->slot = state->m->method->trait->slot_id;
700 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
704 else if(params->list)
705 type = params->list->param->type;
706 if((minfo=registry_findmember(state->clsinfo, name))) {
707 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
708 syntaxerror("class already contains a member or method called '%s'", name);
710 syntaxerror("getter/setter for '%s' already defined", name);
711 /* make a setter or getter into a getset */
716 if(type && minfo->type != type)
717 syntaxerror("different type in getter and setter");
719 minfo = memberinfo_register(state->clsinfo, name, gs);
722 /* can't assign a slot as getter and setter might have different slots */
723 //minfo->slot = slot;
725 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
726 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
727 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
728 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
729 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
733 static int flags2access(int flags)
736 if(flags&FLAG_PUBLIC) {
737 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
738 access = ACCESS_PACKAGE;
739 } else if(flags&FLAG_PRIVATE) {
740 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
741 access = ACCESS_PRIVATE;
742 } else if(flags&FLAG_PROTECTED) {
743 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
744 access = ACCESS_PROTECTED;
746 access = ACCESS_PACKAGEINTERNAL;
751 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
752 params_t*params, classinfo_t*return_type)
756 global->variable_count = 0;
757 state->function = name;
760 syntaxerror("not able to start another method scope");
763 namespace_t mname_ns = {flags2access(flags), ""};
764 multiname_t mname = {QNAME, &mname_ns, 0, name};
766 multiname_t*type2 = sig2mname(return_type);
767 if(!strcmp(state->clsinfo->name,name)) {
768 state->m = abc_class_constructor(state->cls, type2);
770 if(flags&FLAG_STATIC)
771 state->m = abc_class_staticmethod(state->cls, type2, &mname);
773 state->m = abc_class_method(state->cls, type2, &mname);
774 int slot = state->m->trait->slot_id;
775 state->minfo = registerfunction(getset, flags, name, params, return_type, slot);
778 if(getset == KW_GET) state->m->trait->kind = TRAIT_GETTER;
779 if(getset == KW_SET) state->m->trait->kind = TRAIT_SETTER;
780 if(params->varargs) state->m->flags |= METHOD_NEED_REST;
784 for(p=params->list;p;p=p->next) {
785 if(params->varargs && !p->next) {
786 break; //varargs: omit last parameter in function signature
788 multiname_t*m = sig2mname(p->param->type);
789 list_append(state->m->parameters, m);
790 if(p->param->value) {
791 check_constant_against_type(p->param->type, p->param->value);
792 opt=1;list_append(state->m->optional_parameters, p->param->value);
794 syntaxerror("non-optional parameter not allowed after optional parameters");
798 /* state->vars is initialized by state_new */
799 if(new_variable("this", state->clsinfo)!=0) syntaxerror("Internal error");
801 for(p=params->list;p;p=p->next) {
802 new_variable(p->param->name, p->param->type);
805 static void endfunction(code_t*body)
808 if(!(state->cls->flags & CLASS_INTERFACE)) {
810 if(state->late_binding) {
811 c = abc_getlocal_0(c);
812 c = abc_pushscope(c);
814 c = code_append(c, state->initcode);
815 c = code_append(c, body);
817 /* append return if necessary */
818 if(!c || c->opcode != OPCODE_RETURNVOID &&
819 c->opcode != OPCODE_RETURNVALUE) {
820 c = abc_returnvoid(c);
822 if(state->m->body->code) syntaxerror("internal error");
823 state->m->body->code = c;
830 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
835 void breakjumpsto(code_t*c, code_t*jump)
840 if(c->opcode == OPCODE___BREAK__) {
841 c->opcode = OPCODE_JUMP;
848 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
851 return registry_getanytype();
852 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
853 return registry_getanytype();
856 return registry_getanytype();
858 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
863 return abc_coerce_a(c);
867 // cast an "any" type to a specific type. subject to
868 // runtime exceptions
869 return abc_coerce2(c, &m);
872 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
873 return abc_coerce2(c, &m);
875 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
876 return abc_coerce2(c, &m);
878 /* these are subject to overflow */
879 if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
880 return abc_coerce2(c, &m);
882 if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
883 return abc_coerce2(c, &m);
886 classinfo_t*supertype = from;
888 if(supertype == to) {
889 // target type is one of from's superclasses
890 return abc_coerce2(c, &m);
893 while(supertype->interfaces[t]) {
894 if(supertype->interfaces[t]==to) {
895 // to type is one of from's interfaces
896 return abc_coerce2(c, &m);
900 supertype = supertype->superclass;
902 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
904 syntaxerror("can't convert type %s to %s", from->name, to->name);
907 code_t*defaultvalue(code_t*c, classinfo_t*type)
909 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
910 c = abc_pushbyte(c, 0);
911 } else if(TYPE_IS_BOOLEAN(type)) {
912 c = abc_pushfalse(c);
919 char is_pushundefined(code_t*c)
921 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
924 void parserassert(int b)
926 if(!b) syntaxerror("internal error: assertion failed");
929 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
933 [prefix code] [read instruction]
937 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
940 if(in && in->opcode == OPCODE_COERCE_A) {
941 in = code_cutlast(in);
944 syntaxerror("internal error");
946 /* chop off read instruction */
950 prefix = r->prev;r->prev = 0;
956 char use_temp_var = readbefore;
958 /* generate the write instruction, and maybe append a dup to the prefix code */
959 code_t* write = abc_nop(0);
960 if(r->opcode == OPCODE_GETPROPERTY) {
961 write->opcode = OPCODE_SETPROPERTY;
962 multiname_t*m = (multiname_t*)r->data[0];
963 write->data[0] = multiname_clone(m);
964 if(m->type != QNAME && m->type != MULTINAME)
965 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
967 prefix = abc_dup(prefix); // we need the object, too
970 } else if(r->opcode == OPCODE_GETSLOT) {
971 write->opcode = OPCODE_SETSLOT;
972 write->data[0] = r->data[0];
974 prefix = abc_dup(prefix); // we need the object, too
977 } else if(r->opcode == OPCODE_GETLOCAL) {
978 write->opcode = OPCODE_SETLOCAL;
979 write->data[0] = r->data[0];
980 } else if(r->opcode == OPCODE_GETLOCAL_0) {
981 write->opcode = OPCODE_SETLOCAL_0;
982 } else if(r->opcode == OPCODE_GETLOCAL_1) {
983 write->opcode = OPCODE_SETLOCAL_1;
984 } else if(r->opcode == OPCODE_GETLOCAL_2) {
985 write->opcode = OPCODE_SETLOCAL_2;
986 } else if(r->opcode == OPCODE_GETLOCAL_3) {
987 write->opcode = OPCODE_SETLOCAL_3;
989 code_dump(r, 0, 0, "", stdout);
990 syntaxerror("illegal lvalue: can't assign a value to this expression");
997 /* with getproperty/getslot, we have to be extra careful not
998 to execute the read code twice, as it might have side-effects
999 (e.g. if the property is in fact a setter/getter combination)
1001 So read the value, modify it, and write it again,
1002 using prefix only once and making sure (by using a temporary
1003 register) that the return value is what we just wrote */
1004 temp = gettempvar();
1005 c = code_append(c, prefix);
1006 c = code_append(c, r);
1009 c = abc_setlocal(c, temp);
1011 c = code_append(c, middlepart);
1014 c = abc_setlocal(c, temp);
1016 c = code_append(c, write);
1017 c = abc_getlocal(c, temp);
1018 c = abc_kill(c, temp);
1020 /* if we're allowed to execute the read code twice *and*
1021 the middlepart doesn't modify the code, things are easier.
1023 code_t* r2 = code_dup(r);
1024 //c = code_append(c, prefix);
1025 parserassert(!prefix);
1026 c = code_append(c, r);
1027 c = code_append(c, middlepart);
1028 c = code_append(c, write);
1029 c = code_append(c, r2);
1032 /* even smaller version: overwrite the value without reading
1036 c = code_append(c, prefix);
1039 c = code_append(c, middlepart);
1040 c = code_append(c, write);
1041 c = code_append(c, r);
1043 temp = gettempvar();
1045 c = code_append(c, prefix);
1048 c = code_append(c, middlepart);
1050 c = abc_setlocal(c, temp);
1051 c = code_append(c, write);
1052 c = abc_getlocal(c, temp);
1065 /* ------------ code blocks / statements ---------------- */
1069 MAYBECODE: CODE {$$=$1;}
1070 MAYBECODE: {$$=code_new();}
1072 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1073 CODE: CODEPIECE {$$=$1;}
1075 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1076 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1077 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1078 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1079 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1080 CODEPIECE: ';' {$$=code_new();}
1081 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1082 CODEPIECE: VOIDEXPRESSION {$$=$1}
1083 CODEPIECE: FOR {$$=$1}
1084 CODEPIECE: WHILE {$$=$1}
1085 CODEPIECE: BREAK {$$=$1}
1086 CODEPIECE: RETURN {$$=$1}
1087 CODEPIECE: IF {$$=$1}
1088 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1089 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1091 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1092 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1093 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1095 /* ------------ variables --------------------------- */
1097 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1098 | {$$.c=abc_pushundefined(0);
1102 VAR : "const" | "var"
1103 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1105 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1106 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1108 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1110 if(variable_exists($2))
1111 syntaxerror("Variable %s already defined", $2);
1113 if(!is_subtype_of($4.t, $3)) {
1114 syntaxerror("Can't convert %s to %s", $4.t->name,
1118 int index = new_variable($2, $3);
1121 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1123 $$ = converttype($$, $4.t, $3);
1124 $$ = abc_setlocal($$, index);
1126 $$ = defaultvalue(0, $3);
1127 $$ = abc_setlocal($$, index);
1130 /* if this is a typed variable:
1131 push default value for type on stack */
1133 state->initcode = defaultvalue(state->initcode, $3);
1134 state->initcode = abc_setlocal(state->initcode, index);
1137 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1139 $$ = abc_coerce_a($$);
1140 $$ = abc_setlocal($$, index);
1146 /* that's the default for a local register, anyway
1148 state->initcode = abc_pushundefined(state->initcode);
1149 state->initcode = abc_setlocal(state->initcode, index);
1151 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1154 /* ------------ control flow ------------------------- */
1156 MAYBEELSE: %prec prec_none {$$ = code_new();}
1157 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1158 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1160 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1161 $$ = state->initcode;state->initcode=0;
1163 $$ = code_append($$, $4.c);
1164 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1166 $$ = code_append($$, $6);
1168 myjmp = $$ = abc_jump($$, 0);
1170 myif->branch = $$ = abc_label($$);
1172 $$ = code_append($$, $7);
1173 myjmp->branch = $$ = abc_label($$);
1176 $$ = killvars($$);old_state();
1179 FOR_INIT : {$$=code_new();}
1180 FOR_INIT : VARIABLE_DECLARATION
1181 FOR_INIT : VOIDEXPRESSION
1183 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1184 $$ = state->initcode;state->initcode=0;
1186 $$ = code_append($$, $4);
1187 code_t*loopstart = $$ = abc_label($$);
1188 $$ = code_append($$, $6.c);
1189 code_t*myif = $$ = abc_iffalse($$, 0);
1190 $$ = code_append($$, $10);
1191 $$ = code_append($$, $8);
1192 $$ = abc_jump($$, loopstart);
1193 code_t*out = $$ = abc_label($$);
1194 breakjumpsto($$, out);
1197 $$ = killvars($$);old_state();
1200 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1201 $$ = state->initcode;state->initcode=0;
1203 code_t*myjmp = $$ = abc_jump($$, 0);
1204 code_t*loopstart = $$ = abc_label($$);
1205 $$ = code_append($$, $6);
1206 myjmp->branch = $$ = abc_label($$);
1207 $$ = code_append($$, $4.c);
1208 $$ = abc_iftrue($$, loopstart);
1209 code_t*out = $$ = abc_label($$);
1210 breakjumpsto($$, out);
1212 $$ = killvars($$);old_state();
1216 $$ = abc___break__(0);
1219 /* ------------ packages and imports ---------------- */
1221 X_IDENTIFIER: T_IDENTIFIER
1222 | "package" {$$="package";}
1224 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1225 PACKAGE: X_IDENTIFIER {$$=$1;}
1227 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1228 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1230 IMPORT : "import" QNAME {
1233 syntaxerror("Couldn't import class\n");
1234 state_has_imports();
1235 dict_put(state->imports, c->name, c);
1238 IMPORT : "import" PACKAGE '.' '*' {
1241 state_has_imports();
1242 list_append(state->wildcard_imports, i);
1246 /* ------------ classes and interfaces (header) -------------- */
1248 MAYBE_MODIFIERS : {$$=0;}
1249 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1250 MODIFIER_LIST : MODIFIER {$$=$1;}
1251 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1253 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1254 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1255 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1256 | KW_STATIC {$$=FLAG_STATIC;}
1257 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1258 | KW_FINAL {$$=FLAG_FINAL;}
1259 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1260 | KW_NATIVE {$$=FLAG_NATIVE;}
1261 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1263 EXTENDS : {$$=registry_getobjectclass();}
1264 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1266 EXTENDS_LIST : {$$=list_new();}
1267 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1269 IMPLEMENTS_LIST : {$$=list_new();}
1270 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1272 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1273 EXTENDS IMPLEMENTS_LIST
1274 '{' {startclass($1,$3,$4,$5, 0);}
1275 MAYBE_DECLARATION_LIST
1278 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1280 '{' {startclass($1,$3,0,$4,1);}
1281 MAYBE_IDECLARATION_LIST
1284 /* ------------ classes and interfaces (body) -------------- */
1286 MAYBE_DECLARATION_LIST :
1287 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1288 DECLARATION_LIST : DECLARATION
1289 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1291 DECLARATION : SLOT_DECLARATION
1292 DECLARATION : FUNCTION_DECLARATION
1294 MAYBE_IDECLARATION_LIST :
1295 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1296 IDECLARATION_LIST : IDECLARATION
1297 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1299 IDECLARATION : "var" T_IDENTIFIER {
1300 syntaxerror("variable declarations not allowed in interfaces");
1302 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1304 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1305 syntaxerror("invalid method modifiers: interface methods always need to be public");
1307 startfunction(0,$1,$3,$4,&$6,$8);
1311 /* ------------ classes and interfaces (body, slots ) ------- */
1313 VARCONST: "var" | "const"
1315 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1317 memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
1319 info->flags = flags;
1322 namespace_t mname_ns = {flags2access(flags), ""};
1323 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1325 if(!(flags&FLAG_STATIC)) {
1328 t=abc_class_slot(state->cls, &mname, &m);
1329 info->slot = t->slot_id;
1331 t=abc_class_slot(state->cls, &mname, 0);
1336 t=abc_class_staticslot(state->cls, &mname, &m);
1337 //info->slot = t->slot_id;
1339 t=abc_class_staticslot(state->cls, &mname, 0);
1342 if($5.c && !is_pushundefined($5.c)) {
1344 c = abc_getlocal_0(c);
1345 c = code_append(c, $5.c);
1346 c = converttype(c, $5.t, $4);
1347 c = abc_setslot(c, t->slot_id);
1348 if(!(flags&FLAG_STATIC))
1349 state->cls_init = code_append(state->cls_init, c);
1351 state->cls_static_init = code_append(state->cls_static_init, c);
1354 t->kind= TRAIT_CONST;
1358 /* ------------ constants -------------------------------------- */
1360 MAYBESTATICCONSTANT: {$$=0;}
1361 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1363 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1364 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1365 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1366 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1367 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1368 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1369 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1370 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1371 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1373 /* ------------ classes and interfaces (body, functions) ------- */
1375 // non-vararg version
1377 memset(&$$,0,sizeof($$));
1379 MAYBE_PARAM_LIST: PARAM_LIST {
1384 MAYBE_PARAM_LIST: "..." PARAM {
1385 memset(&$$,0,sizeof($$));
1387 list_append($$.list, $2);
1389 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1392 list_append($$.list, $4);
1396 PARAM_LIST: PARAM_LIST ',' PARAM {
1398 list_append($$.list, $3);
1401 memset(&$$,0,sizeof($$));
1402 list_append($$.list, $1);
1405 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1406 $$ = malloc(sizeof(param_t));
1411 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1412 $$ = malloc(sizeof(param_t));
1414 $$->type = TYPE_ANY;
1417 GETSET : "get" {$$=$1;}
1421 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1422 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1424 if(!state->m) syntaxerror("internal error: undefined function");
1428 /* ------------- package + class ids --------------- */
1430 CLASS: T_IDENTIFIER {
1432 /* try current package */
1433 $$ = registry_findclass(state->package, $1);
1435 /* try explicit imports */
1436 dictentry_t* e = dict_get_slot(state->imports, $1);
1440 if(!strcmp(e->key, $1)) {
1441 $$ = (classinfo_t*)e->data;
1446 /* try package.* imports */
1447 import_list_t*l = state->wildcard_imports;
1451 //printf("does package %s contain a class %s?\n", l->import->package, $1);
1452 $$ = registry_findclass(l->import->package, $1);
1456 /* try global package */
1458 $$ = registry_findclass("", $1);
1461 if(!$$) syntaxerror("Could not find class %s\n", $1);
1464 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1465 $$ = registry_findclass($1, $3);
1466 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1469 QNAME: PACKAGEANDCLASS
1472 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1473 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1475 TYPE : QNAME {$$=$1;}
1476 | '*' {$$=registry_getanytype();}
1477 | "String" {$$=registry_getstringclass();}
1478 | "int" {$$=registry_getintclass();}
1479 | "uint" {$$=registry_getuintclass();}
1480 | "Boolean" {$$=registry_getbooleanclass();}
1481 | "Number" {$$=registry_getnumberclass();}
1483 MAYBETYPE: ':' TYPE {$$=$2;}
1486 /* ----------function calls, constructor calls ------ */
1488 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1489 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1491 MAYBE_EXPRESSION_LIST : {$$=0;}
1492 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1493 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1494 typedcode_t*t = malloc(sizeof(typedcode_t));
1496 list_append($$, t);}
1497 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1498 typedcode_t*t = malloc(sizeof(typedcode_t));
1500 list_append($$, t);}
1502 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1506 /* TODO: why do we have to *find* our own classes? */
1507 $$.c = abc_findpropstrict2($$.c, &m);
1509 typedcode_list_t*l = $3;
1512 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1516 $$.c = abc_constructprop2($$.c, &m, len);
1520 /* TODO: use abc_call (for calling local variables),
1521 abc_callstatic (for calling own methods)
1524 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1525 typedcode_list_t*l = $3;
1527 code_t*paramcode = 0;
1529 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1535 if($$.c->opcode == OPCODE_COERCE_A) {
1536 $$.c = code_cutlast($$.c);
1540 multiname_t*name = 0;
1541 if($$.c->opcode == OPCODE_GETPROPERTY) {
1542 name = multiname_clone($$.c->data[0]);
1543 $$.c = code_cutlast($$.c);
1544 $$.c = code_append($$.c, paramcode);
1545 $$.c = abc_callproperty2($$.c, name, len);
1546 } else if($$.c->opcode == OPCODE_GETSLOT) {
1547 int slot = (int)(ptroff_t)$$.c->data[0];
1548 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1549 if(t->kind!=TRAIT_METHOD) {
1550 //flash allows to assign closures to members.
1551 //syntaxerror("not a function");
1554 $$.c = code_cutlast($$.c);
1555 $$.c = code_append($$.c, paramcode);
1556 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1557 $$.c = abc_callproperty2($$.c, name, len);
1559 $$.c = abc_getlocal_0($$.c);
1560 $$.c = code_append($$.c, paramcode);
1561 $$.c = abc_call($$.c, len);
1566 if(TYPE_IS_FUNCTION($1.t) &&
1567 (f = registry_findmember($1.t, "call"))) {
1568 $$.t = f->return_type;
1570 $$.c = abc_coerce_a($$.c);
1575 RETURN: "return" %prec prec_none {
1576 $$ = abc_returnvoid(0);
1578 RETURN: "return" EXPRESSION {
1580 $$ = abc_returnvalue($$);
1582 // ----------------------- expression types -------------------------------------
1584 NONCOMMAEXPRESSION : E %prec prec_belowminus {$$=$1;}
1585 EXPRESSION : E %prec prec_belowminus {$$ = $1;}
1586 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1588 $$.c = cut_last_push($$.c);
1589 $$.c = code_append($$.c,$3.c);
1592 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1594 // ----------------------- expression evaluation -------------------------------------
1597 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1599 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1603 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1604 //MULTINAME(m, registry_getintclass());
1605 //$$.c = abc_coerce2($$.c, &m); // FIXME
1608 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1611 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1614 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1617 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1620 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1623 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1624 $$.t = TYPE_BOOLEAN;
1626 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1627 $$.t = TYPE_BOOLEAN;
1629 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1634 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1635 $$.t = TYPE_BOOLEAN;
1637 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1638 $$.t = TYPE_BOOLEAN;
1640 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1641 $$.t = TYPE_BOOLEAN;
1643 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1644 $$.t = TYPE_BOOLEAN;
1646 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1647 $$.t = TYPE_BOOLEAN;
1649 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1650 $$.t = TYPE_BOOLEAN;
1652 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1653 $$.t = TYPE_BOOLEAN;
1656 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1658 $$.c = converttype($$.c, $1.t, $$.t);
1659 $$.c = abc_dup($$.c);
1660 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1661 $$.c = cut_last_push($$.c);
1662 $$.c = code_append($$.c,$3.c);
1663 $$.c = converttype($$.c, $3.t, $$.t);
1664 code_t*label = $$.c = abc_label($$.c);
1665 jmp->branch = label;
1668 $$.t = join_types($1.t, $3.t, 'A');
1669 /*printf("%08x:\n",$1.t);
1670 code_dump($1.c, 0, 0, "", stdout);
1671 printf("%08x:\n",$3.t);
1672 code_dump($3.c, 0, 0, "", stdout);
1673 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1675 $$.c = converttype($$.c, $1.t, $$.t);
1676 $$.c = abc_dup($$.c);
1677 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1678 $$.c = cut_last_push($$.c);
1679 $$.c = code_append($$.c,$3.c);
1680 $$.c = converttype($$.c, $3.t, $$.t);
1681 code_t*label = $$.c = abc_label($$.c);
1682 jmp->branch = label;
1685 E : '!' E {$$.c=$2.c;
1686 $$.c = abc_not($$.c);
1687 $$.t = TYPE_BOOLEAN;
1692 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1693 $$.t = join_types($1.t, $3.t, '+');
1695 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1696 $$.t = join_types($1.t, $3.t, '%');
1698 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1699 $$.t = join_types($1.t, $3.t, '*');
1704 E : '(' E ')' {$$=$2;}
1709 $$.c = code_append($$.c, $3.c);
1711 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1712 $$.c = abc_getproperty2($$.c, &m);
1717 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1718 c=abc_multiply_i(c);
1722 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1723 $$.c = toreadwrite($1.c, c, 0, 0);
1727 code_t*c = abc_modulo($3.c);
1728 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1729 $$.c = toreadwrite($1.c, c, 0, 0);
1733 code_t*c = abc_lshift($3.c);
1734 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1735 $$.c = toreadwrite($1.c, c, 0, 0);
1739 code_t*c = abc_rshift($3.c);
1740 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1741 $$.c = toreadwrite($1.c, c, 0, 0);
1745 code_t*c = abc_urshift($3.c);
1746 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1747 $$.c = toreadwrite($1.c, c, 0, 0);
1751 code_t*c = abc_divide($3.c);
1752 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1753 $$.c = toreadwrite($1.c, c, 0, 0);
1758 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1763 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1765 $$.c = toreadwrite($1.c, c, 0, 0);
1768 E : E "-=" E { code_t*c = $3.c;
1769 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1770 c=abc_subtract_i(c);
1774 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1776 $$.c = toreadwrite($1.c, c, 0, 0);
1779 E : E '=' E { code_t*c = 0;
1780 c = code_append(c, $3.c);
1781 c = converttype(c, $3.t, $1.t);
1782 $$.c = toreadwrite($1.c, c, 1, 0);
1786 // TODO: use inclocal where appropriate
1787 E : E "++" { code_t*c = 0;
1788 classinfo_t*type = $1.t;
1789 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1790 c=abc_increment_i(c);
1796 c=converttype(c, type, $1.t);
1797 $$.c = toreadwrite($1.c, c, 0, 1);
1800 E : E "--" { code_t*c = 0;
1801 classinfo_t*type = $1.t;
1802 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1803 c=abc_decrement_i(c);
1809 c=converttype(c, type, $1.t);
1810 $$.c = toreadwrite($1.c, c, 0, 1);
1814 E : "++" E { code_t*c = 0;
1815 classinfo_t*type = $2.t;
1816 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1817 c=abc_increment_i(c);
1823 c=converttype(c, type, $2.t);
1824 $$.c = toreadwrite($2.c, c, 0, 0);
1828 E : "--" E { code_t*c = 0;
1829 classinfo_t*type = $2.t;
1830 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1831 c=abc_decrement_i(c);
1837 c=converttype(c, type, $2.t);
1838 $$.c = toreadwrite($2.c, c, 0, 0);
1842 E : E '.' T_IDENTIFIER
1845 memberinfo_t*f = registry_findmember($$.t, $3);
1848 $$.c = abc_getslot($$.c, f->slot);
1851 namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
1852 multiname_t m = {QNAME, &ns, 0, $3};
1853 $$.c = abc_getproperty2($$.c, &m);
1855 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1856 $$.c = abc_getproperty2($$.c, &m);
1859 /* determine type */
1861 if(f->kind == MEMBER_METHOD) {
1862 $$.t = TYPE_FUNCTION(f);
1867 $$.c = abc_coerce_a($$.c);
1868 $$.t = registry_getanytype();
1871 /* when resolving a property on an unknown type, we do know the
1872 name of the property (and don't seem to need the package), but
1873 we do need to make avm2 try out all access modes */
1874 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1875 $$.c = abc_getproperty2($$.c, &m);
1876 $$.c = abc_coerce_a($$.c);
1877 $$.t = registry_getanytype();
1881 VAR_READ : T_IDENTIFIER {
1886 if((i = find_variable($1, &$$.t)) >= 0) {
1887 // $1 is a local variable
1888 $$.c = abc_getlocal($$.c, i);
1889 } else if(f = registry_findmember(state->clsinfo, $1)) {
1890 // $1 is a function in this class
1891 if(f->flags&FLAG_STATIC) {
1892 /* there doesn't seem to be any "static" way to access
1893 static properties of a class */
1894 state->late_binding = 1;
1896 namespace_t ns = {flags2access(f->flags), ""};
1897 multiname_t m = {QNAME, &ns, 0, $1};
1898 $$.c = abc_findpropstrict2($$.c, &m);
1899 $$.c = abc_getproperty2($$.c, &m);
1902 $$.c = abc_getlocal_0($$.c);
1903 $$.c = abc_getslot($$.c, f->slot);
1905 namespace_t ns = {flags2access(f->flags), ""};
1906 multiname_t m = {QNAME, &ns, 0, $1};
1907 $$.c = abc_getlocal_0($$.c);
1908 $$.c = abc_getproperty2($$.c, &m);
1911 if(f->kind == MEMBER_METHOD) {
1912 $$.t = TYPE_FUNCTION(f);
1917 // let the avm2 resolve $1
1918 if(strcmp($1,"trace"))
1919 warning("Couldn't resolve %s, doing late binding", $1);
1920 state->late_binding = 1;
1922 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
1925 $$.c = abc_findpropstrict2($$.c, &m);
1926 $$.c = abc_getproperty2($$.c, &m);
1931 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1932 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1933 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1935 // ----------------- namespaces -------------------------------------------------
1937 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
1938 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
1939 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
1941 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER