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((minfo = registry_findmember(state->cls->info, name, 0))) {
759 if(minfo->parent == state->cls->info) {
760 syntaxerror("class already contains a member/method called '%s'", name);
761 } else if(!minfo->parent) {
762 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
764 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
765 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
768 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
769 minfo->return_type = return_type;
770 // getslot on a member slot only returns "undefined", so no need
771 // to actually store these
772 //state->minfo->slot = state->method->abc->method->trait->slot_id;
774 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
778 else if(params->list)
779 type = params->list->param->type;
780 // not sure wether to look into superclasses here, too
781 if((minfo=registry_findmember(state->cls->info, name, 0))) {
782 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
783 syntaxerror("class already contains a member or method called '%s'", name);
785 syntaxerror("getter/setter for '%s' already defined", name);
786 /* make a setter or getter into a getset */
791 if(type && minfo->type != type)
792 syntaxerror("different type in getter and setter");
794 minfo = memberinfo_register(state->cls->info, name, gs);
797 /* can't assign a slot as getter and setter might have different slots */
798 //minfo->slot = slot;
800 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
801 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
802 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
803 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
804 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
805 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
809 static int flags2access(int flags)
812 if(flags&FLAG_PUBLIC) {
813 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
814 access = ACCESS_PACKAGE;
815 } else if(flags&FLAG_PRIVATE) {
816 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
817 access = ACCESS_PRIVATE;
818 } else if(flags&FLAG_PROTECTED) {
819 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
820 access = ACCESS_PROTECTED;
822 access = ACCESS_PACKAGEINTERNAL;
827 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
828 params_t*params, classinfo_t*return_type)
831 syntaxerror("not able to start another method scope");
834 state->method = rfx_calloc(sizeof(methodstate_t));
835 state->method->initcode = 0;
836 state->method->is_constructor = !strcmp(state->cls->info->name,name);
837 state->method->has_super = 0;
839 state->cls->has_constructor |= state->method->is_constructor;
841 global->variable_count = 0;
843 /* state->vars is initialized by state_new */
844 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
846 for(p=params->list;p;p=p->next) {
847 new_variable(p->param->name, p->param->type);
849 if(state->method->is_constructor)
850 name = "__as3_constructor__";
851 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
854 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
855 params_t*params, classinfo_t*return_type, code_t*body)
857 namespace_t mname_ns = {flags2access(flags), ""};
858 multiname_t mname = {QNAME, &mname_ns, 0, name};
862 multiname_t*type2 = sig2mname(return_type);
864 if(state->method->is_constructor) {
865 f = abc_class_getconstructor(state->cls->abc, type2);
867 if(flags&FLAG_STATIC)
868 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
870 f = abc_class_method(state->cls->abc, type2, &mname);
871 slot = f->trait->slot_id;
873 //flash doesn't seem to allow us to access function slots
874 //state->method->info->slot = slot;
876 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
877 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
878 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
879 if(params->varargs) f->flags |= METHOD_NEED_REST;
883 for(p=params->list;p;p=p->next) {
884 if(params->varargs && !p->next) {
885 break; //varargs: omit last parameter in function signature
887 multiname_t*m = sig2mname(p->param->type);
888 list_append(f->parameters, m);
889 if(p->param->value) {
890 check_constant_against_type(p->param->type, p->param->value);
891 opt=1;list_append(f->optional_parameters, p->param->value);
893 syntaxerror("non-optional parameter not allowed after optional parameters");
896 check_code_for_break(body);
899 f->body->code = body;
902 syntaxerror("interface methods can't have a method body");
909 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
914 void breakjumpsto(code_t*c, char*name, code_t*jump)
917 if(c->opcode == OPCODE___BREAK__) {
918 string_t*name2 = c->data[0];
919 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
920 c->opcode = OPCODE_JUMP;
927 void continuejumpsto(code_t*c, char*name, code_t*jump)
930 if(c->opcode == OPCODE___CONTINUE__) {
931 string_t*name2 = c->data[0];
932 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
933 c->opcode = OPCODE_JUMP;
941 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
944 return registry_getanytype();
945 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
946 return registry_getanytype();
949 return registry_getanytype();
951 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
956 return abc_coerce_a(c);
960 // cast an "any" type to a specific type. subject to
961 // runtime exceptions
962 return abc_coerce2(c, &m);
965 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
966 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
967 // allow conversion between number types
968 return abc_coerce2(c, &m);
970 //printf("%s.%s\n", from.package, from.name);
971 //printf("%s.%s\n", to.package, to.name);
973 classinfo_t*supertype = from;
975 if(supertype == to) {
976 // target type is one of from's superclasses
977 return abc_coerce2(c, &m);
980 while(supertype->interfaces[t]) {
981 if(supertype->interfaces[t]==to) {
982 // target type is one of from's interfaces
983 return abc_coerce2(c, &m);
987 supertype = supertype->superclass;
989 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
991 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
993 syntaxerror("can't convert type %s to %s", from->name, to->name);
996 code_t*defaultvalue(code_t*c, classinfo_t*type)
998 if(TYPE_IS_INT(type)) {
999 c = abc_pushbyte(c, 0);
1000 } else if(TYPE_IS_UINT(type)) {
1001 c = abc_pushuint(c, 0);
1002 } else if(TYPE_IS_FLOAT(type)) {
1004 } else if(TYPE_IS_BOOLEAN(type)) {
1005 c = abc_pushfalse(c);
1007 c = abc_pushnull(c);
1012 char is_pushundefined(code_t*c)
1014 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1017 void parserassert(int b)
1019 if(!b) syntaxerror("internal error: assertion failed");
1022 static classinfo_t* find_class(char*name)
1026 c = registry_findclass(state->package, name);
1028 /* try explicit imports */
1029 dictentry_t* e = dict_get_slot(state->imports, name);
1033 if(!strcmp(e->key, name)) {
1034 c = (classinfo_t*)e->data;
1039 /* try package.* imports */
1040 import_list_t*l = state->wildcard_imports;
1044 //printf("does package %s contain a class %s?\n", l->import->package, name);
1045 c = registry_findclass(l->import->package, name);
1049 /* try global package */
1051 c = registry_findclass("", name);
1056 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1060 [prefix code] [read instruction]
1064 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1067 if(in && in->opcode == OPCODE_COERCE_A) {
1068 in = code_cutlast(in);
1071 syntaxerror("internal error");
1073 /* chop off read instruction */
1077 prefix = r->prev;r->prev = 0;
1083 char use_temp_var = readbefore;
1085 /* generate the write instruction, and maybe append a dup to the prefix code */
1086 code_t* write = abc_nop(0);
1087 if(r->opcode == OPCODE_GETPROPERTY) {
1088 write->opcode = OPCODE_SETPROPERTY;
1089 multiname_t*m = (multiname_t*)r->data[0];
1090 write->data[0] = multiname_clone(m);
1091 if(m->type == QNAME || m->type == MULTINAME) {
1093 prefix = abc_dup(prefix); // we need the object, too
1096 } else if(m->type == MULTINAMEL) {
1098 /* dupping two values on the stack requires 5 operations and one register-
1099 couldn't adobe just have given us a dup2? */
1100 int temp = gettempvar();
1101 prefix = abc_setlocal(prefix, temp);
1102 prefix = abc_dup(prefix);
1103 prefix = abc_getlocal(prefix, temp);
1104 prefix = abc_swap(prefix);
1105 prefix = abc_getlocal(prefix, temp);
1109 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1111 } else if(r->opcode == OPCODE_GETSLOT) {
1112 write->opcode = OPCODE_SETSLOT;
1113 write->data[0] = r->data[0];
1115 prefix = abc_dup(prefix); // we need the object, too
1118 } else if(r->opcode == OPCODE_GETLOCAL) {
1119 write->opcode = OPCODE_SETLOCAL;
1120 write->data[0] = r->data[0];
1121 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1122 write->opcode = OPCODE_SETLOCAL_0;
1123 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1124 write->opcode = OPCODE_SETLOCAL_1;
1125 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1126 write->opcode = OPCODE_SETLOCAL_2;
1127 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1128 write->opcode = OPCODE_SETLOCAL_3;
1130 code_dump(r, 0, 0, "", stdout);
1131 syntaxerror("illegal lvalue: can't assign a value to this expression");
1138 /* with getproperty/getslot, we have to be extra careful not
1139 to execute the read code twice, as it might have side-effects
1140 (e.g. if the property is in fact a setter/getter combination)
1142 So read the value, modify it, and write it again,
1143 using prefix only once and making sure (by using a temporary
1144 register) that the return value is what we just wrote */
1145 temp = gettempvar();
1146 c = code_append(c, prefix);
1147 c = code_append(c, r);
1150 c = abc_setlocal(c, temp);
1152 c = code_append(c, middlepart);
1155 c = abc_setlocal(c, temp);
1157 c = code_append(c, write);
1158 c = abc_getlocal(c, temp);
1159 c = abc_kill(c, temp);
1161 /* if we're allowed to execute the read code twice *and*
1162 the middlepart doesn't modify the code, things are easier.
1164 code_t* r2 = code_dup(r);
1165 //c = code_append(c, prefix);
1166 parserassert(!prefix);
1167 c = code_append(c, r);
1168 c = code_append(c, middlepart);
1169 c = code_append(c, write);
1170 c = code_append(c, r2);
1173 /* even smaller version: overwrite the value without reading
1177 c = code_append(c, prefix);
1180 c = code_append(c, middlepart);
1181 c = code_append(c, write);
1182 c = code_append(c, r);
1184 temp = gettempvar();
1186 c = code_append(c, prefix);
1189 c = code_append(c, middlepart);
1191 c = abc_setlocal(c, temp);
1192 c = code_append(c, write);
1193 c = abc_getlocal(c, temp);
1200 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1201 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1208 /* ------------ code blocks / statements ---------------- */
1210 PROGRAM: MAYBECODE {
1211 /* todo: do something with this code if we're outside a function */
1213 warning("ignored code");
1216 MAYBECODE: CODE {$$=$1;}
1217 MAYBECODE: {$$=code_new();}
1219 CODE: CODE CODEPIECE {
1220 $$=code_append($1,$2);
1226 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1227 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1228 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1229 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1230 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1231 CODEPIECE: ';' {$$=code_new();}
1232 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1233 CODEPIECE: VOIDEXPRESSION {$$=$1}
1234 CODEPIECE: FOR {$$=$1}
1235 CODEPIECE: WHILE {$$=$1}
1236 CODEPIECE: DO_WHILE {$$=$1}
1237 CODEPIECE: SWITCH {$$=$1}
1238 CODEPIECE: BREAK {$$=$1}
1239 CODEPIECE: CONTINUE {$$=$1}
1240 CODEPIECE: RETURN {$$=$1}
1241 CODEPIECE: IF {$$=$1}
1242 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1243 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1245 CODEBLOCK : '{' CODE '}' {$$=$2;}
1246 CODEBLOCK : '{' '}' {$$=0;}
1247 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1248 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1250 /* ------------ variables --------------------------- */
1252 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1253 | {$$.c=abc_pushundefined(0);
1257 VAR : "const" | "var"
1258 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1260 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1261 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1263 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1265 if(variable_exists($2))
1266 syntaxerror("Variable %s already defined", $2);
1268 if(!is_subtype_of($4.t, $3)) {
1269 syntaxerror("Can't convert %s to %s", $4.t->name,
1273 int index = new_variable($2, $3);
1276 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1278 $$ = converttype($$, $4.t, $3);
1279 $$ = abc_setlocal($$, index);
1281 $$ = defaultvalue(0, $3);
1282 $$ = abc_setlocal($$, index);
1285 /* if this is a typed variable:
1286 push default value for type on stack */
1288 state->method->initcode = defaultvalue(state->method->initcode, $3);
1289 state->method->initcode = abc_setlocal(state->method->initcode, index);
1292 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1294 $$ = abc_coerce_a($$);
1295 $$ = abc_setlocal($$, index);
1301 /* that's the default for a local register, anyway
1303 state->method->initcode = abc_pushundefined(state->method->initcode);
1304 state->method->initcode = abc_setlocal(state->method->initcode, index);
1306 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1309 /* ------------ control flow ------------------------- */
1311 MAYBEELSE: %prec below_else {$$ = code_new();}
1312 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1313 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1315 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1317 $$ = code_append($$, $4.c);
1318 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1320 $$ = code_append($$, $6);
1322 myjmp = $$ = abc_jump($$, 0);
1324 myif->branch = $$ = abc_nop($$);
1326 $$ = code_append($$, $7);
1327 myjmp->branch = $$ = abc_nop($$);
1330 $$ = killvars($$);old_state();
1333 FOR_INIT : {$$=code_new();}
1334 FOR_INIT : VARIABLE_DECLARATION
1335 FOR_INIT : VOIDEXPRESSION
1337 FOR : T_FOR '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1339 $$ = code_append($$, $4);
1340 code_t*loopstart = $$ = abc_label($$);
1341 $$ = code_append($$, $6.c);
1342 code_t*myif = $$ = abc_iffalse($$, 0);
1343 $$ = code_append($$, $10);
1344 code_t*cont = $$ = abc_nop($$);
1345 $$ = code_append($$, $8);
1346 $$ = abc_jump($$, loopstart);
1347 code_t*out = $$ = abc_nop($$);
1348 breakjumpsto($$, $1, out);
1349 continuejumpsto($$, $1, cont);
1352 $$ = killvars($$);old_state();
1355 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1358 code_t*myjmp = $$ = abc_jump($$, 0);
1359 code_t*loopstart = $$ = abc_label($$);
1360 $$ = code_append($$, $6);
1361 code_t*cont = $$ = abc_nop($$);
1362 myjmp->branch = cont;
1363 $$ = code_append($$, $4.c);
1364 $$ = abc_iftrue($$, loopstart);
1365 code_t*out = $$ = abc_nop($$);
1366 breakjumpsto($$, $1, out);
1367 continuejumpsto($$, $1, cont);
1373 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1375 code_t*loopstart = $$ = abc_label($$);
1376 $$ = code_append($$, $3);
1377 code_t*cont = $$ = abc_nop($$);
1378 $$ = code_append($$, $6.c);
1379 $$ = abc_iftrue($$, loopstart);
1380 code_t*out = $$ = abc_nop($$);
1381 breakjumpsto($$, $1, out);
1382 continuejumpsto($$, $1, cont);
1387 BREAK : "break" %prec prec_none {
1388 $$ = abc___break__(0, "");
1390 BREAK : "break" T_IDENTIFIER {
1391 $$ = abc___break__(0, $2);
1393 CONTINUE : "continue" %prec prec_none {
1394 $$ = abc___continue__(0, "");
1396 CONTINUE : "continue" T_IDENTIFIER {
1397 $$ = abc___continue__(0, $2);
1400 MAYBE_CASE_LIST : {$$=0;}
1401 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1402 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1403 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1404 CASE_LIST: CASE {$$=$1}
1405 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1407 CASE: "case" E ':' MAYBECODE {
1409 $$ = code_append($$, $2.c);
1410 code_t*j = $$ = abc_ifne($$, 0);
1411 $$ = code_append($$, $4);
1412 if($$->opcode != OPCODE___BREAK__) {
1413 $$ = abc___fallthrough__($$, "");
1415 code_t*e = $$ = abc_nop($$);
1418 DEFAULT: "default" ':' MAYBECODE {
1421 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1423 $$ = code_append($$, $7);
1424 code_t*out = $$ = abc_pop($$);
1425 breakjumpsto($$, $1, out);
1427 code_t*c = $$,*lastblock=0;
1429 if(c->opcode == OPCODE_IFNE) {
1430 if(!c->next) syntaxerror("internal error in fallthrough handling");
1432 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1434 c->opcode = OPCODE_JUMP;
1435 c->branch = lastblock;
1437 /* fall through end of switch */
1438 c->opcode = OPCODE_NOP;
1446 /* ------------ packages and imports ---------------- */
1448 X_IDENTIFIER: T_IDENTIFIER
1449 | "package" {$$="package";}
1451 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1452 PACKAGE: X_IDENTIFIER {$$=$1;}
1454 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1455 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1457 IMPORT : "import" QNAME {
1460 syntaxerror("Couldn't import class\n");
1461 state_has_imports();
1462 dict_put(state->imports, c->name, c);
1465 IMPORT : "import" PACKAGE '.' '*' {
1468 state_has_imports();
1469 list_append(state->wildcard_imports, i);
1473 /* ------------ classes and interfaces (header) -------------- */
1475 MAYBE_MODIFIERS : {$$=0;}
1476 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1477 MODIFIER_LIST : MODIFIER {$$=$1;}
1478 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1480 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1481 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1482 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1483 | KW_STATIC {$$=FLAG_STATIC;}
1484 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1485 | KW_FINAL {$$=FLAG_FINAL;}
1486 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1487 | KW_NATIVE {$$=FLAG_NATIVE;}
1488 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1490 EXTENDS : {$$=registry_getobjectclass();}
1491 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1493 EXTENDS_LIST : {$$=list_new();}
1494 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1496 IMPLEMENTS_LIST : {$$=list_new();}
1497 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1499 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1500 EXTENDS IMPLEMENTS_LIST
1501 '{' {startclass($1,$3,$4,$5, 0);}
1502 MAYBE_DECLARATION_LIST
1505 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1507 '{' {startclass($1,$3,0,$4,1);}
1508 MAYBE_IDECLARATION_LIST
1511 /* ------------ classes and interfaces (body) -------------- */
1513 MAYBE_DECLARATION_LIST :
1514 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1515 DECLARATION_LIST : DECLARATION
1516 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1518 DECLARATION : SLOT_DECLARATION
1519 DECLARATION : FUNCTION_DECLARATION
1521 MAYBE_IDECLARATION_LIST :
1522 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1523 IDECLARATION_LIST : IDECLARATION
1524 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1526 IDECLARATION : "var" T_IDENTIFIER {
1527 syntaxerror("variable declarations not allowed in interfaces");
1529 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1531 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1532 syntaxerror("invalid method modifiers: interface methods always need to be public");
1534 startfunction(0,$1,$3,$4,&$6,$8);
1535 endfunction(0,$1,$3,$4,&$6,$8, 0);
1538 /* ------------ classes and interfaces (body, slots ) ------- */
1540 VARCONST: "var" | "const"
1542 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1544 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1546 info->flags = flags;
1549 namespace_t mname_ns = {flags2access(flags), ""};
1550 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1552 if(!(flags&FLAG_STATIC)) {
1555 t=abc_class_slot(state->cls->abc, &mname, &m);
1557 t=abc_class_slot(state->cls->abc, &mname, 0);
1559 info->slot = t->slot_id;
1563 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1565 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1567 info->slot = t->slot_id;
1569 if($5.c && !is_pushundefined($5.c)) {
1571 c = abc_getlocal_0(c);
1572 c = code_append(c, $5.c);
1573 c = converttype(c, $5.t, $4);
1574 c = abc_setslot(c, t->slot_id);
1575 if(!(flags&FLAG_STATIC))
1576 state->cls->init = code_append(state->cls->init, c);
1578 state->cls->static_init = code_append(state->cls->static_init, c);
1581 t->kind= TRAIT_CONST;
1585 /* ------------ constants -------------------------------------- */
1587 MAYBESTATICCONSTANT: {$$=0;}
1588 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1590 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1591 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1592 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1593 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1594 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1595 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1596 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1597 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1598 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1600 /* ------------ classes and interfaces (body, functions) ------- */
1602 // non-vararg version
1604 memset(&$$,0,sizeof($$));
1606 MAYBE_PARAM_LIST: PARAM_LIST {
1611 MAYBE_PARAM_LIST: "..." PARAM {
1612 memset(&$$,0,sizeof($$));
1614 list_append($$.list, $2);
1616 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1619 list_append($$.list, $4);
1623 PARAM_LIST: PARAM_LIST ',' PARAM {
1625 list_append($$.list, $3);
1628 memset(&$$,0,sizeof($$));
1629 list_append($$.list, $1);
1632 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1633 $$ = malloc(sizeof(param_t));
1638 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1639 $$ = malloc(sizeof(param_t));
1641 $$->type = TYPE_ANY;
1644 GETSET : "get" {$$=$1;}
1648 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1649 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1652 if(state->method->late_binding) {
1653 c = abc_getlocal_0(c);
1654 c = abc_pushscope(c);
1656 if(state->method->is_constructor && !state->method->has_super) {
1657 // call default constructor
1658 c = abc_getlocal_0(c);
1659 c = abc_constructsuper(c, 0);
1661 c = wrap_function(c, state->method->initcode, $11);
1662 endfunction(0,$1,$3,$4,&$6,$8,c);
1665 /* ------------- package + class ids --------------- */
1667 CLASS: T_IDENTIFIER {
1669 /* try current package */
1670 $$ = find_class($1);
1671 if(!$$) syntaxerror("Could not find class %s\n", $1);
1674 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1675 $$ = registry_findclass($1, $3);
1676 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1679 QNAME: PACKAGEANDCLASS
1682 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1683 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1685 TYPE : QNAME {$$=$1;}
1686 | '*' {$$=registry_getanytype();}
1687 | "void" {$$=registry_getanytype();}
1689 | "String" {$$=registry_getstringclass();}
1690 | "int" {$$=registry_getintclass();}
1691 | "uint" {$$=registry_getuintclass();}
1692 | "Boolean" {$$=registry_getbooleanclass();}
1693 | "Number" {$$=registry_getnumberclass();}
1696 MAYBETYPE: ':' TYPE {$$=$2;}
1699 /* ----------function calls, delete, constructor calls ------ */
1701 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1702 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1704 MAYBE_EXPRESSION_LIST : {$$=0;}
1705 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1706 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1707 typedcode_t*t = malloc(sizeof(typedcode_t));
1709 list_append($$, t);}
1710 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1711 typedcode_t*t = malloc(sizeof(typedcode_t));
1713 list_append($$, t);}
1715 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1720 $$.c = abc_getglobalscope($$.c);
1721 $$.c = abc_getslot($$.c, $2->slot);
1723 $$.c = abc_findpropstrict2($$.c, &m);
1726 typedcode_list_t*l = $3;
1729 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1734 $$.c = abc_construct($$.c, len);
1736 $$.c = abc_constructprop2($$.c, &m, len);
1740 /* TODO: use abc_call (for calling local variables),
1741 abc_callstatic (for calling own methods)
1744 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1745 typedcode_list_t*l = $3;
1747 code_t*paramcode = 0;
1749 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1755 if($$.c->opcode == OPCODE_COERCE_A) {
1756 $$.c = code_cutlast($$.c);
1760 multiname_t*name = 0;
1761 if($$.c->opcode == OPCODE_GETPROPERTY) {
1762 name = multiname_clone($$.c->data[0]);
1763 $$.c = code_cutlast($$.c);
1764 $$.c = code_append($$.c, paramcode);
1765 $$.c = abc_callproperty2($$.c, name, len);
1766 } else if($$.c->opcode == OPCODE_GETSLOT) {
1767 int slot = (int)(ptroff_t)$$.c->data[0];
1768 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1769 if(t->kind!=TRAIT_METHOD) {
1770 //ok: flash allows to assign closures to members.
1773 $$.c = code_cutlast($$.c);
1774 $$.c = code_append($$.c, paramcode);
1775 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1776 $$.c = abc_callproperty2($$.c, name, len);
1777 } else if($$.c->opcode == OPCODE_GETSUPER) {
1778 name = multiname_clone($$.c->data[0]);
1779 $$.c = code_cutlast($$.c);
1780 $$.c = code_append($$.c, paramcode);
1781 $$.c = abc_callsuper2($$.c, name, len);
1783 $$.c = abc_getlocal_0($$.c);
1784 $$.c = code_append($$.c, paramcode);
1785 $$.c = abc_call($$.c, len);
1790 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1791 $$.t = $1.t->function->return_type;
1793 $$.c = abc_coerce_a($$.c);
1797 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1798 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1799 if(!state->method) syntaxerror("super() not allowed outside of a function");
1800 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1803 $$.c = abc_getlocal_0($$.c);
1804 typedcode_list_t*l = 0;
1806 for(l=$3;l;l=l->next) {
1807 $$.c = code_append($$.c, l->typedcode->c);len++;
1810 this is dependent on the control path, check this somewhere else
1811 if(state->method->has_super)
1812 syntaxerror("constructor may call super() only once");
1814 state->method->has_super = 1;
1815 $$.c = abc_constructsuper($$.c, len);
1816 $$.c = abc_pushundefined($$.c);
1820 DELETE: "delete" E {
1822 if($$.c->opcode == OPCODE_COERCE_A) {
1823 $$.c = code_cutlast($$.c);
1825 multiname_t*name = 0;
1826 if($$.c->opcode == OPCODE_GETPROPERTY) {
1827 $$.c->opcode = OPCODE_DELETEPROPERTY;
1828 } else if($$.c->opcode == OPCODE_GETSLOT) {
1829 int slot = (int)(ptroff_t)$$.c->data[0];
1830 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1831 $$.c = code_cutlast($$.c);
1832 $$.c = abc_deleteproperty2($$.c, name);
1834 $$.c = abc_getlocal_0($$.c);
1835 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1836 $$.c = abc_deleteproperty2($$.c, &m);
1838 $$.t = TYPE_BOOLEAN;
1841 RETURN: "return" %prec prec_none {
1842 $$ = abc_returnvoid(0);
1844 RETURN: "return" EXPRESSION {
1846 $$ = abc_returnvalue($$);
1849 // ----------------------- expression types -------------------------------------
1851 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1852 EXPRESSION : E %prec below_minus {$$ = $1;}
1853 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1855 $$.c = cut_last_push($$.c);
1856 $$.c = code_append($$.c,$3.c);
1859 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1860 $$=cut_last_push($1.c);
1863 // ----------------------- expression evaluation -------------------------------------
1866 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1868 E : DELETE {$$ = $1;}
1869 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1873 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1874 //MULTINAME(m, registry_getintclass());
1875 //$$.c = abc_coerce2($$.c, &m); // FIXME
1878 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1881 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1884 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1887 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1890 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1893 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1896 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1897 $$.t = TYPE_BOOLEAN;
1899 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1900 $$.t = TYPE_BOOLEAN;
1902 CONSTANT : "null" {$$.c = abc_pushnull(0);
1907 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1908 $$.t = TYPE_BOOLEAN;
1910 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1911 $$.t = TYPE_BOOLEAN;
1913 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1914 $$.t = TYPE_BOOLEAN;
1916 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1917 $$.t = TYPE_BOOLEAN;
1919 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1920 $$.t = TYPE_BOOLEAN;
1922 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1923 $$.t = TYPE_BOOLEAN;
1925 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1926 $$.t = TYPE_BOOLEAN;
1928 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1929 $$.t = TYPE_BOOLEAN;
1932 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1934 $$.c = converttype($$.c, $1.t, $$.t);
1935 $$.c = abc_dup($$.c);
1936 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1937 $$.c = cut_last_push($$.c);
1938 $$.c = code_append($$.c,$3.c);
1939 $$.c = converttype($$.c, $3.t, $$.t);
1940 code_t*label = $$.c = abc_label($$.c);
1941 jmp->branch = label;
1944 $$.t = join_types($1.t, $3.t, 'A');
1945 /*printf("%08x:\n",$1.t);
1946 code_dump($1.c, 0, 0, "", stdout);
1947 printf("%08x:\n",$3.t);
1948 code_dump($3.c, 0, 0, "", stdout);
1949 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1951 $$.c = converttype($$.c, $1.t, $$.t);
1952 $$.c = abc_dup($$.c);
1953 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1954 $$.c = cut_last_push($$.c);
1955 $$.c = code_append($$.c,$3.c);
1956 $$.c = converttype($$.c, $3.t, $$.t);
1957 code_t*label = $$.c = abc_label($$.c);
1958 jmp->branch = label;
1961 E : '!' E {$$.c=$2.c;
1962 $$.c = abc_not($$.c);
1963 $$.t = TYPE_BOOLEAN;
1966 E : '~' E {$$.c=$2.c;
1967 $$.c = abc_bitnot($$.c);
1971 E : E '&' E {$$.c = code_append($1.c,$3.c);
1972 $$.c = abc_bitand($$.c);
1976 E : E '^' E {$$.c = code_append($1.c,$3.c);
1977 $$.c = abc_bitxor($$.c);
1981 E : E '|' E {$$.c = code_append($1.c,$3.c);
1982 $$.c = abc_bitor($$.c);
1986 E : E '-' E {$$.c = code_append($1.c,$3.c);
1987 if(BOTH_INT($1,$3)) {
1988 $$.c = abc_subtract_i($$.c);
1991 $$.c = abc_subtract($$.c);
1995 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1996 $$.c = abc_rshift($$.c);
1999 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2000 $$.c = abc_urshift($$.c);
2003 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2004 $$.c = abc_lshift($$.c);
2008 E : E '/' E {$$.c = code_append($1.c,$3.c);
2009 $$.c = abc_divide($$.c);
2012 E : E '+' E {$$.c = code_append($1.c,$3.c);
2013 $$.c = abc_add($$.c);
2016 E : E '%' E {$$.c = code_append($1.c,$3.c);
2017 $$.c = abc_modulo($$.c);
2020 E : E '*' E {$$.c = code_append($1.c,$3.c);
2021 if(BOTH_INT($1,$3)) {
2022 $$.c = abc_multiply_i($$.c);
2025 $$.c = abc_multiply($$.c);
2030 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2031 if(use_astype && TYPE_IS_CLASS($3.t)) {
2032 MULTINAME(m,$3.t->cls);
2033 $$.c = abc_astype2($1.c, &m);
2036 $$.c = code_append($1.c, $3.c);
2037 $$.c = abc_astypelate($$.c);
2042 E : E "instanceof" E
2043 {$$.c = code_append($1.c, $3.c);
2044 $$.c = abc_instanceof($$.c);
2045 $$.t = TYPE_BOOLEAN;
2048 E : E "is" E {$$.c = code_append($1.c, $3.c);
2049 $$.c = abc_istypelate($$.c);
2050 $$.t = TYPE_BOOLEAN;
2053 E : "typeof" '(' E ')' {
2055 $$.c = abc_typeof($$.c);
2060 $$.c = cut_last_push($2.c);
2061 $$.c = abc_pushundefined($$.c);
2065 E : "void" { $$.c = abc_pushundefined(0);
2069 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2074 $$.c=abc_negate_i($$.c);
2077 $$.c=abc_negate($$.c);
2084 $$.c = code_append($$.c, $3.c);
2086 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2087 $$.c = abc_getproperty2($$.c, &m);
2088 $$.t = 0; // array elements have unknown type
2091 E : '[' MAYBE_EXPRESSION_LIST ']' {
2093 typedcode_list_t*l = 0;
2095 for(l=$2;l;l=l->next) {
2096 $$.c = code_append($$.c, l->typedcode->c);len++;
2098 $$.c = abc_newarray($$.c, len);
2099 $$.t = registry_getarrayclass();
2102 MAYBE_EXPRPAIR_LIST : {$$=0;}
2103 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2105 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2106 typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $1;
2107 typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $3;
2109 list_append($$, t1);
2110 list_append($$, t2);
2112 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2114 typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $3;
2115 typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $5;
2116 list_append($$, t1);
2117 list_append($$, t2);
2122 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2124 typedcode_list_t*l = 0;
2126 for(l=$2;l;l=l->next) {
2127 $$.c = code_append($$.c, l->typedcode->c);len++;
2129 $$.c = abc_newobject($$.c, len/2);
2130 $$.t = registry_getobjectclass();
2135 if(BOTH_INT($1,$3)) {
2136 c=abc_multiply_i(c);
2140 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2141 $$.c = toreadwrite($1.c, c, 0, 0);
2146 code_t*c = abc_modulo($3.c);
2147 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2148 $$.c = toreadwrite($1.c, c, 0, 0);
2152 code_t*c = abc_lshift($3.c);
2153 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2154 $$.c = toreadwrite($1.c, c, 0, 0);
2158 code_t*c = abc_rshift($3.c);
2159 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2160 $$.c = toreadwrite($1.c, c, 0, 0);
2164 code_t*c = abc_urshift($3.c);
2165 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2166 $$.c = toreadwrite($1.c, c, 0, 0);
2170 code_t*c = abc_divide($3.c);
2171 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2172 $$.c = toreadwrite($1.c, c, 0, 0);
2177 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2182 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2184 $$.c = toreadwrite($1.c, c, 0, 0);
2187 E : E "-=" E { code_t*c = $3.c;
2188 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2189 c=abc_subtract_i(c);
2193 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2195 $$.c = toreadwrite($1.c, c, 0, 0);
2198 E : E '=' E { code_t*c = 0;
2199 c = code_append(c, $3.c);
2200 c = converttype(c, $3.t, $1.t);
2201 $$.c = toreadwrite($1.c, c, 1, 0);
2205 E : E '?' E ':' E %prec below_assignment {
2207 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2208 $$.c = code_append($$.c, $3.c);
2209 code_t*j2 = $$.c = abc_jump($$.c, 0);
2210 $$.c = j1->branch = abc_label($$.c);
2211 $$.c = code_append($$.c, $5.c);
2212 $$.c = j2->branch = abc_label($$.c);
2213 $$.t = join_types($3.t,$5.t,'?');
2216 // TODO: use inclocal where appropriate
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_increment_i(c);
2226 c=converttype(c, type, $1.t);
2227 $$.c = toreadwrite($1.c, c, 0, 1);
2230 E : E "--" { code_t*c = 0;
2231 classinfo_t*type = $1.t;
2232 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2233 c=abc_decrement_i(c);
2239 c=converttype(c, type, $1.t);
2240 $$.c = toreadwrite($1.c, c, 0, 1);
2244 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2245 classinfo_t*type = $2.t;
2246 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2247 c=abc_increment_i(c);
2253 c=converttype(c, type, $2.t);
2254 $$.c = toreadwrite($2.c, c, 0, 0);
2258 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2259 classinfo_t*type = $2.t;
2260 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2261 c=abc_decrement_i(c);
2267 c=converttype(c, type, $2.t);
2268 $$.c = toreadwrite($2.c, c, 0, 0);
2272 E : "super" '.' T_IDENTIFIER
2273 { if(!state->cls->info)
2274 syntaxerror("super keyword not allowed outside a class");
2275 classinfo_t*t = state->cls->info->superclass;
2276 if(!t) t = TYPE_OBJECT;
2278 memberinfo_t*f = registry_findmember(t, $3, 1);
2279 namespace_t ns = {flags2access(f->flags), ""};
2280 MEMBER_MULTINAME(m, f, $3);
2282 $$.c = abc_getlocal_0($$.c);
2283 $$.c = abc_getsuper2($$.c, &m);
2284 $$.t = memberinfo_gettype(f);
2287 E : E '.' T_IDENTIFIER
2289 classinfo_t*t = $1.t;
2291 if(TYPE_IS_CLASS(t) && t->cls) {
2296 memberinfo_t*f = registry_findmember(t, $3, 1);
2298 if(f && !is_static != !(f->flags&FLAG_STATIC))
2300 if(f && f->slot && !noslot) {
2301 $$.c = abc_getslot($$.c, f->slot);
2303 MEMBER_MULTINAME(m, f, $3);
2304 $$.c = abc_getproperty2($$.c, &m);
2306 /* determine type */
2307 $$.t = memberinfo_gettype(f);
2309 $$.c = abc_coerce_a($$.c);
2311 /* when resolving a property on an unknown type, we do know the
2312 name of the property (and don't seem to need the package), but
2313 we need to make avm2 try out all access modes */
2314 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2315 $$.c = abc_getproperty2($$.c, &m);
2316 $$.c = abc_coerce_a($$.c);
2317 $$.t = registry_getanytype();
2321 VAR_READ : T_IDENTIFIER {
2328 /* look at variables */
2329 if((i = find_variable($1, &$$.t)) >= 0) {
2330 // $1 is a local variable
2331 $$.c = abc_getlocal($$.c, i);
2333 /* look at current class' members */
2334 } else if((f = registry_findmember(state->cls->info, $1, 1))) {
2335 // $1 is a function in this class
2336 int var_is_static = (f->flags&FLAG_STATIC);
2337 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2338 if(var_is_static != i_am_static) {
2339 /* there doesn't seem to be any "static" way to access
2340 static properties of a class */
2341 state->method->late_binding = 1;
2343 namespace_t ns = {flags2access(f->flags), ""};
2344 multiname_t m = {QNAME, &ns, 0, $1};
2345 $$.c = abc_findpropstrict2($$.c, &m);
2346 $$.c = abc_getproperty2($$.c, &m);
2349 $$.c = abc_getlocal_0($$.c);
2350 $$.c = abc_getslot($$.c, f->slot);
2352 namespace_t ns = {flags2access(f->flags), ""};
2353 multiname_t m = {QNAME, &ns, 0, $1};
2354 $$.c = abc_getlocal_0($$.c);
2355 $$.c = abc_getproperty2($$.c, &m);
2358 if(f->kind == MEMBER_METHOD) {
2359 $$.t = TYPE_FUNCTION(f);
2364 /* look at actual classes, in the current package and imported */
2365 } else if((a = find_class($1))) {
2366 if(a->flags & FLAG_METHOD) {
2368 $$.c = abc_findpropstrict2($$.c, &m);
2369 $$.c = abc_getproperty2($$.c, &m);
2370 $$.t = TYPE_FUNCTION(a->function);
2373 $$.c = abc_getglobalscope($$.c);
2374 $$.c = abc_getslot($$.c, a->slot);
2377 $$.c = abc_getlex2($$.c, &m);
2379 $$.t = TYPE_CLASS(a);
2382 /* unknown object, let the avm2 resolve it */
2384 if(strcmp($1,"trace"))
2385 warning("Couldn't resolve '%s', doing late binding", $1);
2386 state->method->late_binding = 1;
2388 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2391 $$.c = abc_findpropstrict2($$.c, &m);
2392 $$.c = abc_getproperty2($$.c, &m);
2397 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2398 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2399 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2401 // ----------------- namespaces -------------------------------------------------
2403 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2404 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2405 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2407 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER