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 if($$->opcode != OPCODE___BREAK__) {
1403 $$ = abc___fallthrough__($$, "");
1405 code_t*e = $$ = abc_nop($$);
1408 DEFAULT: "default" ':' MAYBECODE {
1411 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1413 $$ = code_append($$, $7);
1414 code_t*out = $$ = abc_pop($$);
1415 breakjumpsto($$, $1, out);
1417 code_t*c = $$,*lastblock=0;
1419 if(c->opcode == OPCODE_IFNE) {
1420 if(!c->next) syntaxerror("internal error in fallthrough handling");
1422 } else if(c->opcode == OPCODE___CONTINUE__) {
1424 c->opcode = OPCODE_JUMP;
1425 c->branch = lastblock;
1427 /* fall through end of switch */
1428 c->opcode = OPCODE_NOP;
1436 /* ------------ packages and imports ---------------- */
1438 X_IDENTIFIER: T_IDENTIFIER
1439 | "package" {$$="package";}
1441 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1442 PACKAGE: X_IDENTIFIER {$$=$1;}
1444 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1445 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1447 IMPORT : "import" QNAME {
1450 syntaxerror("Couldn't import class\n");
1451 state_has_imports();
1452 dict_put(state->imports, c->name, c);
1455 IMPORT : "import" PACKAGE '.' '*' {
1458 state_has_imports();
1459 list_append(state->wildcard_imports, i);
1463 /* ------------ classes and interfaces (header) -------------- */
1465 MAYBE_MODIFIERS : {$$=0;}
1466 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1467 MODIFIER_LIST : MODIFIER {$$=$1;}
1468 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1470 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1471 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1472 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1473 | KW_STATIC {$$=FLAG_STATIC;}
1474 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1475 | KW_FINAL {$$=FLAG_FINAL;}
1476 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1477 | KW_NATIVE {$$=FLAG_NATIVE;}
1478 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1480 EXTENDS : {$$=registry_getobjectclass();}
1481 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1483 EXTENDS_LIST : {$$=list_new();}
1484 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1486 IMPLEMENTS_LIST : {$$=list_new();}
1487 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1489 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1490 EXTENDS IMPLEMENTS_LIST
1491 '{' {startclass($1,$3,$4,$5, 0);}
1492 MAYBE_DECLARATION_LIST
1495 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1497 '{' {startclass($1,$3,0,$4,1);}
1498 MAYBE_IDECLARATION_LIST
1501 /* ------------ classes and interfaces (body) -------------- */
1503 MAYBE_DECLARATION_LIST :
1504 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1505 DECLARATION_LIST : DECLARATION
1506 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1508 DECLARATION : SLOT_DECLARATION
1509 DECLARATION : FUNCTION_DECLARATION
1511 MAYBE_IDECLARATION_LIST :
1512 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1513 IDECLARATION_LIST : IDECLARATION
1514 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1516 IDECLARATION : "var" T_IDENTIFIER {
1517 syntaxerror("variable declarations not allowed in interfaces");
1519 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1521 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1522 syntaxerror("invalid method modifiers: interface methods always need to be public");
1524 startfunction(0,$1,$3,$4,&$6,$8);
1525 endfunction(0,$1,$3,$4,&$6,$8, 0);
1528 /* ------------ classes and interfaces (body, slots ) ------- */
1530 VARCONST: "var" | "const"
1532 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1534 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1536 info->flags = flags;
1539 namespace_t mname_ns = {flags2access(flags), ""};
1540 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1542 if(!(flags&FLAG_STATIC)) {
1545 t=abc_class_slot(state->cls->abc, &mname, &m);
1547 t=abc_class_slot(state->cls->abc, &mname, 0);
1549 info->slot = t->slot_id;
1553 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1555 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1557 info->slot = t->slot_id;
1559 if($5.c && !is_pushundefined($5.c)) {
1561 c = abc_getlocal_0(c);
1562 c = code_append(c, $5.c);
1563 c = converttype(c, $5.t, $4);
1564 c = abc_setslot(c, t->slot_id);
1565 if(!(flags&FLAG_STATIC))
1566 state->cls->init = code_append(state->cls->init, c);
1568 state->cls->static_init = code_append(state->cls->static_init, c);
1571 t->kind= TRAIT_CONST;
1575 /* ------------ constants -------------------------------------- */
1577 MAYBESTATICCONSTANT: {$$=0;}
1578 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1580 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1581 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1582 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1583 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1584 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1585 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1586 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1587 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1588 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1590 /* ------------ classes and interfaces (body, functions) ------- */
1592 // non-vararg version
1594 memset(&$$,0,sizeof($$));
1596 MAYBE_PARAM_LIST: PARAM_LIST {
1601 MAYBE_PARAM_LIST: "..." PARAM {
1602 memset(&$$,0,sizeof($$));
1604 list_append($$.list, $2);
1606 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1609 list_append($$.list, $4);
1613 PARAM_LIST: PARAM_LIST ',' PARAM {
1615 list_append($$.list, $3);
1618 memset(&$$,0,sizeof($$));
1619 list_append($$.list, $1);
1622 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1623 $$ = malloc(sizeof(param_t));
1628 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1629 $$ = malloc(sizeof(param_t));
1631 $$->type = TYPE_ANY;
1634 GETSET : "get" {$$=$1;}
1638 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1639 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1642 if(state->method->late_binding) {
1643 c = abc_getlocal_0(c);
1644 c = abc_pushscope(c);
1646 if(state->method->is_constructor && !state->method->has_super) {
1647 // call default constructor
1648 c = abc_getlocal_0(c);
1649 c = abc_constructsuper(c, 0);
1651 c = wrap_function(c, state->method->initcode, $11);
1652 endfunction(0,$1,$3,$4,&$6,$8,c);
1655 /* ------------- package + class ids --------------- */
1657 CLASS: T_IDENTIFIER {
1659 /* try current package */
1660 $$ = find_class($1);
1661 if(!$$) syntaxerror("Could not find class %s\n", $1);
1664 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1665 $$ = registry_findclass($1, $3);
1666 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1669 QNAME: PACKAGEANDCLASS
1672 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1673 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1675 TYPE : QNAME {$$=$1;}
1676 | '*' {$$=registry_getanytype();}
1677 | "void" {$$=registry_getanytype();}
1679 | "String" {$$=registry_getstringclass();}
1680 | "int" {$$=registry_getintclass();}
1681 | "uint" {$$=registry_getuintclass();}
1682 | "Boolean" {$$=registry_getbooleanclass();}
1683 | "Number" {$$=registry_getnumberclass();}
1686 MAYBETYPE: ':' TYPE {$$=$2;}
1689 /* ----------function calls, delete, constructor calls ------ */
1691 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1692 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1694 MAYBE_EXPRESSION_LIST : {$$=0;}
1695 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1696 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1697 typedcode_t*t = malloc(sizeof(typedcode_t));
1699 list_append($$, t);}
1700 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1701 typedcode_t*t = malloc(sizeof(typedcode_t));
1703 list_append($$, t);}
1705 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1710 $$.c = abc_getglobalscope($$.c);
1711 $$.c = abc_getslot($$.c, $2->slot);
1713 $$.c = abc_findpropstrict2($$.c, &m);
1716 typedcode_list_t*l = $3;
1719 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1724 $$.c = abc_construct($$.c, len);
1726 $$.c = abc_constructprop2($$.c, &m, len);
1730 /* TODO: use abc_call (for calling local variables),
1731 abc_callstatic (for calling own methods)
1734 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1735 typedcode_list_t*l = $3;
1737 code_t*paramcode = 0;
1739 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1745 if($$.c->opcode == OPCODE_COERCE_A) {
1746 $$.c = code_cutlast($$.c);
1750 multiname_t*name = 0;
1751 if($$.c->opcode == OPCODE_GETPROPERTY) {
1752 name = multiname_clone($$.c->data[0]);
1753 $$.c = code_cutlast($$.c);
1754 $$.c = code_append($$.c, paramcode);
1755 $$.c = abc_callproperty2($$.c, name, len);
1756 } else if($$.c->opcode == OPCODE_GETSLOT) {
1757 int slot = (int)(ptroff_t)$$.c->data[0];
1758 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1759 if(t->kind!=TRAIT_METHOD) {
1760 //ok: flash allows to assign closures to members.
1763 $$.c = code_cutlast($$.c);
1764 $$.c = code_append($$.c, paramcode);
1765 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1766 $$.c = abc_callproperty2($$.c, name, len);
1767 } else if($$.c->opcode == OPCODE_GETSUPER) {
1768 name = multiname_clone($$.c->data[0]);
1769 $$.c = code_cutlast($$.c);
1770 $$.c = code_append($$.c, paramcode);
1771 $$.c = abc_callsuper2($$.c, name, len);
1773 $$.c = abc_getlocal_0($$.c);
1774 $$.c = code_append($$.c, paramcode);
1775 $$.c = abc_call($$.c, len);
1780 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1781 $$.t = $1.t->function->return_type;
1783 $$.c = abc_coerce_a($$.c);
1787 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1788 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1789 if(!state->method) syntaxerror("super() not allowed outside of a function");
1790 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1793 $$.c = abc_getlocal_0($$.c);
1794 typedcode_list_t*l = 0;
1796 for(l=$3;l;l=l->next) {
1797 $$.c = code_append($$.c, l->typedcode->c);len++;
1800 this is dependent on the control path, check this somewhere else
1801 if(state->method->has_super)
1802 syntaxerror("constructor may call super() only once");
1804 state->method->has_super = 1;
1805 $$.c = abc_constructsuper($$.c, len);
1806 $$.c = abc_pushundefined($$.c);
1810 DELETE: "delete" E {
1812 if($$.c->opcode == OPCODE_COERCE_A) {
1813 $$.c = code_cutlast($$.c);
1815 multiname_t*name = 0;
1816 if($$.c->opcode == OPCODE_GETPROPERTY) {
1817 $$.c->opcode = OPCODE_DELETEPROPERTY;
1818 } else if($$.c->opcode == OPCODE_GETSLOT) {
1819 int slot = (int)(ptroff_t)$$.c->data[0];
1820 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1821 $$.c = code_cutlast($$.c);
1822 $$.c = abc_deleteproperty2($$.c, name);
1824 $$.c = abc_getlocal_0($$.c);
1825 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1826 $$.c = abc_deleteproperty2($$.c, &m);
1828 $$.t = TYPE_BOOLEAN;
1831 RETURN: "return" %prec prec_none {
1832 $$ = abc_returnvoid(0);
1834 RETURN: "return" EXPRESSION {
1836 $$ = abc_returnvalue($$);
1839 // ----------------------- expression types -------------------------------------
1841 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1842 EXPRESSION : E %prec below_minus {$$ = $1;}
1843 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1845 $$.c = cut_last_push($$.c);
1846 $$.c = code_append($$.c,$3.c);
1849 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1850 $$=cut_last_push($1.c);
1853 // ----------------------- expression evaluation -------------------------------------
1856 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1858 E : DELETE {$$ = $1;}
1859 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1863 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1864 //MULTINAME(m, registry_getintclass());
1865 //$$.c = abc_coerce2($$.c, &m); // FIXME
1868 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1871 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1874 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1877 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1880 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1883 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1886 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1887 $$.t = TYPE_BOOLEAN;
1889 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1890 $$.t = TYPE_BOOLEAN;
1892 CONSTANT : "null" {$$.c = abc_pushnull(0);
1897 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1898 $$.t = TYPE_BOOLEAN;
1900 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1901 $$.t = TYPE_BOOLEAN;
1903 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1904 $$.t = TYPE_BOOLEAN;
1906 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1907 $$.t = TYPE_BOOLEAN;
1909 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1910 $$.t = TYPE_BOOLEAN;
1912 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1913 $$.t = TYPE_BOOLEAN;
1915 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1916 $$.t = TYPE_BOOLEAN;
1918 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1919 $$.t = TYPE_BOOLEAN;
1922 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1924 $$.c = converttype($$.c, $1.t, $$.t);
1925 $$.c = abc_dup($$.c);
1926 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1927 $$.c = cut_last_push($$.c);
1928 $$.c = code_append($$.c,$3.c);
1929 $$.c = converttype($$.c, $3.t, $$.t);
1930 code_t*label = $$.c = abc_label($$.c);
1931 jmp->branch = label;
1934 $$.t = join_types($1.t, $3.t, 'A');
1935 /*printf("%08x:\n",$1.t);
1936 code_dump($1.c, 0, 0, "", stdout);
1937 printf("%08x:\n",$3.t);
1938 code_dump($3.c, 0, 0, "", stdout);
1939 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1941 $$.c = converttype($$.c, $1.t, $$.t);
1942 $$.c = abc_dup($$.c);
1943 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1944 $$.c = cut_last_push($$.c);
1945 $$.c = code_append($$.c,$3.c);
1946 $$.c = converttype($$.c, $3.t, $$.t);
1947 code_t*label = $$.c = abc_label($$.c);
1948 jmp->branch = label;
1951 E : '!' E {$$.c=$2.c;
1952 $$.c = abc_not($$.c);
1953 $$.t = TYPE_BOOLEAN;
1956 E : '~' E {$$.c=$2.c;
1957 $$.c = abc_bitnot($$.c);
1961 E : E '&' E {$$.c = code_append($1.c,$3.c);
1962 $$.c = abc_bitand($$.c);
1966 E : E '^' E {$$.c = code_append($1.c,$3.c);
1967 $$.c = abc_bitxor($$.c);
1971 E : E '|' E {$$.c = code_append($1.c,$3.c);
1972 $$.c = abc_bitor($$.c);
1976 E : E '-' E {$$.c = code_append($1.c,$3.c);
1977 if(BOTH_INT($1,$3)) {
1978 $$.c = abc_subtract_i($$.c);
1981 $$.c = abc_subtract($$.c);
1985 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1986 $$.c = abc_rshift($$.c);
1989 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1990 $$.c = abc_urshift($$.c);
1993 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1994 $$.c = abc_lshift($$.c);
1998 E : E '/' E {$$.c = code_append($1.c,$3.c);
1999 $$.c = abc_divide($$.c);
2002 E : E '+' E {$$.c = code_append($1.c,$3.c);
2003 $$.c = abc_add($$.c);
2006 E : E '%' E {$$.c = code_append($1.c,$3.c);
2007 $$.c = abc_modulo($$.c);
2010 E : E '*' E {$$.c = code_append($1.c,$3.c);
2011 if(BOTH_INT($1,$3)) {
2012 $$.c = abc_multiply_i($$.c);
2015 $$.c = abc_multiply($$.c);
2020 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2021 if(use_astype && TYPE_IS_CLASS($3.t)) {
2022 MULTINAME(m,$3.t->cls);
2023 $$.c = abc_astype2($1.c, &m);
2026 $$.c = code_append($1.c, $3.c);
2027 $$.c = abc_astypelate($$.c);
2032 E : E "instanceof" E
2033 {$$.c = code_append($1.c, $3.c);
2034 $$.c = abc_instanceof($$.c);
2035 $$.t = TYPE_BOOLEAN;
2038 E : E "is" E {$$.c = code_append($1.c, $3.c);
2039 $$.c = abc_istypelate($$.c);
2040 $$.t = TYPE_BOOLEAN;
2043 E : "typeof" '(' E ')' {
2045 $$.c = abc_typeof($$.c);
2050 $$.c = cut_last_push($2.c);
2051 $$.c = abc_pushundefined($$.c);
2055 E : "void" { $$.c = abc_pushundefined(0);
2059 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2064 $$.c=abc_negate_i($$.c);
2067 $$.c=abc_negate($$.c);
2074 $$.c = code_append($$.c, $3.c);
2076 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2077 $$.c = abc_getproperty2($$.c, &m);
2078 $$.t = 0; // array elements have unknown type
2081 E : '[' MAYBE_EXPRESSION_LIST ']' {
2083 typedcode_list_t*l = 0;
2085 for(l=$2;l;l=l->next) {
2086 $$.c = code_append($$.c, l->typedcode->c);len++;
2088 $$.c = abc_newarray($$.c, len);
2089 $$.t = registry_getarrayclass();
2092 MAYBE_EXPRPAIR_LIST : {$$=0;}
2093 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2095 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2096 typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $1;
2097 typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $3;
2099 list_append($$, t1);
2100 list_append($$, t2);
2102 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2104 typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $3;
2105 typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $5;
2106 list_append($$, t1);
2107 list_append($$, t2);
2112 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2114 typedcode_list_t*l = 0;
2116 for(l=$2;l;l=l->next) {
2117 $$.c = code_append($$.c, l->typedcode->c);len++;
2119 $$.c = abc_newobject($$.c, len/2);
2120 $$.t = registry_getobjectclass();
2125 if(BOTH_INT($1,$3)) {
2126 c=abc_multiply_i(c);
2130 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2131 $$.c = toreadwrite($1.c, c, 0, 0);
2136 code_t*c = abc_modulo($3.c);
2137 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2138 $$.c = toreadwrite($1.c, c, 0, 0);
2142 code_t*c = abc_lshift($3.c);
2143 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2144 $$.c = toreadwrite($1.c, c, 0, 0);
2148 code_t*c = abc_rshift($3.c);
2149 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2150 $$.c = toreadwrite($1.c, c, 0, 0);
2154 code_t*c = abc_urshift($3.c);
2155 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2156 $$.c = toreadwrite($1.c, c, 0, 0);
2160 code_t*c = abc_divide($3.c);
2161 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2162 $$.c = toreadwrite($1.c, c, 0, 0);
2167 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2172 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2174 $$.c = toreadwrite($1.c, c, 0, 0);
2177 E : E "-=" E { code_t*c = $3.c;
2178 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2179 c=abc_subtract_i(c);
2183 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2185 $$.c = toreadwrite($1.c, c, 0, 0);
2188 E : E '=' E { code_t*c = 0;
2189 c = code_append(c, $3.c);
2190 c = converttype(c, $3.t, $1.t);
2191 $$.c = toreadwrite($1.c, c, 1, 0);
2195 E : E '?' E ':' E %prec below_assignment {
2197 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2198 $$.c = code_append($$.c, $3.c);
2199 code_t*j2 = $$.c = abc_jump($$.c, 0);
2200 $$.c = j1->branch = abc_label($$.c);
2201 $$.c = code_append($$.c, $5.c);
2202 $$.c = j2->branch = abc_label($$.c);
2203 $$.t = join_types($3.t,$5.t,'?');
2206 // TODO: use inclocal where appropriate
2207 E : E "++" { code_t*c = 0;
2208 classinfo_t*type = $1.t;
2209 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2210 c=abc_increment_i(c);
2216 c=converttype(c, type, $1.t);
2217 $$.c = toreadwrite($1.c, c, 0, 1);
2220 E : E "--" { code_t*c = 0;
2221 classinfo_t*type = $1.t;
2222 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2223 c=abc_decrement_i(c);
2229 c=converttype(c, type, $1.t);
2230 $$.c = toreadwrite($1.c, c, 0, 1);
2234 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2235 classinfo_t*type = $2.t;
2236 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2237 c=abc_increment_i(c);
2243 c=converttype(c, type, $2.t);
2244 $$.c = toreadwrite($2.c, c, 0, 0);
2248 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2249 classinfo_t*type = $2.t;
2250 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2251 c=abc_decrement_i(c);
2257 c=converttype(c, type, $2.t);
2258 $$.c = toreadwrite($2.c, c, 0, 0);
2262 E : "super" '.' T_IDENTIFIER
2263 { if(!state->cls->info)
2264 syntaxerror("super keyword not allowed outside a class");
2265 classinfo_t*t = state->cls->info->superclass;
2266 if(!t) t = TYPE_OBJECT;
2268 memberinfo_t*f = registry_findmember(t, $3);
2269 namespace_t ns = {flags2access(f->flags), ""};
2270 MEMBER_MULTINAME(m, f, $3);
2272 $$.c = abc_getlocal_0($$.c);
2273 $$.c = abc_getsuper2($$.c, &m);
2274 $$.t = memberinfo_gettype(f);
2277 E : E '.' T_IDENTIFIER
2279 classinfo_t*t = $1.t;
2281 if(TYPE_IS_CLASS(t) && t->cls) {
2286 memberinfo_t*f = registry_findmember(t, $3);
2288 if(f && !is_static != !(f->flags&FLAG_STATIC))
2290 if(f && f->slot && !noslot) {
2291 $$.c = abc_getslot($$.c, f->slot);
2293 MEMBER_MULTINAME(m, f, $3);
2294 $$.c = abc_getproperty2($$.c, &m);
2296 /* determine type */
2297 $$.t = memberinfo_gettype(f);
2299 $$.c = abc_coerce_a($$.c);
2301 /* when resolving a property on an unknown type, we do know the
2302 name of the property (and don't seem to need the package), but
2303 we need to make avm2 try out all access modes */
2304 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2305 $$.c = abc_getproperty2($$.c, &m);
2306 $$.c = abc_coerce_a($$.c);
2307 $$.t = registry_getanytype();
2311 VAR_READ : T_IDENTIFIER {
2318 /* look at variables */
2319 if((i = find_variable($1, &$$.t)) >= 0) {
2320 // $1 is a local variable
2321 $$.c = abc_getlocal($$.c, i);
2323 /* look at current class' members */
2324 } else if((f = registry_findmember(state->cls->info, $1))) {
2325 // $1 is a function in this class
2326 int var_is_static = (f->flags&FLAG_STATIC);
2327 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2328 if(var_is_static != i_am_static) {
2329 /* there doesn't seem to be any "static" way to access
2330 static properties of a class */
2331 state->method->late_binding = 1;
2333 namespace_t ns = {flags2access(f->flags), ""};
2334 multiname_t m = {QNAME, &ns, 0, $1};
2335 $$.c = abc_findpropstrict2($$.c, &m);
2336 $$.c = abc_getproperty2($$.c, &m);
2339 $$.c = abc_getlocal_0($$.c);
2340 $$.c = abc_getslot($$.c, f->slot);
2342 namespace_t ns = {flags2access(f->flags), ""};
2343 multiname_t m = {QNAME, &ns, 0, $1};
2344 $$.c = abc_getlocal_0($$.c);
2345 $$.c = abc_getproperty2($$.c, &m);
2348 if(f->kind == MEMBER_METHOD) {
2349 $$.t = TYPE_FUNCTION(f);
2354 /* look at classes in the current package and imported classes */
2355 } else if((a = find_class($1))) {
2356 if(a->flags & FLAG_METHOD) {
2358 $$.c = abc_findpropstrict2($$.c, &m);
2359 $$.c = abc_getproperty2($$.c, &m);
2360 $$.t = TYPE_FUNCTION(a->function);
2363 $$.c = abc_getglobalscope($$.c);
2364 $$.c = abc_getslot($$.c, a->slot);
2367 $$.c = abc_getlex2($$.c, &m);
2369 $$.t = TYPE_CLASS(a);
2372 /* unknown object, let the avm2 resolve it */
2374 if(strcmp($1,"trace"))
2375 warning("Couldn't resolve '%s', doing late binding", $1);
2376 state->method->late_binding = 1;
2378 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2381 $$.c = abc_findpropstrict2($$.c, &m);
2382 $$.c = abc_getproperty2($$.c, &m);
2387 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2388 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2389 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2391 // ----------------- namespaces -------------------------------------------------
2393 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2394 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2395 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2397 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER