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<id> T_FOR "for"
73 %token<id> T_WHILE "while"
75 %token<id> T_SWITCH "switch"
77 %token<token> KW_IMPLEMENTS
78 %token<token> KW_NAMESPACE "namespace"
79 %token<token> KW_PACKAGE "package"
80 %token<token> KW_PROTECTED
81 %token<token> KW_PUBLIC
82 %token<token> KW_PRIVATE
83 %token<token> KW_USE "use"
84 %token<token> KW_INTERNAL
85 %token<token> KW_NEW "new"
86 %token<token> KW_NATIVE
87 %token<token> KW_FUNCTION "function"
88 %token<token> KW_UNDEFINED "undefined"
89 %token<token> KW_CONTINUE "continue"
90 %token<token> KW_CLASS "class"
91 %token<token> KW_CONST "const"
92 %token<token> KW_CATCH "catch"
93 %token<token> KW_CASE "case"
94 %token<token> KW_SET "set"
95 %token<token> KW_VOID "void"
96 %token<token> KW_STATIC
97 %token<token> KW_INSTANCEOF "instanceof"
98 %token<token> KW_IMPORT "import"
99 %token<token> KW_RETURN "return"
100 %token<token> KW_TYPEOF "typeof"
101 %token<token> KW_INTERFACE "interface"
102 %token<token> KW_NULL "null"
103 %token<token> KW_VAR "var"
104 %token<token> KW_DYNAMIC "dynamic"
105 %token<token> KW_OVERRIDE
106 %token<token> KW_FINAL
107 %token<token> KW_GET "get"
108 %token<token> KW_TRY "try"
109 %token<token> KW_SUPER "super"
110 %token<token> KW_EXTENDS
111 %token<token> KW_FALSE "false"
112 %token<token> KW_TRUE "true"
113 %token<token> KW_BOOLEAN "Boolean"
114 %token<token> KW_UINT "uint"
115 %token<token> KW_INT "int"
116 %token<token> KW_NUMBER "Number"
117 %token<token> KW_STRING "String"
118 %token<token> KW_DEFAULT "default"
119 %token<token> KW_DELETE "delete"
120 %token<token> KW_IF "if"
121 %token<token> KW_ELSE "else"
122 %token<token> KW_BREAK "break"
123 %token<token> KW_IS "is"
124 %token<token> KW_AS "as"
126 %token<token> T_EQEQ "=="
127 %token<token> T_EQEQEQ "==="
128 %token<token> T_NE "!="
129 %token<token> T_NEE "!=="
130 %token<token> T_LE "<="
131 %token<token> T_GE ">="
132 %token<token> T_DIVBY "/="
133 %token<token> T_MODBY "%="
134 %token<token> T_MULBY "*="
135 %token<token> T_PLUSBY "+="
136 %token<token> T_MINUSBY "-="
137 %token<token> T_SHRBY ">>="
138 %token<token> T_SHLBY "<<="
139 %token<token> T_USHRBY ">>>="
140 %token<token> T_OROR "||"
141 %token<token> T_ANDAND "&&"
142 %token<token> T_COLONCOLON "::"
143 %token<token> T_MINUSMINUS "--"
144 %token<token> T_PLUSPLUS "++"
145 %token<token> T_DOTDOT ".."
146 %token<token> T_DOTDOTDOT "..."
147 %token<token> T_SHL "<<"
148 %token<token> T_USHR ">>>"
149 %token<token> T_SHR ">>"
151 %type <id> X_IDENTIFIER PACKAGE
152 %type <token> VARCONST
154 %type <code> CODEPIECE
155 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
156 %type <token> PACKAGE_DECLARATION
157 %type <token> FUNCTION_DECLARATION
158 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
159 %type <token> CLASS_DECLARATION
160 %type <token> NAMESPACE_DECLARATION
161 %type <token> INTERFACE_DECLARATION
162 %type <code> VOIDEXPRESSION
163 %type <value> EXPRESSION NONCOMMAEXPRESSION
164 %type <value> MAYBEEXPRESSION
165 %type <value> E DELETE
166 %type <value> CONSTANT
167 %type <code> FOR IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
168 %type <token> USE_NAMESPACE
169 %type <code> FOR_INIT
171 %type <classinfo> MAYBETYPE
174 %type <params> PARAM_LIST
175 %type <params> MAYBE_PARAM_LIST
176 %type <flags> MAYBE_MODIFIERS
177 %type <flags> MODIFIER_LIST
178 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
179 %type <classinfo_list> IMPLEMENTS_LIST
180 %type <classinfo> EXTENDS
181 %type <classinfo_list> EXTENDS_LIST
182 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
183 %type <classinfo_list> QNAME_LIST
184 %type <classinfo> TYPE
186 //%type <token> VARIABLE
187 %type <value> VAR_READ
189 //%type <token> T_IDENTIFIER
190 %type <token> MODIFIER
191 %type <value> FUNCTIONCALL
192 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
194 // precedence: from low to high
198 %left below_semicolon
201 %nonassoc below_assignment // for ?:, contrary to spec
202 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
209 %nonassoc "==" "!=" "===" "!=="
211 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
212 %left "<<" ">>" ">>>"
216 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
218 %nonassoc below_curly
219 %left '[' ']' '{' "new" '.' ".." "::"
220 %nonassoc T_IDENTIFIER
225 // needed for "return" precedence:
226 %nonassoc T_STRING T_REGEXP
227 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
228 %nonassoc "false" "true" "null" "undefined" "super"
234 static int yyerror(char*s)
236 syntaxerror("%s", s);
238 static char* concat3str(const char* t1, const char* t2, const char* t3)
243 char*text = malloc(l1+l2+l3+1);
244 memcpy(text , t1, l1);
245 memcpy(text+l1, t2, l2);
246 memcpy(text+l1+l2, t3, l3);
251 typedef struct _import {
255 DECLARE_LIST(import);
257 typedef struct _classstate {
263 char has_constructor;
266 typedef struct _methodstate {
270 /* code that needs to be executed at the start of
271 a method (like initializing local registers) */
277 typedef struct _state {
281 import_list_t*wildcard_imports;
283 char has_own_imports;
286 methodstate_t*method;
291 typedef struct _global {
298 static global_t*global = 0;
299 static state_t* state = 0;
303 #define MULTINAME(m,x) \
306 registry_fill_multiname(&m, &m##_ns, x);
308 #define MEMBER_MULTINAME(m,f,n) \
312 m##_ns.access = flags2access(f->flags); \
316 m.namespace_set = 0; \
319 m.type = MULTINAME; \
321 m.namespace_set = &nopackage_namespace_set; \
325 /* warning: list length of namespace set is undefined */
326 #define MULTINAME_LATE(m, access, package) \
327 namespace_t m##_ns = {access, package}; \
328 namespace_set_t m##_nsset; \
329 namespace_list_t m##_l;m##_l.next = 0; \
330 m##_nsset.namespaces = &m##_l; \
331 m##_nsset = m##_nsset; \
332 m##_l.namespace = &m##_ns; \
333 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
335 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
336 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
337 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
338 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
339 static namespace_list_t nl4 = {&ns4,0};
340 static namespace_list_t nl3 = {&ns3,&nl4};
341 static namespace_list_t nl2 = {&ns2,&nl3};
342 static namespace_list_t nl1 = {&ns1,&nl2};
343 static namespace_set_t nopackage_namespace_set = {&nl1};
345 static state_list_t*state_stack=0;
347 static void init_globals()
349 global = rfx_calloc(sizeof(global_t));
352 static void new_state()
355 NEW(state_list_t, sl);
357 state_t*oldstate = state;
359 memcpy(s, state, sizeof(state_t)); //shallow copy
360 sl->next = state_stack;
363 s->imports = dict_new();
368 state->has_own_imports = 0;
369 state->vars = dict_new();
371 static void state_has_imports()
373 state->wildcard_imports = list_clone(state->wildcard_imports);
374 state->imports = dict_clone(state->imports);
375 state->has_own_imports = 1;
378 static void old_state()
380 if(!state_stack || !state_stack->next)
381 syntaxerror("invalid nesting");
382 state_t*oldstate = state;
383 state_list_t*old = state_stack;
384 state_stack = state_stack->next;
386 state = state_stack->state;
387 /*if(state->method->initcode) {
388 printf("residual initcode\n");
389 code_dump(state->method->initcode, 0, 0, "", stdout);
391 if(oldstate->has_own_imports) {
392 list_free(oldstate->wildcard_imports);
393 dict_destroy(oldstate->imports);oldstate->imports=0;
396 void initialize_state()
401 global->file = abc_file_new();
402 global->file->flags &= ~ABCFILE_LAZY;
404 global->init = abc_initscript(global->file, 0);
405 code_t*c = global->init->method->body->code;
407 c = abc_getlocal_0(c);
408 c = abc_pushscope(c);
410 /* findpropstrict doesn't just return a scope object- it
411 also makes it "active" somehow. Push local_0 on the
412 scope stack and read it back with findpropstrict, it'll
413 contain properties like "trace". Trying to find the same
414 property on a "vanilla" local_0 yields only a "undefined" */
415 //c = abc_findpropstrict(c, "[package]::trace");
417 /*c = abc_getlocal_0(c);
418 c = abc_findpropstrict(c, "[package]::trace");
420 c = abc_setlocal_1(c);
422 c = abc_pushbyte(c, 0);
423 c = abc_setlocal_2(c);
425 code_t*xx = c = abc_label(c);
426 c = abc_findpropstrict(c, "[package]::trace");
427 c = abc_pushstring(c, "prop:");
428 c = abc_hasnext2(c, 1, 2);
430 c = abc_setlocal_3(c);
431 c = abc_callpropvoid(c, "[package]::trace", 2);
432 c = abc_getlocal_3(c);
434 c = abc_iftrue(c,xx);*/
436 c = abc_findpropstrict(c, "[package]::trace");
437 c = abc_pushstring(c, "[entering global init function]");
438 c = abc_callpropvoid(c, "[package]::trace", 1);
440 global->init->method->body->code = c;
442 void* finalize_state()
444 if(state->level!=1) {
445 syntaxerror("unexpected end of file");
447 abc_method_body_t*m = global->init->method->body;
450 __ findpropstrict(m, "[package]::trace");
451 __ pushstring(m, "[leaving global init function]");
452 __ callpropvoid(m, "[package]::trace", 1);
458 static void startpackage(char*name)
461 syntaxerror("Packages can not be nested.");
464 /*printf("entering package \"%s\"\n", name);*/
465 state->package = name;
467 static void endpackage()
469 /*printf("leaving package \"%s\"\n", state->package);*/
474 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
477 syntaxerror("inner classes now allowed");
480 state->cls = rfx_calloc(sizeof(classstate_t));
483 classinfo_list_t*mlist=0;
484 /*printf("entering class %s\n", name);
485 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
487 printf(" extends: %s.%s\n", extends->package, extends->name);
488 printf(" implements (%d): ", list_length(implements));
489 for(mlist=implements;mlist;mlist=mlist->next) {
490 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
495 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
496 syntaxerror("invalid modifier(s)");
498 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
499 syntaxerror("public and internal not supported at the same time.");
501 /* create the class name, together with the proper attributes */
505 if(!(flags&FLAG_PUBLIC) && !state->package) {
506 access = ACCESS_PRIVATE; package = current_filename;
507 } else if(!(flags&FLAG_PUBLIC) && state->package) {
508 access = ACCESS_PACKAGEINTERNAL; package = state->package;
509 } else if(state->package) {
510 access = ACCESS_PACKAGE; package = state->package;
512 syntaxerror("public classes only allowed inside a package");
515 if(registry_findclass(package, classname)) {
516 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
520 /* build info struct */
521 int num_interfaces = (list_length(implements));
522 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
523 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
525 classinfo_list_t*l = implements;
526 for(l=implements;l;l=l->next) {
527 state->cls->info->interfaces[pos++] = l->classinfo;
530 multiname_t*extends2 = sig2mname(extends);
532 MULTINAME(classname2,state->cls->info);
535 state->cls_init = abc_getlocal_0(state->cls_init);
536 state->cls_init = abc_constructsuper(state->cls_init, 0);
539 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
540 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
541 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
543 state->cls->info->flags |= CLASS_INTERFACE;
544 abc_class_interface(state->cls->abc);
547 abc_class_protectedNS(state->cls->abc, classname);
549 for(mlist=implements;mlist;mlist=mlist->next) {
550 MULTINAME(m, mlist->classinfo);
551 abc_class_add_interface(state->cls->abc, &m);
554 /* now write the construction code for this class */
555 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
557 abc_method_body_t*m = global->init->method->body;
558 __ getglobalscope(m);
559 classinfo_t*s = extends;
564 //TODO: take a look at the current scope stack, maybe
565 // we can re-use something
570 multiname_t*s2 = sig2mname(s);
572 multiname_destroy(s2);
574 __ pushscope(m); count++;
575 m->code = m->code->prev->prev; // invert
577 /* continue appending after last op end */
578 while(m->code && m->code->next) m->code = m->code->next;
580 /* TODO: if this is one of *our* classes, we can also
581 do a getglobalscope/getslot <nr> (which references
582 the init function's slots) */
584 __ getlex2(m, extends2);
586 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
587 stack is not the superclass */
588 __ pushscope(m);count++;
591 /* notice: we get a verify error #1107 if the top element on the scope
592 stack is not the global object */
594 __ pushscope(m);count++;
596 __ newclass(m,state->cls->abc);
600 __ setslot(m, slotindex);
602 /* flash.display.MovieClip handling */
603 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
604 if(state->package && state->package[0]) {
605 globalclass = concat3str(state->package, ".", classname);
607 globalclass = strdup(classname);
610 multiname_destroy(extends2);
613 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
615 c = code_append(c, initcode);
616 c = code_append(c, body);
617 /* append return if necessary */
618 if(!c || c->opcode != OPCODE_RETURNVOID &&
619 c->opcode != OPCODE_RETURNVALUE) {
620 c = abc_returnvoid(c);
625 static void endclass()
627 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
629 c = abc_getlocal_0(c);
630 c = abc_constructsuper(c, 0);
631 state->cls->init = code_append(state->cls->init, c);
634 if(state->cls->init) {
635 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
636 m->body->code = wrap_function(0, state->cls->init, m->body->code);
638 if(state->cls->static_init) {
639 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
640 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
642 // handy for scope testing
646 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
652 typedef struct _variable {
657 static int find_variable(char*name, classinfo_t**m)
659 state_list_t* s = state_stack;
663 v = dict_lookup(s->state->vars, name);
674 static int find_variable_safe(char*name, classinfo_t**m)
676 int i = find_variable(name, m);
678 syntaxerror("undefined variable: %s", name);
681 static char variable_exists(char*name)
683 return dict_lookup(state->vars, name)!=0;
685 static int new_variable(char*name, classinfo_t*type)
688 v->index = global->variable_count;
690 dict_put(state->vars, name, v);
691 return global->variable_count++;
693 #define TEMPVARNAME "__as3_temp__"
694 static int gettempvar()
696 int i = find_variable(TEMPVARNAME, 0);
698 i = new_variable(TEMPVARNAME, 0);
703 code_t* killvars(code_t*c)
706 for(t=0;t<state->vars->hashsize;t++) {
707 dictentry_t*e =state->vars->slots[t];
709 variable_t*v = (variable_t*)e->data;
710 //do this always, otherwise register types don't match
711 //in the verifier when doing nested loops
712 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
713 c = abc_kill(c, v->index);
720 void check_code_for_break(code_t*c)
723 if(c->opcode == OPCODE___BREAK__) {
724 char*name = string_cstr(c->data[0]);
725 syntaxerror("Unresolved \"break %s\"", name);
727 if(c->opcode == OPCODE___CONTINUE__) {
728 char*name = string_cstr(c->data[0]);
729 syntaxerror("Unresolved \"continue %s\"", name);
736 static void check_constant_against_type(classinfo_t*t, constant_t*c)
738 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
739 if(TYPE_IS_NUMBER(t)) {
740 xassert(c->type == CONSTANT_FLOAT
741 || c->type == CONSTANT_INT
742 || c->type == CONSTANT_UINT);
743 } else if(TYPE_IS_UINT(t)) {
744 xassert(c->type == CONSTANT_UINT ||
745 (c->type == CONSTANT_INT && c->i>0));
746 } else if(TYPE_IS_INT(t)) {
747 xassert(c->type == CONSTANT_INT);
748 } else if(TYPE_IS_BOOLEAN(t)) {
749 xassert(c->type == CONSTANT_TRUE
750 || c->type == CONSTANT_FALSE);
754 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
756 memberinfo_t*minfo = 0;
757 if(getset != KW_GET && getset != KW_SET) {
758 if(registry_findmember(state->cls->info, name)) {
759 syntaxerror("class already contains a member/method called '%s'", name);
761 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
762 minfo->return_type = return_type;
763 // getslot on a member slot only returns "undefined", so no need
764 // to actually store these
765 //state->minfo->slot = state->method->abc->method->trait->slot_id;
767 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
771 else if(params->list)
772 type = params->list->param->type;
773 if((minfo=registry_findmember(state->cls->info, name))) {
774 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
775 syntaxerror("class already contains a member or method called '%s'", name);
777 syntaxerror("getter/setter for '%s' already defined", name);
778 /* make a setter or getter into a getset */
783 if(type && minfo->type != type)
784 syntaxerror("different type in getter and setter");
786 minfo = memberinfo_register(state->cls->info, name, gs);
789 /* can't assign a slot as getter and setter might have different slots */
790 //minfo->slot = slot;
792 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
793 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
794 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
795 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
796 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
800 static int flags2access(int flags)
803 if(flags&FLAG_PUBLIC) {
804 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
805 access = ACCESS_PACKAGE;
806 } else if(flags&FLAG_PRIVATE) {
807 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
808 access = ACCESS_PRIVATE;
809 } else if(flags&FLAG_PROTECTED) {
810 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
811 access = ACCESS_PROTECTED;
813 access = ACCESS_PACKAGEINTERNAL;
818 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
819 params_t*params, classinfo_t*return_type)
822 syntaxerror("not able to start another method scope");
825 state->method = rfx_calloc(sizeof(methodstate_t));
826 state->method->initcode = 0;
827 state->method->is_constructor = !strcmp(state->cls->info->name,name);
828 state->method->has_super = 0;
830 state->cls->has_constructor |= state->method->is_constructor;
832 global->variable_count = 0;
834 /* state->vars is initialized by state_new */
835 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
837 for(p=params->list;p;p=p->next) {
838 new_variable(p->param->name, p->param->type);
840 if(state->method->is_constructor)
841 name = "__as3_constructor__";
842 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
845 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
846 params_t*params, classinfo_t*return_type, code_t*body)
848 namespace_t mname_ns = {flags2access(flags), ""};
849 multiname_t mname = {QNAME, &mname_ns, 0, name};
853 multiname_t*type2 = sig2mname(return_type);
855 if(state->method->is_constructor) {
856 f = abc_class_getconstructor(state->cls->abc, type2);
858 if(flags&FLAG_STATIC)
859 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
861 f = abc_class_method(state->cls->abc, type2, &mname);
862 slot = f->trait->slot_id;
864 //flash doesn't seem to allow us to access function slots
865 //state->method->info->slot = slot;
867 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
868 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
869 if(params->varargs) f->flags |= METHOD_NEED_REST;
873 for(p=params->list;p;p=p->next) {
874 if(params->varargs && !p->next) {
875 break; //varargs: omit last parameter in function signature
877 multiname_t*m = sig2mname(p->param->type);
878 list_append(f->parameters, m);
879 if(p->param->value) {
880 check_constant_against_type(p->param->type, p->param->value);
881 opt=1;list_append(f->optional_parameters, p->param->value);
883 syntaxerror("non-optional parameter not allowed after optional parameters");
886 check_code_for_break(body);
889 f->body->code = body;
892 syntaxerror("interface methods can't have a method body");
899 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
904 void breakjumpsto(code_t*c, char*name, code_t*jump)
907 if(c->opcode == OPCODE___BREAK__) {
908 string_t*name2 = c->data[0];
909 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
910 c->opcode = OPCODE_JUMP;
917 void continuejumpsto(code_t*c, char*name, code_t*jump)
920 if(c->opcode == OPCODE___CONTINUE__) {
921 string_t*name2 = c->data[0];
922 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
923 c->opcode = OPCODE_JUMP;
931 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
934 return registry_getanytype();
935 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
936 return registry_getanytype();
939 return registry_getanytype();
941 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
946 return abc_coerce_a(c);
950 // cast an "any" type to a specific type. subject to
951 // runtime exceptions
952 return abc_coerce2(c, &m);
955 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
956 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
957 // allow conversion between number types
958 return abc_coerce2(c, &m);
960 //printf("%s.%s\n", from.package, from.name);
961 //printf("%s.%s\n", to.package, to.name);
963 classinfo_t*supertype = from;
965 if(supertype == to) {
966 // target type is one of from's superclasses
967 return abc_coerce2(c, &m);
970 while(supertype->interfaces[t]) {
971 if(supertype->interfaces[t]==to) {
972 // target type is one of from's interfaces
973 return abc_coerce2(c, &m);
977 supertype = supertype->superclass;
979 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
981 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
983 syntaxerror("can't convert type %s to %s", from->name, to->name);
986 code_t*defaultvalue(code_t*c, classinfo_t*type)
988 if(TYPE_IS_INT(type)) {
989 c = abc_pushbyte(c, 0);
990 } else if(TYPE_IS_UINT(type)) {
991 c = abc_pushuint(c, 0);
992 } else if(TYPE_IS_FLOAT(type)) {
994 } else if(TYPE_IS_BOOLEAN(type)) {
995 c = abc_pushfalse(c);
1002 char is_pushundefined(code_t*c)
1004 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1007 void parserassert(int b)
1009 if(!b) syntaxerror("internal error: assertion failed");
1012 static classinfo_t* find_class(char*name)
1016 c = registry_findclass(state->package, name);
1018 /* try explicit imports */
1019 dictentry_t* e = dict_get_slot(state->imports, name);
1023 if(!strcmp(e->key, name)) {
1024 c = (classinfo_t*)e->data;
1029 /* try package.* imports */
1030 import_list_t*l = state->wildcard_imports;
1034 //printf("does package %s contain a class %s?\n", l->import->package, name);
1035 c = registry_findclass(l->import->package, name);
1039 /* try global package */
1041 c = registry_findclass("", name);
1046 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1050 [prefix code] [read instruction]
1054 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1057 if(in && in->opcode == OPCODE_COERCE_A) {
1058 in = code_cutlast(in);
1061 syntaxerror("internal error");
1063 /* chop off read instruction */
1067 prefix = r->prev;r->prev = 0;
1073 char use_temp_var = readbefore;
1075 /* generate the write instruction, and maybe append a dup to the prefix code */
1076 code_t* write = abc_nop(0);
1077 if(r->opcode == OPCODE_GETPROPERTY) {
1078 write->opcode = OPCODE_SETPROPERTY;
1079 multiname_t*m = (multiname_t*)r->data[0];
1080 write->data[0] = multiname_clone(m);
1081 if(m->type == QNAME || m->type == MULTINAME) {
1083 prefix = abc_dup(prefix); // we need the object, too
1086 } else if(m->type == MULTINAMEL) {
1088 /* dupping two values on the stack requires 5 operations and one register-
1089 couldn't adobe just have given us a dup2? */
1090 int temp = gettempvar();
1091 prefix = abc_setlocal(prefix, temp);
1092 prefix = abc_dup(prefix);
1093 prefix = abc_getlocal(prefix, temp);
1094 prefix = abc_swap(prefix);
1095 prefix = abc_getlocal(prefix, temp);
1099 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1101 } else if(r->opcode == OPCODE_GETSLOT) {
1102 write->opcode = OPCODE_SETSLOT;
1103 write->data[0] = r->data[0];
1105 prefix = abc_dup(prefix); // we need the object, too
1108 } else if(r->opcode == OPCODE_GETLOCAL) {
1109 write->opcode = OPCODE_SETLOCAL;
1110 write->data[0] = r->data[0];
1111 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1112 write->opcode = OPCODE_SETLOCAL_0;
1113 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1114 write->opcode = OPCODE_SETLOCAL_1;
1115 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1116 write->opcode = OPCODE_SETLOCAL_2;
1117 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1118 write->opcode = OPCODE_SETLOCAL_3;
1120 code_dump(r, 0, 0, "", stdout);
1121 syntaxerror("illegal lvalue: can't assign a value to this expression");
1128 /* with getproperty/getslot, we have to be extra careful not
1129 to execute the read code twice, as it might have side-effects
1130 (e.g. if the property is in fact a setter/getter combination)
1132 So read the value, modify it, and write it again,
1133 using prefix only once and making sure (by using a temporary
1134 register) that the return value is what we just wrote */
1135 temp = gettempvar();
1136 c = code_append(c, prefix);
1137 c = code_append(c, r);
1140 c = abc_setlocal(c, temp);
1142 c = code_append(c, middlepart);
1145 c = abc_setlocal(c, temp);
1147 c = code_append(c, write);
1148 c = abc_getlocal(c, temp);
1149 c = abc_kill(c, temp);
1151 /* if we're allowed to execute the read code twice *and*
1152 the middlepart doesn't modify the code, things are easier.
1154 code_t* r2 = code_dup(r);
1155 //c = code_append(c, prefix);
1156 parserassert(!prefix);
1157 c = code_append(c, r);
1158 c = code_append(c, middlepart);
1159 c = code_append(c, write);
1160 c = code_append(c, r2);
1163 /* even smaller version: overwrite the value without reading
1167 c = code_append(c, prefix);
1170 c = code_append(c, middlepart);
1171 c = code_append(c, write);
1172 c = code_append(c, r);
1174 temp = gettempvar();
1176 c = code_append(c, prefix);
1179 c = code_append(c, middlepart);
1181 c = abc_setlocal(c, temp);
1182 c = code_append(c, write);
1183 c = abc_getlocal(c, temp);
1190 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1191 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1198 /* ------------ code blocks / statements ---------------- */
1200 PROGRAM: MAYBECODE {
1201 /* todo: do something with this code if we're outside a function */
1203 warning("ignored code");
1206 MAYBECODE: CODE {$$=$1;}
1207 MAYBECODE: {$$=code_new();}
1209 CODE: CODE CODEPIECE {
1210 $$=code_append($1,$2);
1216 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1217 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1218 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1219 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1220 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1221 CODEPIECE: ';' {$$=code_new();}
1222 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1223 CODEPIECE: VOIDEXPRESSION {$$=$1}
1224 CODEPIECE: FOR {$$=$1}
1225 CODEPIECE: WHILE {$$=$1}
1226 CODEPIECE: DO_WHILE {$$=$1}
1227 CODEPIECE: SWITCH {$$=$1}
1228 CODEPIECE: BREAK {$$=$1}
1229 CODEPIECE: CONTINUE {$$=$1}
1230 CODEPIECE: RETURN {$$=$1}
1231 CODEPIECE: IF {$$=$1}
1232 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1233 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1235 CODEBLOCK : '{' CODE '}' {$$=$2;}
1236 CODEBLOCK : '{' '}' {$$=0;}
1237 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1238 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1240 /* ------------ variables --------------------------- */
1242 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1243 | {$$.c=abc_pushundefined(0);
1247 VAR : "const" | "var"
1248 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1250 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1251 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1253 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1255 if(variable_exists($2))
1256 syntaxerror("Variable %s already defined", $2);
1258 if(!is_subtype_of($4.t, $3)) {
1259 syntaxerror("Can't convert %s to %s", $4.t->name,
1263 int index = new_variable($2, $3);
1266 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1268 $$ = converttype($$, $4.t, $3);
1269 $$ = abc_setlocal($$, index);
1271 $$ = defaultvalue(0, $3);
1272 $$ = abc_setlocal($$, index);
1275 /* if this is a typed variable:
1276 push default value for type on stack */
1278 state->method->initcode = defaultvalue(state->method->initcode, $3);
1279 state->method->initcode = abc_setlocal(state->method->initcode, index);
1282 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1284 $$ = abc_coerce_a($$);
1285 $$ = abc_setlocal($$, index);
1291 /* that's the default for a local register, anyway
1293 state->method->initcode = abc_pushundefined(state->method->initcode);
1294 state->method->initcode = abc_setlocal(state->method->initcode, index);
1296 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1299 /* ------------ control flow ------------------------- */
1301 MAYBEELSE: %prec below_else {$$ = code_new();}
1302 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1303 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1305 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1307 $$ = code_append($$, $4.c);
1308 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1310 $$ = code_append($$, $6);
1312 myjmp = $$ = abc_jump($$, 0);
1314 myif->branch = $$ = abc_nop($$);
1316 $$ = code_append($$, $7);
1317 myjmp->branch = $$ = abc_nop($$);
1320 $$ = killvars($$);old_state();
1323 FOR_INIT : {$$=code_new();}
1324 FOR_INIT : VARIABLE_DECLARATION
1325 FOR_INIT : VOIDEXPRESSION
1327 FOR : T_FOR '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1329 $$ = code_append($$, $4);
1330 code_t*loopstart = $$ = abc_label($$);
1331 $$ = code_append($$, $6.c);
1332 code_t*myif = $$ = abc_iffalse($$, 0);
1333 $$ = code_append($$, $10);
1334 code_t*cont = $$ = abc_nop($$);
1335 $$ = code_append($$, $8);
1336 $$ = abc_jump($$, loopstart);
1337 code_t*out = $$ = abc_nop($$);
1338 breakjumpsto($$, $1, out);
1339 continuejumpsto($$, $1, cont);
1342 $$ = killvars($$);old_state();
1345 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1348 code_t*myjmp = $$ = abc_jump($$, 0);
1349 code_t*loopstart = $$ = abc_label($$);
1350 $$ = code_append($$, $6);
1351 code_t*cont = $$ = abc_nop($$);
1352 myjmp->branch = cont;
1353 $$ = code_append($$, $4.c);
1354 $$ = abc_iftrue($$, loopstart);
1355 code_t*out = $$ = abc_nop($$);
1356 breakjumpsto($$, $1, out);
1357 continuejumpsto($$, $1, cont);
1363 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1365 code_t*loopstart = $$ = abc_label($$);
1366 $$ = code_append($$, $3);
1367 code_t*cont = $$ = abc_nop($$);
1368 $$ = code_append($$, $6.c);
1369 $$ = abc_iftrue($$, loopstart);
1370 code_t*out = $$ = abc_nop($$);
1371 breakjumpsto($$, $1, out);
1372 continuejumpsto($$, $1, cont);
1377 BREAK : "break" %prec prec_none {
1378 $$ = abc___break__(0, "");
1380 BREAK : "break" T_IDENTIFIER {
1381 $$ = abc___break__(0, $2);
1383 CONTINUE : "continue" %prec prec_none {
1384 $$ = abc___continue__(0, "");
1386 CONTINUE : "continue" T_IDENTIFIER {
1387 $$ = abc___continue__(0, $2);
1390 MAYBE_CASE_LIST : {$$=0;}
1391 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1392 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1393 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1394 CASE_LIST: CASE {$$=$1}
1395 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1397 CASE: "case" CONSTANT ':' MAYBECODE {
1399 $$ = code_append($$, $2.c);
1400 code_t*j = $$ = abc_ifne($$, 0);
1401 $$ = code_append($$, $4);
1402 $$ = abc___continue__($$, "");
1403 code_t*e = $$ = abc_nop($$);
1406 DEFAULT: "default" ':' MAYBECODE {
1409 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1411 $$ = code_append($$, $7);
1412 code_t*out = $$ = abc_pop($$);
1413 breakjumpsto($$, $1, out);
1415 code_t*c = $$,*lastblock=0;
1417 if(c->opcode == OPCODE_IFNE) {
1419 } else if(c->opcode == OPCODE___CONTINUE__) {
1421 c->opcode = OPCODE_JUMP;
1422 c->branch = lastblock;
1424 /* fall through end of switch */
1425 c->opcode = OPCODE_NOP;
1433 /* ------------ packages and imports ---------------- */
1435 X_IDENTIFIER: T_IDENTIFIER
1436 | "package" {$$="package";}
1438 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1439 PACKAGE: X_IDENTIFIER {$$=$1;}
1441 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1442 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1444 IMPORT : "import" QNAME {
1447 syntaxerror("Couldn't import class\n");
1448 state_has_imports();
1449 dict_put(state->imports, c->name, c);
1452 IMPORT : "import" PACKAGE '.' '*' {
1455 state_has_imports();
1456 list_append(state->wildcard_imports, i);
1460 /* ------------ classes and interfaces (header) -------------- */
1462 MAYBE_MODIFIERS : {$$=0;}
1463 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1464 MODIFIER_LIST : MODIFIER {$$=$1;}
1465 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1467 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1468 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1469 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1470 | KW_STATIC {$$=FLAG_STATIC;}
1471 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1472 | KW_FINAL {$$=FLAG_FINAL;}
1473 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1474 | KW_NATIVE {$$=FLAG_NATIVE;}
1475 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1477 EXTENDS : {$$=registry_getobjectclass();}
1478 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1480 EXTENDS_LIST : {$$=list_new();}
1481 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1483 IMPLEMENTS_LIST : {$$=list_new();}
1484 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1486 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1487 EXTENDS IMPLEMENTS_LIST
1488 '{' {startclass($1,$3,$4,$5, 0);}
1489 MAYBE_DECLARATION_LIST
1492 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1494 '{' {startclass($1,$3,0,$4,1);}
1495 MAYBE_IDECLARATION_LIST
1498 /* ------------ classes and interfaces (body) -------------- */
1500 MAYBE_DECLARATION_LIST :
1501 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1502 DECLARATION_LIST : DECLARATION
1503 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1505 DECLARATION : SLOT_DECLARATION
1506 DECLARATION : FUNCTION_DECLARATION
1508 MAYBE_IDECLARATION_LIST :
1509 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1510 IDECLARATION_LIST : IDECLARATION
1511 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1513 IDECLARATION : "var" T_IDENTIFIER {
1514 syntaxerror("variable declarations not allowed in interfaces");
1516 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1518 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1519 syntaxerror("invalid method modifiers: interface methods always need to be public");
1521 startfunction(0,$1,$3,$4,&$6,$8);
1522 endfunction(0,$1,$3,$4,&$6,$8, 0);
1525 /* ------------ classes and interfaces (body, slots ) ------- */
1527 VARCONST: "var" | "const"
1529 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1531 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1533 info->flags = flags;
1536 namespace_t mname_ns = {flags2access(flags), ""};
1537 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1539 if(!(flags&FLAG_STATIC)) {
1542 t=abc_class_slot(state->cls->abc, &mname, &m);
1544 t=abc_class_slot(state->cls->abc, &mname, 0);
1546 info->slot = t->slot_id;
1550 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1552 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1554 info->slot = t->slot_id;
1556 if($5.c && !is_pushundefined($5.c)) {
1558 c = abc_getlocal_0(c);
1559 c = code_append(c, $5.c);
1560 c = converttype(c, $5.t, $4);
1561 c = abc_setslot(c, t->slot_id);
1562 if(!(flags&FLAG_STATIC))
1563 state->cls->init = code_append(state->cls->init, c);
1565 state->cls->static_init = code_append(state->cls->static_init, c);
1568 t->kind= TRAIT_CONST;
1572 /* ------------ constants -------------------------------------- */
1574 MAYBESTATICCONSTANT: {$$=0;}
1575 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1577 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1578 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1579 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1580 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1581 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1582 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1583 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1584 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1585 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1587 /* ------------ classes and interfaces (body, functions) ------- */
1589 // non-vararg version
1591 memset(&$$,0,sizeof($$));
1593 MAYBE_PARAM_LIST: PARAM_LIST {
1598 MAYBE_PARAM_LIST: "..." PARAM {
1599 memset(&$$,0,sizeof($$));
1601 list_append($$.list, $2);
1603 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1606 list_append($$.list, $4);
1610 PARAM_LIST: PARAM_LIST ',' PARAM {
1612 list_append($$.list, $3);
1615 memset(&$$,0,sizeof($$));
1616 list_append($$.list, $1);
1619 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1620 $$ = malloc(sizeof(param_t));
1625 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1626 $$ = malloc(sizeof(param_t));
1628 $$->type = TYPE_ANY;
1631 GETSET : "get" {$$=$1;}
1635 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1636 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1639 if(state->method->late_binding) {
1640 c = abc_getlocal_0(c);
1641 c = abc_pushscope(c);
1643 if(state->method->is_constructor && !state->method->has_super) {
1644 // call default constructor
1645 c = abc_getlocal_0(c);
1646 c = abc_constructsuper(c, 0);
1648 c = wrap_function(c, state->method->initcode, $11);
1649 endfunction(0,$1,$3,$4,&$6,$8,c);
1652 /* ------------- package + class ids --------------- */
1654 CLASS: T_IDENTIFIER {
1656 /* try current package */
1657 $$ = find_class($1);
1658 if(!$$) syntaxerror("Could not find class %s\n", $1);
1661 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1662 $$ = registry_findclass($1, $3);
1663 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1666 QNAME: PACKAGEANDCLASS
1669 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1670 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1672 TYPE : QNAME {$$=$1;}
1673 | '*' {$$=registry_getanytype();}
1674 | "void" {$$=registry_getanytype();}
1676 | "String" {$$=registry_getstringclass();}
1677 | "int" {$$=registry_getintclass();}
1678 | "uint" {$$=registry_getuintclass();}
1679 | "Boolean" {$$=registry_getbooleanclass();}
1680 | "Number" {$$=registry_getnumberclass();}
1683 MAYBETYPE: ':' TYPE {$$=$2;}
1686 /* ----------function calls, delete, constructor calls ------ */
1688 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1689 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1691 MAYBE_EXPRESSION_LIST : {$$=0;}
1692 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1693 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1694 typedcode_t*t = malloc(sizeof(typedcode_t));
1696 list_append($$, t);}
1697 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1698 typedcode_t*t = malloc(sizeof(typedcode_t));
1700 list_append($$, t);}
1702 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1707 $$.c = abc_getglobalscope($$.c);
1708 $$.c = abc_getslot($$.c, $2->slot);
1710 $$.c = abc_findpropstrict2($$.c, &m);
1713 typedcode_list_t*l = $3;
1716 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1721 $$.c = abc_construct($$.c, len);
1723 $$.c = abc_constructprop2($$.c, &m, len);
1727 /* TODO: use abc_call (for calling local variables),
1728 abc_callstatic (for calling own methods)
1731 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1732 typedcode_list_t*l = $3;
1734 code_t*paramcode = 0;
1736 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1742 if($$.c->opcode == OPCODE_COERCE_A) {
1743 $$.c = code_cutlast($$.c);
1747 multiname_t*name = 0;
1748 if($$.c->opcode == OPCODE_GETPROPERTY) {
1749 name = multiname_clone($$.c->data[0]);
1750 $$.c = code_cutlast($$.c);
1751 $$.c = code_append($$.c, paramcode);
1752 $$.c = abc_callproperty2($$.c, name, len);
1753 } else if($$.c->opcode == OPCODE_GETSLOT) {
1754 int slot = (int)(ptroff_t)$$.c->data[0];
1755 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1756 if(t->kind!=TRAIT_METHOD) {
1757 //ok: flash allows to assign closures to members.
1760 $$.c = code_cutlast($$.c);
1761 $$.c = code_append($$.c, paramcode);
1762 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1763 $$.c = abc_callproperty2($$.c, name, len);
1764 } else if($$.c->opcode == OPCODE_GETSUPER) {
1765 name = multiname_clone($$.c->data[0]);
1766 $$.c = code_cutlast($$.c);
1767 $$.c = code_append($$.c, paramcode);
1768 $$.c = abc_callsuper2($$.c, name, len);
1770 $$.c = abc_getlocal_0($$.c);
1771 $$.c = code_append($$.c, paramcode);
1772 $$.c = abc_call($$.c, len);
1777 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1778 $$.t = $1.t->function->return_type;
1780 $$.c = abc_coerce_a($$.c);
1784 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1785 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1786 if(!state->method) syntaxerror("super() not allowed outside of a function");
1787 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1790 $$.c = abc_getlocal_0($$.c);
1791 typedcode_list_t*l = 0;
1793 for(l=$3;l;l=l->next) {
1794 $$.c = code_append($$.c, l->typedcode->c);len++;
1797 this is dependent on the control path, check this somewhere else
1798 if(state->method->has_super)
1799 syntaxerror("constructor may call super() only once");
1801 state->method->has_super = 1;
1802 $$.c = abc_constructsuper($$.c, len);
1803 $$.c = abc_pushundefined($$.c);
1807 DELETE: "delete" E {
1809 if($$.c->opcode == OPCODE_COERCE_A) {
1810 $$.c = code_cutlast($$.c);
1812 multiname_t*name = 0;
1813 if($$.c->opcode == OPCODE_GETPROPERTY) {
1814 $$.c->opcode = OPCODE_DELETEPROPERTY;
1815 } else if($$.c->opcode == OPCODE_GETSLOT) {
1816 int slot = (int)(ptroff_t)$$.c->data[0];
1817 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1818 $$.c = code_cutlast($$.c);
1819 $$.c = abc_deleteproperty2($$.c, name);
1821 $$.c = abc_getlocal_0($$.c);
1822 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1823 $$.c = abc_deleteproperty2($$.c, &m);
1825 $$.t = TYPE_BOOLEAN;
1828 RETURN: "return" %prec prec_none {
1829 $$ = abc_returnvoid(0);
1831 RETURN: "return" EXPRESSION {
1833 $$ = abc_returnvalue($$);
1836 // ----------------------- expression types -------------------------------------
1838 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1839 EXPRESSION : E %prec below_minus {$$ = $1;}
1840 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1842 $$.c = cut_last_push($$.c);
1843 $$.c = code_append($$.c,$3.c);
1846 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1847 $$=cut_last_push($1.c);
1850 // ----------------------- expression evaluation -------------------------------------
1853 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1855 E : DELETE {$$ = $1;}
1856 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1860 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1861 //MULTINAME(m, registry_getintclass());
1862 //$$.c = abc_coerce2($$.c, &m); // FIXME
1865 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1868 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1871 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1874 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1877 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1880 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1883 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1884 $$.t = TYPE_BOOLEAN;
1886 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1887 $$.t = TYPE_BOOLEAN;
1889 CONSTANT : "null" {$$.c = abc_pushnull(0);
1894 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1895 $$.t = TYPE_BOOLEAN;
1897 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1898 $$.t = TYPE_BOOLEAN;
1900 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1901 $$.t = TYPE_BOOLEAN;
1903 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1904 $$.t = TYPE_BOOLEAN;
1906 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1907 $$.t = TYPE_BOOLEAN;
1909 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1910 $$.t = TYPE_BOOLEAN;
1912 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1913 $$.t = TYPE_BOOLEAN;
1915 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1916 $$.t = TYPE_BOOLEAN;
1919 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1921 $$.c = converttype($$.c, $1.t, $$.t);
1922 $$.c = abc_dup($$.c);
1923 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1924 $$.c = cut_last_push($$.c);
1925 $$.c = code_append($$.c,$3.c);
1926 $$.c = converttype($$.c, $3.t, $$.t);
1927 code_t*label = $$.c = abc_label($$.c);
1928 jmp->branch = label;
1931 $$.t = join_types($1.t, $3.t, 'A');
1932 /*printf("%08x:\n",$1.t);
1933 code_dump($1.c, 0, 0, "", stdout);
1934 printf("%08x:\n",$3.t);
1935 code_dump($3.c, 0, 0, "", stdout);
1936 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1938 $$.c = converttype($$.c, $1.t, $$.t);
1939 $$.c = abc_dup($$.c);
1940 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1941 $$.c = cut_last_push($$.c);
1942 $$.c = code_append($$.c,$3.c);
1943 $$.c = converttype($$.c, $3.t, $$.t);
1944 code_t*label = $$.c = abc_label($$.c);
1945 jmp->branch = label;
1948 E : '!' E {$$.c=$2.c;
1949 $$.c = abc_not($$.c);
1950 $$.t = TYPE_BOOLEAN;
1953 E : '~' E {$$.c=$2.c;
1954 $$.c = abc_bitnot($$.c);
1958 E : E '&' E {$$.c = code_append($1.c,$3.c);
1959 $$.c = abc_bitand($$.c);
1963 E : E '^' E {$$.c = code_append($1.c,$3.c);
1964 $$.c = abc_bitxor($$.c);
1968 E : E '|' E {$$.c = code_append($1.c,$3.c);
1969 $$.c = abc_bitor($$.c);
1973 E : E '-' E {$$.c = code_append($1.c,$3.c);
1974 if(BOTH_INT($1,$3)) {
1975 $$.c = abc_subtract_i($$.c);
1978 $$.c = abc_subtract($$.c);
1982 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1983 $$.c = abc_rshift($$.c);
1986 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1987 $$.c = abc_urshift($$.c);
1990 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1991 $$.c = abc_lshift($$.c);
1995 E : E '/' E {$$.c = code_append($1.c,$3.c);
1996 $$.c = abc_divide($$.c);
1999 E : E '+' E {$$.c = code_append($1.c,$3.c);
2000 $$.c = abc_add($$.c);
2003 E : E '%' E {$$.c = code_append($1.c,$3.c);
2004 $$.c = abc_modulo($$.c);
2007 E : E '*' E {$$.c = code_append($1.c,$3.c);
2008 if(BOTH_INT($1,$3)) {
2009 $$.c = abc_multiply_i($$.c);
2012 $$.c = abc_multiply($$.c);
2017 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2018 if(use_astype && TYPE_IS_CLASS($3.t)) {
2019 MULTINAME(m,$3.t->cls);
2020 $$.c = abc_astype2($1.c, &m);
2023 $$.c = code_append($1.c, $3.c);
2024 $$.c = abc_astypelate($$.c);
2029 E : E "instanceof" E
2030 {$$.c = code_append($1.c, $3.c);
2031 $$.c = abc_instanceof($$.c);
2032 $$.t = TYPE_BOOLEAN;
2035 E : E "is" E {$$.c = code_append($1.c, $3.c);
2036 $$.c = abc_istypelate($$.c);
2037 $$.t = TYPE_BOOLEAN;
2040 E : "typeof" '(' E ')' {
2042 $$.c = abc_typeof($$.c);
2047 $$.c = cut_last_push($2.c);
2048 $$.c = abc_pushundefined($$.c);
2052 E : "void" { $$.c = abc_pushundefined(0);
2056 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2061 $$.c=abc_negate_i($$.c);
2064 $$.c=abc_negate($$.c);
2071 $$.c = code_append($$.c, $3.c);
2073 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2074 $$.c = abc_getproperty2($$.c, &m);
2075 $$.t = 0; // array elements have unknown type
2078 E : '[' MAYBE_EXPRESSION_LIST ']' {
2080 typedcode_list_t*l = 0;
2082 for(l=$2;l;l=l->next) {
2083 $$.c = code_append($$.c, l->typedcode->c);len++;
2085 $$.c = abc_newarray($$.c, len);
2086 $$.t = registry_getarrayclass();
2089 MAYBE_EXPRPAIR_LIST : {$$=0;}
2090 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2092 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2093 typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $1;
2094 typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $3;
2096 list_append($$, t1);
2097 list_append($$, t2);
2099 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2101 typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $3;
2102 typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $5;
2103 list_append($$, t1);
2104 list_append($$, t2);
2109 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2111 typedcode_list_t*l = 0;
2113 for(l=$2;l;l=l->next) {
2114 $$.c = code_append($$.c, l->typedcode->c);len++;
2116 $$.c = abc_newobject($$.c, len/2);
2117 $$.t = registry_getobjectclass();
2122 if(BOTH_INT($1,$3)) {
2123 c=abc_multiply_i(c);
2127 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2128 $$.c = toreadwrite($1.c, c, 0, 0);
2133 code_t*c = abc_modulo($3.c);
2134 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2135 $$.c = toreadwrite($1.c, c, 0, 0);
2139 code_t*c = abc_lshift($3.c);
2140 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2141 $$.c = toreadwrite($1.c, c, 0, 0);
2145 code_t*c = abc_rshift($3.c);
2146 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2147 $$.c = toreadwrite($1.c, c, 0, 0);
2151 code_t*c = abc_urshift($3.c);
2152 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2153 $$.c = toreadwrite($1.c, c, 0, 0);
2157 code_t*c = abc_divide($3.c);
2158 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2159 $$.c = toreadwrite($1.c, c, 0, 0);
2164 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2169 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2171 $$.c = toreadwrite($1.c, c, 0, 0);
2174 E : E "-=" E { code_t*c = $3.c;
2175 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2176 c=abc_subtract_i(c);
2180 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2182 $$.c = toreadwrite($1.c, c, 0, 0);
2185 E : E '=' E { code_t*c = 0;
2186 c = code_append(c, $3.c);
2187 c = converttype(c, $3.t, $1.t);
2188 $$.c = toreadwrite($1.c, c, 1, 0);
2192 E : E '?' E ':' E %prec below_assignment {
2194 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2195 $$.c = code_append($$.c, $3.c);
2196 code_t*j2 = $$.c = abc_jump($$.c, 0);
2197 $$.c = j1->branch = abc_label($$.c);
2198 $$.c = code_append($$.c, $5.c);
2199 $$.c = j2->branch = abc_label($$.c);
2200 $$.t = join_types($3.t,$5.t,'?');
2203 // TODO: use inclocal where appropriate
2204 E : E "++" { code_t*c = 0;
2205 classinfo_t*type = $1.t;
2206 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2207 c=abc_increment_i(c);
2213 c=converttype(c, type, $1.t);
2214 $$.c = toreadwrite($1.c, c, 0, 1);
2217 E : E "--" { code_t*c = 0;
2218 classinfo_t*type = $1.t;
2219 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2220 c=abc_decrement_i(c);
2226 c=converttype(c, type, $1.t);
2227 $$.c = toreadwrite($1.c, c, 0, 1);
2231 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2232 classinfo_t*type = $2.t;
2233 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2234 c=abc_increment_i(c);
2240 c=converttype(c, type, $2.t);
2241 $$.c = toreadwrite($2.c, c, 0, 0);
2245 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2246 classinfo_t*type = $2.t;
2247 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2248 c=abc_decrement_i(c);
2254 c=converttype(c, type, $2.t);
2255 $$.c = toreadwrite($2.c, c, 0, 0);
2259 E : "super" '.' T_IDENTIFIER
2260 { if(!state->cls->info)
2261 syntaxerror("super keyword not allowed outside a class");
2262 classinfo_t*t = state->cls->info->superclass;
2263 if(!t) t = TYPE_OBJECT;
2265 memberinfo_t*f = registry_findmember(t, $3);
2266 namespace_t ns = {flags2access(f->flags), ""};
2267 MEMBER_MULTINAME(m, f, $3);
2269 $$.c = abc_getlocal_0($$.c);
2270 $$.c = abc_getsuper2($$.c, &m);
2271 $$.t = memberinfo_gettype(f);
2274 E : E '.' T_IDENTIFIER
2276 classinfo_t*t = $1.t;
2278 if(TYPE_IS_CLASS(t) && t->cls) {
2283 memberinfo_t*f = registry_findmember(t, $3);
2285 if(f && !is_static != !(f->flags&FLAG_STATIC))
2287 if(f && f->slot && !noslot) {
2288 $$.c = abc_getslot($$.c, f->slot);
2290 MEMBER_MULTINAME(m, f, $3);
2291 $$.c = abc_getproperty2($$.c, &m);
2293 /* determine type */
2294 $$.t = memberinfo_gettype(f);
2296 $$.c = abc_coerce_a($$.c);
2298 /* when resolving a property on an unknown type, we do know the
2299 name of the property (and don't seem to need the package), but
2300 we need to make avm2 try out all access modes */
2301 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2302 $$.c = abc_getproperty2($$.c, &m);
2303 $$.c = abc_coerce_a($$.c);
2304 $$.t = registry_getanytype();
2308 VAR_READ : T_IDENTIFIER {
2315 /* look at variables */
2316 if((i = find_variable($1, &$$.t)) >= 0) {
2317 // $1 is a local variable
2318 $$.c = abc_getlocal($$.c, i);
2320 /* look at current class' members */
2321 } else if((f = registry_findmember(state->cls->info, $1))) {
2322 // $1 is a function in this class
2323 int var_is_static = (f->flags&FLAG_STATIC);
2324 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2325 if(var_is_static != i_am_static) {
2326 /* there doesn't seem to be any "static" way to access
2327 static properties of a class */
2328 state->method->late_binding = 1;
2330 namespace_t ns = {flags2access(f->flags), ""};
2331 multiname_t m = {QNAME, &ns, 0, $1};
2332 $$.c = abc_findpropstrict2($$.c, &m);
2333 $$.c = abc_getproperty2($$.c, &m);
2336 $$.c = abc_getlocal_0($$.c);
2337 $$.c = abc_getslot($$.c, f->slot);
2339 namespace_t ns = {flags2access(f->flags), ""};
2340 multiname_t m = {QNAME, &ns, 0, $1};
2341 $$.c = abc_getlocal_0($$.c);
2342 $$.c = abc_getproperty2($$.c, &m);
2345 if(f->kind == MEMBER_METHOD) {
2346 $$.t = TYPE_FUNCTION(f);
2351 /* look at classes in the current package and imported classes */
2352 } else if((a = find_class($1))) {
2353 if(a->flags & FLAG_METHOD) {
2355 $$.c = abc_findpropstrict2($$.c, &m);
2356 $$.c = abc_getproperty2($$.c, &m);
2357 $$.t = TYPE_FUNCTION(a->function);
2360 $$.c = abc_getglobalscope($$.c);
2361 $$.c = abc_getslot($$.c, a->slot);
2364 $$.c = abc_getlex2($$.c, &m);
2366 $$.t = TYPE_CLASS(a);
2369 /* unknown object, let the avm2 resolve it */
2371 if(strcmp($1,"trace"))
2372 warning("Couldn't resolve '%s', doing late binding", $1);
2373 state->method->late_binding = 1;
2375 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2378 $$.c = abc_findpropstrict2($$.c, &m);
2379 $$.c = abc_getproperty2($$.c, &m);
2384 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2385 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2386 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2388 // ----------------- namespaces -------------------------------------------------
2390 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2391 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2392 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2394 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER