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;
54 codeandnumber_t value_list;
60 for_start_t for_start;
64 %token<id> T_IDENTIFIER
66 %token<token> T_REGEXP
68 %token<number_int> T_INT
69 %token<number_uint> T_UINT
70 %token<number_uint> T_BYTE
71 %token<number_uint> T_SHORT
72 %token<number_float> T_FLOAT
74 %token<id> T_FOR "for"
75 %token<id> T_WHILE "while"
77 %token<id> T_SWITCH "switch"
79 %token<token> KW_IMPLEMENTS
80 %token<token> KW_NAMESPACE "namespace"
81 %token<token> KW_PACKAGE "package"
82 %token<token> KW_PROTECTED
83 %token<token> KW_PUBLIC
84 %token<token> KW_PRIVATE
85 %token<token> KW_USE "use"
86 %token<token> KW_INTERNAL
87 %token<token> KW_NEW "new"
88 %token<token> KW_NATIVE
89 %token<token> KW_FUNCTION "function"
90 %token<token> KW_UNDEFINED "undefined"
91 %token<token> KW_CONTINUE "continue"
92 %token<token> KW_CLASS "class"
93 %token<token> KW_CONST "const"
94 %token<token> KW_CATCH "catch"
95 %token<token> KW_CASE "case"
96 %token<token> KW_SET "set"
97 %token<token> KW_VOID "void"
98 %token<token> KW_STATIC
99 %token<token> KW_INSTANCEOF "instanceof"
100 %token<token> KW_IMPORT "import"
101 %token<token> KW_RETURN "return"
102 %token<token> KW_TYPEOF "typeof"
103 %token<token> KW_INTERFACE "interface"
104 %token<token> KW_NULL "null"
105 %token<token> KW_VAR "var"
106 %token<token> KW_DYNAMIC "dynamic"
107 %token<token> KW_OVERRIDE
108 %token<token> KW_FINAL
109 %token<token> KW_EACH "each"
110 %token<token> KW_GET "get"
111 %token<token> KW_TRY "try"
112 %token<token> KW_SUPER "super"
113 %token<token> KW_EXTENDS
114 %token<token> KW_FALSE "false"
115 %token<token> KW_TRUE "true"
116 %token<token> KW_BOOLEAN "Boolean"
117 %token<token> KW_UINT "uint"
118 %token<token> KW_INT "int"
119 %token<token> KW_NUMBER "Number"
120 %token<token> KW_STRING "String"
121 %token<token> KW_DEFAULT "default"
122 %token<token> KW_DELETE "delete"
123 %token<token> KW_IF "if"
124 %token<token> KW_ELSE "else"
125 %token<token> KW_BREAK "break"
126 %token<token> KW_IS "is"
127 %token<token> KW_IN "in"
128 %token<token> KW_AS "as"
130 %token<token> T_EQEQ "=="
131 %token<token> T_EQEQEQ "==="
132 %token<token> T_NE "!="
133 %token<token> T_NEE "!=="
134 %token<token> T_LE "<="
135 %token<token> T_GE ">="
136 %token<token> T_DIVBY "/="
137 %token<token> T_MODBY "%="
138 %token<token> T_MULBY "*="
139 %token<token> T_PLUSBY "+="
140 %token<token> T_MINUSBY "-="
141 %token<token> T_SHRBY ">>="
142 %token<token> T_SHLBY "<<="
143 %token<token> T_USHRBY ">>>="
144 %token<token> T_OROR "||"
145 %token<token> T_ANDAND "&&"
146 %token<token> T_COLONCOLON "::"
147 %token<token> T_MINUSMINUS "--"
148 %token<token> T_PLUSPLUS "++"
149 %token<token> T_DOTDOT ".."
150 %token<token> T_DOTDOTDOT "..."
151 %token<token> T_SHL "<<"
152 %token<token> T_USHR ">>>"
153 %token<token> T_SHR ">>"
155 %type <for_start> FOR_START
156 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
157 %type <token> VARCONST
159 %type <code> CODEPIECE
160 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
161 %type <token> PACKAGE_DECLARATION
162 %type <token> FUNCTION_DECLARATION
163 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
164 %type <token> CLASS_DECLARATION
165 %type <token> NAMESPACE_DECLARATION
166 %type <token> INTERFACE_DECLARATION
167 %type <code> VOIDEXPRESSION
168 %type <value> EXPRESSION NONCOMMAEXPRESSION
169 %type <value> MAYBEEXPRESSION
170 %type <value> E DELETE
171 %type <value> CONSTANT
172 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
173 %type <token> USE_NAMESPACE
174 %type <code> FOR_INIT
176 %type <classinfo> MAYBETYPE
179 %type <params> PARAM_LIST
180 %type <params> MAYBE_PARAM_LIST
181 %type <flags> MAYBE_MODIFIERS
182 %type <flags> MODIFIER_LIST
183 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
184 %type <classinfo_list> IMPLEMENTS_LIST
185 %type <classinfo> EXTENDS
186 %type <classinfo_list> EXTENDS_LIST
187 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
188 %type <classinfo_list> QNAME_LIST
189 %type <classinfo> TYPE
190 //%type <token> VARIABLE
191 %type <value> VAR_READ
193 //%type <token> T_IDENTIFIER
194 %type <token> MODIFIER
195 %type <value> FUNCTIONCALL
196 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
198 // precedence: from low to high
202 %left below_semicolon
205 %nonassoc below_assignment // for ?:, contrary to spec
206 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
213 %nonassoc "==" "!=" "===" "!=="
214 %nonassoc "is" "as" "in"
215 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
216 %left "<<" ">>" ">>>"
220 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
222 %nonassoc below_curly
223 %left '[' ']' '{' "new" '.' ".." "::"
224 %nonassoc T_IDENTIFIER
225 %left above_identifier
230 // needed for "return" precedence:
231 %nonassoc T_STRING T_REGEXP
232 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
233 %nonassoc "false" "true" "null" "undefined" "super"
239 static int yyerror(char*s)
241 syntaxerror("%s", s);
244 static char* concat2(const char* t1, const char* t2)
248 char*text = malloc(l1+l2+1);
249 memcpy(text , t1, l1);
250 memcpy(text+l1, t2, l2);
254 static char* concat3(const char* t1, const char* t2, const char* t3)
259 char*text = malloc(l1+l2+l3+1);
260 memcpy(text , t1, l1);
261 memcpy(text+l1, t2, l2);
262 memcpy(text+l1+l2, t3, l3);
267 typedef struct _import {
271 DECLARE_LIST(import);
273 typedef struct _classstate {
279 char has_constructor;
282 typedef struct _methodstate {
286 /* code that needs to be executed at the start of
287 a method (like initializing local registers) */
293 typedef struct _state {
298 import_list_t*wildcard_imports;
300 char has_own_imports;
303 methodstate_t*method;
308 typedef struct _global {
315 static global_t*global = 0;
316 static state_t* state = 0;
320 #define MULTINAME(m,x) \
323 registry_fill_multiname(&m, &m##_ns, x);
325 #define MEMBER_MULTINAME(m,f,n) \
329 m##_ns.access = flags2access(f->flags); \
333 m.namespace_set = 0; \
336 m.type = MULTINAME; \
338 m.namespace_set = &nopackage_namespace_set; \
342 /* warning: list length of namespace set is undefined */
343 #define MULTINAME_LATE(m, access, package) \
344 namespace_t m##_ns = {access, package}; \
345 namespace_set_t m##_nsset; \
346 namespace_list_t m##_l;m##_l.next = 0; \
347 m##_nsset.namespaces = &m##_l; \
348 m##_nsset = m##_nsset; \
349 m##_l.namespace = &m##_ns; \
350 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
352 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
353 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
354 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
355 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
356 static namespace_list_t nl4 = {&ns4,0};
357 static namespace_list_t nl3 = {&ns3,&nl4};
358 static namespace_list_t nl2 = {&ns2,&nl3};
359 static namespace_list_t nl1 = {&ns1,&nl2};
360 static namespace_set_t nopackage_namespace_set = {&nl1};
362 static void init_globals()
364 global = rfx_calloc(sizeof(global_t));
367 static void new_state()
370 state_t*oldstate = state;
372 memcpy(s, state, sizeof(state_t)); //shallow copy
374 s->imports = dict_new();
378 state->has_own_imports = 0;
379 state->vars = dict_new();
380 state->old = oldstate;
382 static void state_has_imports()
384 state->wildcard_imports = list_clone(state->wildcard_imports);
385 state->imports = dict_clone(state->imports);
386 state->has_own_imports = 1;
389 static void state_destroy(state_t*state)
391 if(state->has_own_imports) {
392 list_free(state->wildcard_imports);
393 dict_destroy(state->imports);state->imports=0;
395 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
396 dict_destroy(state->imports);state->imports=0;
400 for(t=0;t<state->vars->hashsize;t++) {
401 dictentry_t*e =state->vars->slots[t];
403 free(e->data);e->data=0;
407 dict_destroy(state->vars);state->vars=0;
413 static void old_state()
415 if(!state || !state->old)
416 syntaxerror("invalid nesting");
417 state_t*leaving = state;
419 /*if(state->method->initcode) {
420 printf("residual initcode\n");
421 code_dump(state->method->initcode, 0, 0, "", stdout);
423 state_destroy(leaving);
425 void initialize_state()
430 global->file = abc_file_new();
431 global->file->flags &= ~ABCFILE_LAZY;
433 global->init = abc_initscript(global->file, 0);
434 code_t*c = global->init->method->body->code;
436 c = abc_getlocal_0(c);
437 c = abc_pushscope(c);
439 /* findpropstrict doesn't just return a scope object- it
440 also makes it "active" somehow. Push local_0 on the
441 scope stack and read it back with findpropstrict, it'll
442 contain properties like "trace". Trying to find the same
443 property on a "vanilla" local_0 yields only a "undefined" */
444 //c = abc_findpropstrict(c, "[package]::trace");
446 /*c = abc_getlocal_0(c);
447 c = abc_findpropstrict(c, "[package]::trace");
449 c = abc_setlocal_1(c);
451 c = abc_pushbyte(c, 0);
452 c = abc_setlocal_2(c);
454 code_t*xx = c = abc_label(c);
455 c = abc_findpropstrict(c, "[package]::trace");
456 c = abc_pushstring(c, "prop:");
457 c = abc_hasnext2(c, 1, 2);
459 c = abc_setlocal_3(c);
460 c = abc_callpropvoid(c, "[package]::trace", 2);
461 c = abc_getlocal_3(c);
463 c = abc_iftrue(c,xx);*/
465 c = abc_findpropstrict(c, "[package]::trace");
466 c = abc_pushstring(c, "[entering global init function]");
467 c = abc_callpropvoid(c, "[package]::trace", 1);
469 global->init->method->body->code = c;
471 void* finalize_state()
473 if(state->level!=1) {
474 syntaxerror("unexpected end of file");
476 abc_method_body_t*m = global->init->method->body;
479 __ findpropstrict(m, "[package]::trace");
480 __ pushstring(m, "[leaving global init function]");
481 __ callpropvoid(m, "[package]::trace", 1);
484 state_destroy(state);
490 static void startpackage(char*name)
493 syntaxerror("Packages can not be nested.");
496 /*printf("entering package \"%s\"\n", name);*/
497 state->package = strdup(name);
499 static void endpackage()
501 /*printf("leaving package \"%s\"\n", state->package);*/
503 //used e.g. in classinfo_register:
504 //free(state->package);state->package=0;
510 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
513 syntaxerror("inner classes now allowed");
516 state->cls = rfx_calloc(sizeof(classstate_t));
519 classinfo_list_t*mlist=0;
520 /*printf("entering class %s\n", name);
521 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
523 printf(" extends: %s.%s\n", extends->package, extends->name);
524 printf(" implements (%d): ", list_length(implements));
525 for(mlist=implements;mlist;mlist=mlist->next) {
526 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
531 if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
532 syntaxerror("invalid modifier(s)");
534 if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
535 syntaxerror("public and internal not supported at the same time.");
537 /* create the class name, together with the proper attributes */
541 if(!(flags&FLAG_PUBLIC) && !state->package) {
542 access = ACCESS_PRIVATE; package = current_filename;
543 } else if(!(flags&FLAG_PUBLIC) && state->package) {
544 access = ACCESS_PACKAGEINTERNAL; package = state->package;
545 } else if(state->package) {
546 access = ACCESS_PACKAGE; package = state->package;
548 syntaxerror("public classes only allowed inside a package");
551 if(registry_findclass(package, classname)) {
552 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
556 /* build info struct */
557 int num_interfaces = (list_length(implements));
558 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
559 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
561 classinfo_list_t*l = implements;
562 for(l=implements;l;l=l->next) {
563 state->cls->info->interfaces[pos++] = l->classinfo;
566 multiname_t*extends2 = sig2mname(extends);
568 MULTINAME(classname2,state->cls->info);
571 state->cls_init = abc_getlocal_0(state->cls_init);
572 state->cls_init = abc_constructsuper(state->cls_init, 0);
575 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
576 if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
577 if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
579 state->cls->info->flags |= CLASS_INTERFACE;
580 abc_class_interface(state->cls->abc);
583 abc_class_protectedNS(state->cls->abc, classname);
585 for(mlist=implements;mlist;mlist=mlist->next) {
586 MULTINAME(m, mlist->classinfo);
587 abc_class_add_interface(state->cls->abc, &m);
590 /* now write the construction code for this class */
591 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
593 abc_method_body_t*m = global->init->method->body;
594 __ getglobalscope(m);
595 classinfo_t*s = extends;
600 //TODO: take a look at the current scope stack, maybe
601 // we can re-use something
606 multiname_t*s2 = sig2mname(s);
608 multiname_destroy(s2);
610 __ pushscope(m); count++;
611 m->code = m->code->prev->prev; // invert
613 /* continue appending after last op end */
614 while(m->code && m->code->next) m->code = m->code->next;
616 /* TODO: if this is one of *our* classes, we can also
617 do a getglobalscope/getslot <nr> (which references
618 the init function's slots) */
620 __ getlex2(m, extends2);
622 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
623 stack is not the superclass */
624 __ pushscope(m);count++;
627 /* notice: we get a verify error #1107 if the top element on the scope
628 stack is not the global object */
630 __ pushscope(m);count++;
632 __ newclass(m,state->cls->abc);
636 __ setslot(m, slotindex);
638 /* flash.display.MovieClip handling */
639 if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
640 if(state->package && state->package[0]) {
641 globalclass = concat3(state->package, ".", classname);
643 globalclass = strdup(classname);
646 multiname_destroy(extends2);
649 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
651 c = code_append(c, initcode);
652 c = code_append(c, body);
653 /* append return if necessary */
654 if(!c || c->opcode != OPCODE_RETURNVOID &&
655 c->opcode != OPCODE_RETURNVALUE) {
656 c = abc_returnvoid(c);
661 static void endclass()
663 if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
665 c = abc_getlocal_0(c);
666 c = abc_constructsuper(c, 0);
667 state->cls->init = code_append(state->cls->init, c);
670 if(state->cls->init) {
671 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
672 m->body->code = wrap_function(0, state->cls->init, m->body->code);
674 if(state->cls->static_init) {
675 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
676 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
678 // handy for scope testing
682 abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
685 free(state->cls);state->cls=0;
689 typedef struct _variable {
694 static variable_t* find_variable(char*name)
700 v = dict_lookup(s->vars, name);
708 static variable_t* find_variable_safe(char*name)
710 variable_t* v = find_variable(name);
712 syntaxerror("undefined variable: %s", name);
715 static char variable_exists(char*name)
717 return dict_lookup(state->vars, name)!=0;
719 code_t*defaultvalue(code_t*c, classinfo_t*type);
720 static int new_variable(char*name, classinfo_t*type, char init)
723 v->index = global->variable_count;
725 dict_put(state->vars, name, v);
727 if(init && state->method && type) {
728 /* if this is a typed variable:
729 push default value for type on stack at the very beginning of the
730 method, so that it always has that type regardless of the control
732 state->method->initcode = defaultvalue(state->method->initcode, type);
733 state->method->initcode = abc_setlocal(state->method->initcode, v->index);
735 return global->variable_count++;
737 #define TEMPVARNAME "__as3_temp__"
738 static int gettempvar()
740 variable_t*v = find_variable(TEMPVARNAME);
743 return new_variable(TEMPVARNAME, 0, 0);
746 code_t* killvars(code_t*c)
749 for(t=0;t<state->vars->hashsize;t++) {
750 dictentry_t*e =state->vars->slots[t];
752 variable_t*v = (variable_t*)e->data;
753 //do this always, otherwise register types don't match
754 //in the verifier when doing nested loops
755 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
756 c = abc_kill(c, v->index);
763 void check_code_for_break(code_t*c)
766 if(c->opcode == OPCODE___BREAK__) {
767 char*name = string_cstr(c->data[0]);
768 syntaxerror("Unresolved \"break %s\"", name);
770 if(c->opcode == OPCODE___CONTINUE__) {
771 char*name = string_cstr(c->data[0]);
772 syntaxerror("Unresolved \"continue %s\"", name);
779 static void check_constant_against_type(classinfo_t*t, constant_t*c)
781 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
782 if(TYPE_IS_NUMBER(t)) {
783 xassert(c->type == CONSTANT_FLOAT
784 || c->type == CONSTANT_INT
785 || c->type == CONSTANT_UINT);
786 } else if(TYPE_IS_UINT(t)) {
787 xassert(c->type == CONSTANT_UINT ||
788 (c->type == CONSTANT_INT && c->i>0));
789 } else if(TYPE_IS_INT(t)) {
790 xassert(c->type == CONSTANT_INT);
791 } else if(TYPE_IS_BOOLEAN(t)) {
792 xassert(c->type == CONSTANT_TRUE
793 || c->type == CONSTANT_FALSE);
797 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
799 memberinfo_t*minfo = 0;
800 if(getset != KW_GET && getset != KW_SET) {
801 if((minfo = registry_findmember(state->cls->info, name, 0))) {
802 if(minfo->parent == state->cls->info) {
803 syntaxerror("class already contains a member/method called '%s'", name);
804 } else if(!minfo->parent) {
805 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
807 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
808 syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
811 minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
812 minfo->return_type = return_type;
813 // getslot on a member slot only returns "undefined", so no need
814 // to actually store these
815 //state->minfo->slot = state->method->abc->method->trait->slot_id;
817 int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
821 else if(params->list)
822 type = params->list->param->type;
823 // not sure wether to look into superclasses here, too
824 if((minfo=registry_findmember(state->cls->info, name, 0))) {
825 if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
826 syntaxerror("class already contains a member or method called '%s'", name);
828 syntaxerror("getter/setter for '%s' already defined", name);
829 /* make a setter or getter into a getset */
834 if(type && minfo->type != type)
835 syntaxerror("different type in getter and setter");
837 minfo = memberinfo_register(state->cls->info, name, gs);
840 /* can't assign a slot as getter and setter might have different slots */
841 //minfo->slot = slot;
843 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
844 if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
845 if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
846 if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
847 if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
848 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
852 static int flags2access(int flags)
855 if(flags&FLAG_PUBLIC) {
856 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
857 access = ACCESS_PACKAGE;
858 } else if(flags&FLAG_PRIVATE) {
859 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
860 access = ACCESS_PRIVATE;
861 } else if(flags&FLAG_PROTECTED) {
862 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
863 access = ACCESS_PROTECTED;
865 access = ACCESS_PACKAGEINTERNAL;
870 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
871 params_t*params, classinfo_t*return_type)
874 syntaxerror("not able to start another method scope");
877 state->method = rfx_calloc(sizeof(methodstate_t));
878 state->method->initcode = 0;
879 state->method->is_constructor = !strcmp(state->cls->info->name,name);
880 state->method->has_super = 0;
882 state->cls->has_constructor |= state->method->is_constructor;
884 global->variable_count = 0;
886 /* state->vars is initialized by state_new */
887 if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0)!=0) syntaxerror("Internal error");
889 for(p=params->list;p;p=p->next) {
890 new_variable(p->param->name, p->param->type, 0);
892 if(state->method->is_constructor)
893 name = "__as3_constructor__";
894 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
897 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
898 params_t*params, classinfo_t*return_type, code_t*body)
900 namespace_t mname_ns = {flags2access(flags), ""};
901 multiname_t mname = {QNAME, &mname_ns, 0, name};
905 multiname_t*type2 = sig2mname(return_type);
907 if(state->method->is_constructor) {
908 f = abc_class_getconstructor(state->cls->abc, type2);
910 if(flags&FLAG_STATIC)
911 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
913 f = abc_class_method(state->cls->abc, type2, &mname);
914 slot = f->trait->slot_id;
916 //flash doesn't seem to allow us to access function slots
917 //state->method->info->slot = slot;
919 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
920 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
921 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
922 if(params->varargs) f->flags |= METHOD_NEED_REST;
926 for(p=params->list;p;p=p->next) {
927 if(params->varargs && !p->next) {
928 break; //varargs: omit last parameter in function signature
930 multiname_t*m = sig2mname(p->param->type);
931 list_append(f->parameters, m);
932 if(p->param->value) {
933 check_constant_against_type(p->param->type, p->param->value);
934 opt=1;list_append(f->optional_parameters, p->param->value);
936 syntaxerror("non-optional parameter not allowed after optional parameters");
939 check_code_for_break(body);
942 f->body->code = body;
945 syntaxerror("interface methods can't have a method body");
947 free(state->method);state->method=0;
953 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
958 void breakjumpsto(code_t*c, char*name, code_t*jump)
961 if(c->opcode == OPCODE___BREAK__) {
962 string_t*name2 = c->data[0];
963 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
964 c->opcode = OPCODE_JUMP;
971 void continuejumpsto(code_t*c, char*name, code_t*jump)
974 if(c->opcode == OPCODE___CONTINUE__) {
975 string_t*name2 = c->data[0];
976 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
977 c->opcode = OPCODE_JUMP;
985 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
988 return registry_getanytype();
989 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
990 return registry_getanytype();
993 return registry_getanytype();
995 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1000 return abc_coerce_a(c);
1004 // cast an "any" type to a specific type. subject to
1005 // runtime exceptions
1006 return abc_coerce2(c, &m);
1009 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1010 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1011 // allow conversion between number types
1012 return abc_coerce2(c, &m);
1014 //printf("%s.%s\n", from.package, from.name);
1015 //printf("%s.%s\n", to.package, to.name);
1017 classinfo_t*supertype = from;
1019 if(supertype == to) {
1020 // target type is one of from's superclasses
1021 return abc_coerce2(c, &m);
1024 while(supertype->interfaces[t]) {
1025 if(supertype->interfaces[t]==to) {
1026 // target type is one of from's interfaces
1027 return abc_coerce2(c, &m);
1031 supertype = supertype->superclass;
1033 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1035 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1037 syntaxerror("can't convert type %s to %s", from->name, to->name);
1040 code_t*defaultvalue(code_t*c, classinfo_t*type)
1042 if(TYPE_IS_INT(type)) {
1043 c = abc_pushbyte(c, 0);
1044 } else if(TYPE_IS_UINT(type)) {
1045 c = abc_pushuint(c, 0);
1046 } else if(TYPE_IS_FLOAT(type)) {
1048 } else if(TYPE_IS_BOOLEAN(type)) {
1049 c = abc_pushfalse(c);
1051 c = abc_pushnull(c);
1056 char is_pushundefined(code_t*c)
1058 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1061 void parserassert(int b)
1063 if(!b) syntaxerror("internal error: assertion failed");
1066 static classinfo_t* find_class(char*name)
1070 c = registry_findclass(state->package, name);
1072 /* try explicit imports */
1073 dictentry_t* e = dict_get_slot(state->imports, name);
1077 if(!strcmp(e->key, name)) {
1078 c = (classinfo_t*)e->data;
1083 /* try package.* imports */
1084 import_list_t*l = state->wildcard_imports;
1088 //printf("does package %s contain a class %s?\n", l->import->package, name);
1089 c = registry_findclass(l->import->package, name);
1093 /* try global package */
1095 c = registry_findclass("", name);
1100 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1104 [prefix code] [read instruction]
1108 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1111 if(in && in->opcode == OPCODE_COERCE_A) {
1112 in = code_cutlast(in);
1115 syntaxerror("internal error");
1117 /* chop off read instruction */
1121 prefix = r->prev;r->prev = 0;
1127 char use_temp_var = readbefore;
1129 /* generate the write instruction, and maybe append a dup to the prefix code */
1130 code_t* write = abc_nop(0);
1131 if(r->opcode == OPCODE_GETPROPERTY) {
1132 write->opcode = OPCODE_SETPROPERTY;
1133 multiname_t*m = (multiname_t*)r->data[0];
1134 write->data[0] = multiname_clone(m);
1135 if(m->type == QNAME || m->type == MULTINAME) {
1137 prefix = abc_dup(prefix); // we need the object, too
1140 } else if(m->type == MULTINAMEL) {
1142 /* dupping two values on the stack requires 5 operations and one register-
1143 couldn't adobe just have given us a dup2? */
1144 int temp = gettempvar();
1145 prefix = abc_setlocal(prefix, temp);
1146 prefix = abc_dup(prefix);
1147 prefix = abc_getlocal(prefix, temp);
1148 prefix = abc_swap(prefix);
1149 prefix = abc_getlocal(prefix, temp);
1153 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1155 } else if(r->opcode == OPCODE_GETSLOT) {
1156 write->opcode = OPCODE_SETSLOT;
1157 write->data[0] = r->data[0];
1159 prefix = abc_dup(prefix); // we need the object, too
1162 } else if(r->opcode == OPCODE_GETLOCAL) {
1163 write->opcode = OPCODE_SETLOCAL;
1164 write->data[0] = r->data[0];
1165 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1166 write->opcode = OPCODE_SETLOCAL_0;
1167 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1168 write->opcode = OPCODE_SETLOCAL_1;
1169 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1170 write->opcode = OPCODE_SETLOCAL_2;
1171 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1172 write->opcode = OPCODE_SETLOCAL_3;
1174 code_dump(r, 0, 0, "", stdout);
1175 syntaxerror("illegal lvalue: can't assign a value to this expression");
1182 /* with getproperty/getslot, we have to be extra careful not
1183 to execute the read code twice, as it might have side-effects
1184 (e.g. if the property is in fact a setter/getter combination)
1186 So read the value, modify it, and write it again,
1187 using prefix only once and making sure (by using a temporary
1188 register) that the return value is what we just wrote */
1189 temp = gettempvar();
1190 c = code_append(c, prefix);
1191 c = code_append(c, r);
1194 c = abc_setlocal(c, temp);
1196 c = code_append(c, middlepart);
1199 c = abc_setlocal(c, temp);
1201 c = code_append(c, write);
1202 c = abc_getlocal(c, temp);
1203 c = abc_kill(c, temp);
1205 /* if we're allowed to execute the read code twice *and*
1206 the middlepart doesn't modify the code, things are easier.
1208 code_t* r2 = code_dup(r);
1209 //c = code_append(c, prefix);
1210 parserassert(!prefix);
1211 c = code_append(c, r);
1212 c = code_append(c, middlepart);
1213 c = code_append(c, write);
1214 c = code_append(c, r2);
1217 /* even smaller version: overwrite the value without reading
1221 c = code_append(c, prefix);
1224 c = code_append(c, middlepart);
1225 c = code_append(c, write);
1226 c = code_append(c, r);
1228 temp = gettempvar();
1230 c = code_append(c, prefix);
1232 c = code_append(c, middlepart);
1234 c = abc_setlocal(c, temp);
1235 c = code_append(c, write);
1236 c = abc_getlocal(c, temp);
1237 c = abc_kill(c, temp);
1244 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1245 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1252 /* ------------ code blocks / statements ---------------- */
1254 PROGRAM: MAYBECODE {
1255 /* todo: do something with this code if we're outside a function */
1257 warning("ignored code");
1260 MAYBECODE: CODE {$$=$1;}
1261 MAYBECODE: {$$=code_new();}
1263 CODE: CODE CODEPIECE {
1264 $$=code_append($1,$2);
1270 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1271 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1272 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1273 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1274 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1275 CODEPIECE: ';' {$$=code_new();}
1276 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1277 CODEPIECE: VOIDEXPRESSION {$$=$1}
1278 CODEPIECE: FOR {$$=$1}
1279 CODEPIECE: FOR_IN {$$=$1}
1280 CODEPIECE: WHILE {$$=$1}
1281 CODEPIECE: DO_WHILE {$$=$1}
1282 CODEPIECE: SWITCH {$$=$1}
1283 CODEPIECE: BREAK {$$=$1}
1284 CODEPIECE: CONTINUE {$$=$1}
1285 CODEPIECE: RETURN {$$=$1}
1286 CODEPIECE: IF {$$=$1}
1287 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1288 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1290 CODEBLOCK : '{' CODE '}' {$$=$2;}
1291 CODEBLOCK : '{' '}' {$$=0;}
1292 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1293 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1295 /* ------------ variables --------------------------- */
1297 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1298 | {$$.c=abc_pushundefined(0);
1302 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1303 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1305 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1306 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1308 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1310 if(variable_exists($1))
1311 syntaxerror("Variable %s already defined", $1);
1313 if(!is_subtype_of($3.t, $2)) {
1314 syntaxerror("Can't convert %s to %s", $3.t->name,
1318 int index = new_variable($1, $2, 1);
1321 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1323 $$ = converttype($$, $3.t, $2);
1324 $$ = abc_setlocal($$, index);
1326 $$ = defaultvalue(0, $2);
1327 $$ = abc_setlocal($$, index);
1330 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1332 $$ = abc_coerce_a($$);
1333 $$ = abc_setlocal($$, index);
1339 /* that's the default for a local register, anyway
1341 state->method->initcode = abc_pushundefined(state->method->initcode);
1342 state->method->initcode = abc_setlocal(state->method->initcode, index);
1344 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1347 /* ------------ control flow ------------------------- */
1349 MAYBEELSE: %prec below_else {$$ = code_new();}
1350 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1351 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1353 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1355 $$ = code_append($$, $4.c);
1356 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1358 $$ = code_append($$, $6);
1360 myjmp = $$ = abc_jump($$, 0);
1362 myif->branch = $$ = abc_nop($$);
1364 $$ = code_append($$, $7);
1365 myjmp->branch = $$ = abc_nop($$);
1368 $$ = killvars($$);old_state();
1371 FOR_INIT : {$$=code_new();}
1372 FOR_INIT : VARIABLE_DECLARATION
1373 FOR_INIT : VOIDEXPRESSION
1374 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1375 $$=$2;new_variable($2,$3,1);
1377 FOR_IN_INIT : T_IDENTIFIER {
1381 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1382 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1384 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1385 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1387 $$ = code_append($$, $2);
1388 code_t*loopstart = $$ = abc_label($$);
1389 $$ = code_append($$, $4.c);
1390 code_t*myif = $$ = abc_iffalse($$, 0);
1391 $$ = code_append($$, $8);
1392 code_t*cont = $$ = abc_nop($$);
1393 $$ = code_append($$, $6);
1394 $$ = abc_jump($$, loopstart);
1395 code_t*out = $$ = abc_nop($$);
1396 breakjumpsto($$, $1.name, out);
1397 continuejumpsto($$, $1.name, cont);
1400 $$ = killvars($$);old_state();
1403 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1404 variable_t*var = find_variable($2);
1405 char*tmp1name = concat2($2, "__tmp1__");
1406 int it = new_variable(tmp1name, TYPE_INT, 0);
1407 char*tmp2name = concat2($2, "__array__");
1408 int array = new_variable(tmp1name, 0, 0);
1411 $$ = code_append($$, $4.c);
1412 $$ = abc_coerce_a($$);
1413 $$ = abc_setlocal($$, array);
1414 $$ = abc_pushbyte($$, 0);
1415 $$ = abc_setlocal($$, it);
1417 code_t*loopstart = $$ = abc_label($$);
1419 $$ = abc_hasnext2($$, array, it);
1420 code_t*myif = $$ = abc_iffalse($$, 0);
1421 $$ = abc_getlocal($$, array);
1422 $$ = abc_getlocal($$, it);
1424 $$ = abc_nextname($$);
1426 $$ = abc_nextvalue($$);
1427 $$ = converttype($$, 0, var->type);
1428 $$ = abc_setlocal($$, var->index);
1430 $$ = code_append($$, $6);
1431 $$ = abc_jump($$, loopstart);
1433 code_t*out = $$ = abc_nop($$);
1434 breakjumpsto($$, $1.name, out);
1435 continuejumpsto($$, $1.name, loopstart);
1446 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1449 code_t*myjmp = $$ = abc_jump($$, 0);
1450 code_t*loopstart = $$ = abc_label($$);
1451 $$ = code_append($$, $6);
1452 code_t*cont = $$ = abc_nop($$);
1453 myjmp->branch = cont;
1454 $$ = code_append($$, $4.c);
1455 $$ = abc_iftrue($$, loopstart);
1456 code_t*out = $$ = abc_nop($$);
1457 breakjumpsto($$, $1, out);
1458 continuejumpsto($$, $1, cont);
1464 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1466 code_t*loopstart = $$ = abc_label($$);
1467 $$ = code_append($$, $3);
1468 code_t*cont = $$ = abc_nop($$);
1469 $$ = code_append($$, $6.c);
1470 $$ = abc_iftrue($$, loopstart);
1471 code_t*out = $$ = abc_nop($$);
1472 breakjumpsto($$, $1, out);
1473 continuejumpsto($$, $1, cont);
1478 BREAK : "break" %prec prec_none {
1479 $$ = abc___break__(0, "");
1481 BREAK : "break" T_IDENTIFIER {
1482 $$ = abc___break__(0, $2);
1484 CONTINUE : "continue" %prec prec_none {
1485 $$ = abc___continue__(0, "");
1487 CONTINUE : "continue" T_IDENTIFIER {
1488 $$ = abc___continue__(0, $2);
1491 MAYBE_CASE_LIST : {$$=0;}
1492 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1493 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1494 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1495 CASE_LIST: CASE {$$=$1}
1496 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1498 CASE: "case" E ':' MAYBECODE {
1500 $$ = code_append($$, $2.c);
1501 code_t*j = $$ = abc_ifne($$, 0);
1502 $$ = code_append($$, $4);
1503 if($$->opcode != OPCODE___BREAK__) {
1504 $$ = abc___fallthrough__($$, "");
1506 code_t*e = $$ = abc_nop($$);
1509 DEFAULT: "default" ':' MAYBECODE {
1512 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1514 $$ = code_append($$, $7);
1515 code_t*out = $$ = abc_pop($$);
1516 breakjumpsto($$, $1, out);
1518 code_t*c = $$,*lastblock=0;
1520 if(c->opcode == OPCODE_IFNE) {
1521 if(!c->next) syntaxerror("internal error in fallthrough handling");
1523 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1525 c->opcode = OPCODE_JUMP;
1526 c->branch = lastblock;
1528 /* fall through end of switch */
1529 c->opcode = OPCODE_NOP;
1537 /* ------------ packages and imports ---------------- */
1539 X_IDENTIFIER: T_IDENTIFIER
1540 | "package" {$$="package";}
1542 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1543 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1545 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBECODE '}' {endpackage()}
1546 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1548 IMPORT : "import" QNAME {
1551 syntaxerror("Couldn't import class\n");
1552 state_has_imports();
1553 dict_put(state->imports, c->name, c);
1556 IMPORT : "import" PACKAGE '.' '*' {
1559 state_has_imports();
1560 list_append(state->wildcard_imports, i);
1564 /* ------------ classes and interfaces (header) -------------- */
1566 MAYBE_MODIFIERS : {$$=0;}
1567 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1568 MODIFIER_LIST : MODIFIER {$$=$1;}
1569 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1571 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1572 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1573 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1574 | KW_STATIC {$$=FLAG_STATIC;}
1575 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1576 | KW_FINAL {$$=FLAG_FINAL;}
1577 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1578 | KW_NATIVE {$$=FLAG_NATIVE;}
1579 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1581 EXTENDS : {$$=registry_getobjectclass();}
1582 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1584 EXTENDS_LIST : {$$=list_new();}
1585 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1587 IMPLEMENTS_LIST : {$$=list_new();}
1588 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1590 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1591 EXTENDS IMPLEMENTS_LIST
1592 '{' {startclass($1,$3,$4,$5, 0);}
1593 MAYBE_DECLARATION_LIST
1596 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1598 '{' {startclass($1,$3,0,$4,1);}
1599 MAYBE_IDECLARATION_LIST
1602 /* ------------ classes and interfaces (body) -------------- */
1604 MAYBE_DECLARATION_LIST :
1605 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1606 DECLARATION_LIST : DECLARATION
1607 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1609 DECLARATION : SLOT_DECLARATION
1610 DECLARATION : FUNCTION_DECLARATION
1612 MAYBE_IDECLARATION_LIST :
1613 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1614 IDECLARATION_LIST : IDECLARATION
1615 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1617 IDECLARATION : "var" T_IDENTIFIER {
1618 syntaxerror("variable declarations not allowed in interfaces");
1620 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1622 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1623 syntaxerror("invalid method modifiers: interface methods always need to be public");
1625 startfunction(0,$1,$3,$4,&$6,$8);
1626 endfunction(0,$1,$3,$4,&$6,$8, 0);
1629 /* ------------ classes and interfaces (body, slots ) ------- */
1631 VARCONST: "var" | "const"
1633 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1635 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1637 info->flags = flags;
1640 namespace_t mname_ns = {flags2access(flags), ""};
1641 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1643 if(!(flags&FLAG_STATIC)) {
1646 t=abc_class_slot(state->cls->abc, &mname, &m);
1648 t=abc_class_slot(state->cls->abc, &mname, 0);
1650 info->slot = t->slot_id;
1654 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1656 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1658 info->slot = t->slot_id;
1660 if($5.c && !is_pushundefined($5.c)) {
1662 c = abc_getlocal_0(c);
1663 c = code_append(c, $5.c);
1664 c = converttype(c, $5.t, $4);
1665 c = abc_setslot(c, t->slot_id);
1666 if(!(flags&FLAG_STATIC))
1667 state->cls->init = code_append(state->cls->init, c);
1669 state->cls->static_init = code_append(state->cls->static_init, c);
1672 t->kind= TRAIT_CONST;
1676 /* ------------ constants -------------------------------------- */
1678 MAYBESTATICCONSTANT: {$$=0;}
1679 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1681 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1682 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1683 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1684 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1685 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1686 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1687 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1688 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1689 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1691 /* ------------ classes and interfaces (body, functions) ------- */
1693 // non-vararg version
1695 memset(&$$,0,sizeof($$));
1697 MAYBE_PARAM_LIST: PARAM_LIST {
1702 MAYBE_PARAM_LIST: "..." PARAM {
1703 memset(&$$,0,sizeof($$));
1705 list_append($$.list, $2);
1707 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1710 list_append($$.list, $4);
1714 PARAM_LIST: PARAM_LIST ',' PARAM {
1716 list_append($$.list, $3);
1719 memset(&$$,0,sizeof($$));
1720 list_append($$.list, $1);
1723 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1724 $$ = malloc(sizeof(param_t));
1729 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1730 $$ = malloc(sizeof(param_t));
1732 $$->type = TYPE_ANY;
1735 GETSET : "get" {$$=$1;}
1739 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1740 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1743 if(state->method->late_binding) {
1744 c = abc_getlocal_0(c);
1745 c = abc_pushscope(c);
1747 if(state->method->is_constructor && !state->method->has_super) {
1748 // call default constructor
1749 c = abc_getlocal_0(c);
1750 c = abc_constructsuper(c, 0);
1752 c = wrap_function(c, state->method->initcode, $11);
1753 endfunction(0,$1,$3,$4,&$6,$8,c);
1756 /* ------------- package + class ids --------------- */
1758 CLASS: T_IDENTIFIER {
1760 /* try current package */
1761 $$ = find_class($1);
1762 if(!$$) syntaxerror("Could not find class %s\n", $1);
1765 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1766 $$ = registry_findclass($1, $3);
1767 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1771 QNAME: PACKAGEANDCLASS
1774 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1775 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1777 TYPE : QNAME {$$=$1;}
1778 | '*' {$$=registry_getanytype();}
1779 | "void" {$$=registry_getanytype();}
1781 | "String" {$$=registry_getstringclass();}
1782 | "int" {$$=registry_getintclass();}
1783 | "uint" {$$=registry_getuintclass();}
1784 | "Boolean" {$$=registry_getbooleanclass();}
1785 | "Number" {$$=registry_getnumberclass();}
1788 MAYBETYPE: ':' TYPE {$$=$2;}
1791 /* ----------function calls, delete, constructor calls ------ */
1793 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
1794 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1796 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1797 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1798 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
1801 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1803 $$.cc = code_append($1.cc, $3.c);
1806 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1811 $$.c = abc_getglobalscope($$.c);
1812 $$.c = abc_getslot($$.c, $2->slot);
1814 $$.c = abc_findpropstrict2($$.c, &m);
1817 $$.c = code_append($$.c, $3.cc);
1820 $$.c = abc_construct($$.c, $3.len);
1822 $$.c = abc_constructprop2($$.c, &m, $3.len);
1826 /* TODO: use abc_call (for calling local variables),
1827 abc_callstatic (for calling own methods)
1830 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1833 if($$.c->opcode == OPCODE_COERCE_A) {
1834 $$.c = code_cutlast($$.c);
1836 code_t*paramcode = $3.cc;
1839 if($$.c->opcode == OPCODE_GETPROPERTY) {
1840 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1841 $$.c = code_cutlast($$.c);
1842 $$.c = code_append($$.c, paramcode);
1843 $$.c = abc_callproperty2($$.c, name, $3.len);
1844 multiname_destroy(name);
1845 } else if($$.c->opcode == OPCODE_GETSLOT) {
1846 int slot = (int)(ptroff_t)$$.c->data[0];
1847 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1848 if(t->kind!=TRAIT_METHOD) {
1849 //ok: flash allows to assign closures to members.
1851 multiname_t*name = t->name;
1852 $$.c = code_cutlast($$.c);
1853 $$.c = code_append($$.c, paramcode);
1854 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1855 $$.c = abc_callproperty2($$.c, name, $3.len);
1856 } else if($$.c->opcode == OPCODE_GETSUPER) {
1857 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1858 $$.c = code_cutlast($$.c);
1859 $$.c = code_append($$.c, paramcode);
1860 $$.c = abc_callsuper2($$.c, name, $3.len);
1861 multiname_destroy(name);
1863 $$.c = abc_getlocal_0($$.c);
1864 $$.c = code_append($$.c, paramcode);
1865 $$.c = abc_call($$.c, $3.len);
1870 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1871 $$.t = $1.t->function->return_type;
1873 $$.c = abc_coerce_a($$.c);
1878 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1879 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1880 if(!state->method) syntaxerror("super() not allowed outside of a function");
1881 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1884 $$.c = abc_getlocal_0($$.c);
1886 $$.c = code_append($$.c, $3.cc);
1888 this is dependent on the control path, check this somewhere else
1889 if(state->method->has_super)
1890 syntaxerror("constructor may call super() only once");
1892 state->method->has_super = 1;
1893 $$.c = abc_constructsuper($$.c, $3.len);
1894 $$.c = abc_pushundefined($$.c);
1898 DELETE: "delete" E {
1900 if($$.c->opcode == OPCODE_COERCE_A) {
1901 $$.c = code_cutlast($$.c);
1903 multiname_t*name = 0;
1904 if($$.c->opcode == OPCODE_GETPROPERTY) {
1905 $$.c->opcode = OPCODE_DELETEPROPERTY;
1906 } else if($$.c->opcode == OPCODE_GETSLOT) {
1907 int slot = (int)(ptroff_t)$$.c->data[0];
1908 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1909 $$.c = code_cutlast($$.c);
1910 $$.c = abc_deleteproperty2($$.c, name);
1912 $$.c = abc_getlocal_0($$.c);
1913 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1914 $$.c = abc_deleteproperty2($$.c, &m);
1916 $$.t = TYPE_BOOLEAN;
1919 RETURN: "return" %prec prec_none {
1920 $$ = abc_returnvoid(0);
1922 RETURN: "return" EXPRESSION {
1924 $$ = abc_returnvalue($$);
1927 // ----------------------- expression types -------------------------------------
1929 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1930 EXPRESSION : E %prec below_minus {$$ = $1;}
1931 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1933 $$.c = cut_last_push($$.c);
1934 $$.c = code_append($$.c,$3.c);
1937 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1938 $$=cut_last_push($1.c);
1941 // ----------------------- expression evaluation -------------------------------------
1944 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1946 E : DELETE {$$ = $1;}
1947 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1951 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1952 //MULTINAME(m, registry_getintclass());
1953 //$$.c = abc_coerce2($$.c, &m); // FIXME
1956 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1959 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1962 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1965 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1968 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1971 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1974 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1975 $$.t = TYPE_BOOLEAN;
1977 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1978 $$.t = TYPE_BOOLEAN;
1980 CONSTANT : "null" {$$.c = abc_pushnull(0);
1985 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1986 $$.t = TYPE_BOOLEAN;
1988 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1989 $$.t = TYPE_BOOLEAN;
1991 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1992 $$.t = TYPE_BOOLEAN;
1994 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1995 $$.t = TYPE_BOOLEAN;
1997 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1998 $$.t = TYPE_BOOLEAN;
2000 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2001 $$.t = TYPE_BOOLEAN;
2003 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2004 $$.t = TYPE_BOOLEAN;
2006 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2007 $$.t = TYPE_BOOLEAN;
2010 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2012 $$.c = converttype($$.c, $1.t, $$.t);
2013 $$.c = abc_dup($$.c);
2014 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2015 $$.c = cut_last_push($$.c);
2016 $$.c = code_append($$.c,$3.c);
2017 $$.c = converttype($$.c, $3.t, $$.t);
2018 code_t*label = $$.c = abc_label($$.c);
2019 jmp->branch = label;
2022 $$.t = join_types($1.t, $3.t, 'A');
2023 /*printf("%08x:\n",$1.t);
2024 code_dump($1.c, 0, 0, "", stdout);
2025 printf("%08x:\n",$3.t);
2026 code_dump($3.c, 0, 0, "", stdout);
2027 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2029 $$.c = converttype($$.c, $1.t, $$.t);
2030 $$.c = abc_dup($$.c);
2031 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2032 $$.c = cut_last_push($$.c);
2033 $$.c = code_append($$.c,$3.c);
2034 $$.c = converttype($$.c, $3.t, $$.t);
2035 code_t*label = $$.c = abc_label($$.c);
2036 jmp->branch = label;
2039 E : '!' E {$$.c=$2.c;
2040 $$.c = abc_not($$.c);
2041 $$.t = TYPE_BOOLEAN;
2044 E : '~' E {$$.c=$2.c;
2045 $$.c = abc_bitnot($$.c);
2049 E : E '&' E {$$.c = code_append($1.c,$3.c);
2050 $$.c = abc_bitand($$.c);
2054 E : E '^' E {$$.c = code_append($1.c,$3.c);
2055 $$.c = abc_bitxor($$.c);
2059 E : E '|' E {$$.c = code_append($1.c,$3.c);
2060 $$.c = abc_bitor($$.c);
2064 E : E '-' E {$$.c = code_append($1.c,$3.c);
2065 if(BOTH_INT($1,$3)) {
2066 $$.c = abc_subtract_i($$.c);
2069 $$.c = abc_subtract($$.c);
2073 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2074 $$.c = abc_rshift($$.c);
2077 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2078 $$.c = abc_urshift($$.c);
2081 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2082 $$.c = abc_lshift($$.c);
2086 E : E '/' E {$$.c = code_append($1.c,$3.c);
2087 $$.c = abc_divide($$.c);
2090 E : E '+' E {$$.c = code_append($1.c,$3.c);
2091 $$.c = abc_add($$.c);
2094 E : E '%' E {$$.c = code_append($1.c,$3.c);
2095 $$.c = abc_modulo($$.c);
2098 E : E '*' E {$$.c = code_append($1.c,$3.c);
2099 if(BOTH_INT($1,$3)) {
2100 $$.c = abc_multiply_i($$.c);
2103 $$.c = abc_multiply($$.c);
2108 E : E "in" E {$$.c = code_append($1.c,$3.c);
2109 $$.c = abc_in($$.c);
2110 $$.t = TYPE_BOOLEAN;
2113 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2114 if(use_astype && TYPE_IS_CLASS($3.t)) {
2115 MULTINAME(m,$3.t->cls);
2116 $$.c = abc_astype2($1.c, &m);
2119 $$.c = code_append($1.c, $3.c);
2120 $$.c = abc_astypelate($$.c);
2125 E : E "instanceof" E
2126 {$$.c = code_append($1.c, $3.c);
2127 $$.c = abc_instanceof($$.c);
2128 $$.t = TYPE_BOOLEAN;
2131 E : E "is" E {$$.c = code_append($1.c, $3.c);
2132 $$.c = abc_istypelate($$.c);
2133 $$.t = TYPE_BOOLEAN;
2136 E : "typeof" '(' E ')' {
2138 $$.c = abc_typeof($$.c);
2143 $$.c = cut_last_push($2.c);
2144 $$.c = abc_pushundefined($$.c);
2148 E : "void" { $$.c = abc_pushundefined(0);
2152 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2157 $$.c=abc_negate_i($$.c);
2160 $$.c=abc_negate($$.c);
2167 $$.c = code_append($$.c, $3.c);
2169 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2170 $$.c = abc_getproperty2($$.c, &m);
2171 $$.t = 0; // array elements have unknown type
2174 E : '[' MAYBE_EXPRESSION_LIST ']' {
2176 $$.c = code_append($$.c, $2.cc);
2177 $$.c = abc_newarray($$.c, $2.len);
2178 $$.t = registry_getarrayclass();
2181 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2182 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2184 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2186 $$.cc = code_append($$.cc, $1.c);
2187 $$.cc = code_append($$.cc, $3.c);
2190 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2193 $$.cc = code_append($$.cc, $3.c);
2194 $$.cc = code_append($$.cc, $5.c);
2199 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2201 $$.c = code_append($$.c, $2.cc);
2202 $$.c = abc_newobject($$.c, $2.len/2);
2203 $$.t = registry_getobjectclass();
2208 if(BOTH_INT($1,$3)) {
2209 c=abc_multiply_i(c);
2213 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2214 $$.c = toreadwrite($1.c, c, 0, 0);
2219 code_t*c = abc_modulo($3.c);
2220 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2221 $$.c = toreadwrite($1.c, c, 0, 0);
2225 code_t*c = abc_lshift($3.c);
2226 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2227 $$.c = toreadwrite($1.c, c, 0, 0);
2231 code_t*c = abc_rshift($3.c);
2232 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2233 $$.c = toreadwrite($1.c, c, 0, 0);
2237 code_t*c = abc_urshift($3.c);
2238 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2239 $$.c = toreadwrite($1.c, c, 0, 0);
2243 code_t*c = abc_divide($3.c);
2244 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2245 $$.c = toreadwrite($1.c, c, 0, 0);
2250 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2255 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2257 $$.c = toreadwrite($1.c, c, 0, 0);
2260 E : E "-=" E { code_t*c = $3.c;
2261 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2262 c=abc_subtract_i(c);
2266 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2268 $$.c = toreadwrite($1.c, c, 0, 0);
2271 E : E '=' E { code_t*c = 0;
2272 c = code_append(c, $3.c);
2273 c = converttype(c, $3.t, $1.t);
2274 $$.c = toreadwrite($1.c, c, 1, 0);
2278 E : E '?' E ':' E %prec below_assignment {
2280 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2281 $$.c = code_append($$.c, $3.c);
2282 code_t*j2 = $$.c = abc_jump($$.c, 0);
2283 $$.c = j1->branch = abc_label($$.c);
2284 $$.c = code_append($$.c, $5.c);
2285 $$.c = j2->branch = abc_label($$.c);
2286 $$.t = join_types($3.t,$5.t,'?');
2289 // TODO: use inclocal where appropriate
2290 E : E "++" { code_t*c = 0;
2291 classinfo_t*type = $1.t;
2292 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2293 c=abc_increment_i(c);
2299 c=converttype(c, type, $1.t);
2300 $$.c = toreadwrite($1.c, c, 0, 1);
2303 E : E "--" { code_t*c = 0;
2304 classinfo_t*type = $1.t;
2305 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2306 c=abc_decrement_i(c);
2312 c=converttype(c, type, $1.t);
2313 $$.c = toreadwrite($1.c, c, 0, 1);
2317 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2318 classinfo_t*type = $2.t;
2319 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2320 c=abc_increment_i(c);
2326 c=converttype(c, type, $2.t);
2327 $$.c = toreadwrite($2.c, c, 0, 0);
2331 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2332 classinfo_t*type = $2.t;
2333 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2334 c=abc_decrement_i(c);
2340 c=converttype(c, type, $2.t);
2341 $$.c = toreadwrite($2.c, c, 0, 0);
2345 E : "super" '.' T_IDENTIFIER
2346 { if(!state->cls->info)
2347 syntaxerror("super keyword not allowed outside a class");
2348 classinfo_t*t = state->cls->info->superclass;
2349 if(!t) t = TYPE_OBJECT;
2351 memberinfo_t*f = registry_findmember(t, $3, 1);
2352 namespace_t ns = {flags2access(f->flags), ""};
2353 MEMBER_MULTINAME(m, f, $3);
2355 $$.c = abc_getlocal_0($$.c);
2356 $$.c = abc_getsuper2($$.c, &m);
2357 $$.t = memberinfo_gettype(f);
2360 E : E '.' T_IDENTIFIER
2362 classinfo_t*t = $1.t;
2364 if(TYPE_IS_CLASS(t) && t->cls) {
2369 memberinfo_t*f = registry_findmember(t, $3, 1);
2371 if(f && !is_static != !(f->flags&FLAG_STATIC))
2373 if(f && f->slot && !noslot) {
2374 $$.c = abc_getslot($$.c, f->slot);
2376 MEMBER_MULTINAME(m, f, $3);
2377 $$.c = abc_getproperty2($$.c, &m);
2379 /* determine type */
2380 $$.t = memberinfo_gettype(f);
2382 $$.c = abc_coerce_a($$.c);
2384 /* when resolving a property on an unknown type, we do know the
2385 name of the property (and don't seem to need the package), but
2386 we need to make avm2 try out all access modes */
2387 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2388 $$.c = abc_getproperty2($$.c, &m);
2389 $$.c = abc_coerce_a($$.c);
2390 $$.t = registry_getanytype();
2394 VAR_READ : T_IDENTIFIER {
2401 /* look at variables */
2402 if((v = find_variable($1))) {
2403 // $1 is a local variable
2404 $$.c = abc_getlocal($$.c, v->index);
2407 /* look at current class' members */
2408 } else if((f = registry_findmember(state->cls->info, $1, 1))) {
2409 // $1 is a function in this class
2410 int var_is_static = (f->flags&FLAG_STATIC);
2411 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2412 if(var_is_static != i_am_static) {
2413 /* there doesn't seem to be any "static" way to access
2414 static properties of a class */
2415 state->method->late_binding = 1;
2417 namespace_t ns = {flags2access(f->flags), ""};
2418 multiname_t m = {QNAME, &ns, 0, $1};
2419 $$.c = abc_findpropstrict2($$.c, &m);
2420 $$.c = abc_getproperty2($$.c, &m);
2423 $$.c = abc_getlocal_0($$.c);
2424 $$.c = abc_getslot($$.c, f->slot);
2426 namespace_t ns = {flags2access(f->flags), ""};
2427 multiname_t m = {QNAME, &ns, 0, $1};
2428 $$.c = abc_getlocal_0($$.c);
2429 $$.c = abc_getproperty2($$.c, &m);
2432 if(f->kind == MEMBER_METHOD) {
2433 $$.t = TYPE_FUNCTION(f);
2438 /* look at actual classes, in the current package and imported */
2439 } else if((a = find_class($1))) {
2440 if(a->flags & FLAG_METHOD) {
2442 $$.c = abc_findpropstrict2($$.c, &m);
2443 $$.c = abc_getproperty2($$.c, &m);
2444 $$.t = TYPE_FUNCTION(a->function);
2447 $$.c = abc_getglobalscope($$.c);
2448 $$.c = abc_getslot($$.c, a->slot);
2451 $$.c = abc_getlex2($$.c, &m);
2453 $$.t = TYPE_CLASS(a);
2456 /* unknown object, let the avm2 resolve it */
2458 if(strcmp($1,"trace"))
2459 warning("Couldn't resolve '%s', doing late binding", $1);
2460 state->method->late_binding = 1;
2462 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2465 $$.c = abc_findpropstrict2($$.c, &m);
2466 $$.c = abc_getproperty2($$.c, &m);
2471 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2472 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2473 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2475 // ----------------- namespaces -------------------------------------------------
2477 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2478 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2479 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2481 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER