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);
1243 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1244 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1251 /* ------------ code blocks / statements ---------------- */
1253 PROGRAM: MAYBECODE {
1254 /* todo: do something with this code if we're outside a function */
1256 warning("ignored code");
1259 MAYBECODE: CODE {$$=$1;}
1260 MAYBECODE: {$$=code_new();}
1262 CODE: CODE CODEPIECE {
1263 $$=code_append($1,$2);
1269 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1270 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1271 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1272 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1273 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1274 CODEPIECE: ';' {$$=code_new();}
1275 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1276 CODEPIECE: VOIDEXPRESSION {$$=$1}
1277 CODEPIECE: FOR {$$=$1}
1278 CODEPIECE: FOR_IN {$$=$1}
1279 CODEPIECE: WHILE {$$=$1}
1280 CODEPIECE: DO_WHILE {$$=$1}
1281 CODEPIECE: SWITCH {$$=$1}
1282 CODEPIECE: BREAK {$$=$1}
1283 CODEPIECE: CONTINUE {$$=$1}
1284 CODEPIECE: RETURN {$$=$1}
1285 CODEPIECE: IF {$$=$1}
1286 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1287 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1289 CODEBLOCK : '{' CODE '}' {$$=$2;}
1290 CODEBLOCK : '{' '}' {$$=0;}
1291 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1292 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1294 /* ------------ variables --------------------------- */
1296 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1297 | {$$.c=abc_pushundefined(0);
1301 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1302 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1304 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1305 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1307 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1309 if(variable_exists($1))
1310 syntaxerror("Variable %s already defined", $1);
1312 if(!is_subtype_of($3.t, $2)) {
1313 syntaxerror("Can't convert %s to %s", $3.t->name,
1317 int index = new_variable($1, $2, 1);
1320 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1322 $$ = converttype($$, $3.t, $2);
1323 $$ = abc_setlocal($$, index);
1325 $$ = defaultvalue(0, $2);
1326 $$ = abc_setlocal($$, index);
1329 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1331 $$ = abc_coerce_a($$);
1332 $$ = abc_setlocal($$, index);
1338 /* that's the default for a local register, anyway
1340 state->method->initcode = abc_pushundefined(state->method->initcode);
1341 state->method->initcode = abc_setlocal(state->method->initcode, index);
1343 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1346 /* ------------ control flow ------------------------- */
1348 MAYBEELSE: %prec below_else {$$ = code_new();}
1349 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1350 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1352 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1354 $$ = code_append($$, $4.c);
1355 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1357 $$ = code_append($$, $6);
1359 myjmp = $$ = abc_jump($$, 0);
1361 myif->branch = $$ = abc_nop($$);
1363 $$ = code_append($$, $7);
1364 myjmp->branch = $$ = abc_nop($$);
1367 $$ = killvars($$);old_state();
1370 FOR_INIT : {$$=code_new();}
1371 FOR_INIT : VARIABLE_DECLARATION
1372 FOR_INIT : VOIDEXPRESSION
1373 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1374 $$=$2;new_variable($2,$3,1);
1376 FOR_IN_INIT : T_IDENTIFIER {
1380 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1381 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1383 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1384 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1386 $$ = code_append($$, $2);
1387 code_t*loopstart = $$ = abc_label($$);
1388 $$ = code_append($$, $4.c);
1389 code_t*myif = $$ = abc_iffalse($$, 0);
1390 $$ = code_append($$, $8);
1391 code_t*cont = $$ = abc_nop($$);
1392 $$ = code_append($$, $6);
1393 $$ = abc_jump($$, loopstart);
1394 code_t*out = $$ = abc_nop($$);
1395 breakjumpsto($$, $1.name, out);
1396 continuejumpsto($$, $1.name, cont);
1399 $$ = killvars($$);old_state();
1402 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1403 variable_t*var = find_variable($2);
1404 char*tmp1name = concat2($2, "__tmp1__");
1405 int it = new_variable(tmp1name, TYPE_INT, 0);
1406 char*tmp2name = concat2($2, "__array__");
1407 int array = new_variable(tmp1name, 0, 0);
1410 $$ = code_append($$, $4.c);
1411 $$ = abc_coerce_a($$);
1412 $$ = abc_setlocal($$, array);
1413 $$ = abc_pushbyte($$, 0);
1414 $$ = abc_setlocal($$, it);
1416 code_t*loopstart = $$ = abc_label($$);
1418 $$ = abc_hasnext2($$, array, it);
1419 code_t*myif = $$ = abc_iffalse($$, 0);
1420 $$ = abc_getlocal($$, array);
1421 $$ = abc_getlocal($$, it);
1423 $$ = abc_nextname($$);
1425 $$ = abc_nextvalue($$);
1426 $$ = converttype($$, 0, var->type);
1427 $$ = abc_setlocal($$, var->index);
1429 $$ = code_append($$, $6);
1430 $$ = abc_jump($$, loopstart);
1432 code_t*out = $$ = abc_nop($$);
1433 breakjumpsto($$, $1.name, out);
1434 continuejumpsto($$, $1.name, loopstart);
1445 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1448 code_t*myjmp = $$ = abc_jump($$, 0);
1449 code_t*loopstart = $$ = abc_label($$);
1450 $$ = code_append($$, $6);
1451 code_t*cont = $$ = abc_nop($$);
1452 myjmp->branch = cont;
1453 $$ = code_append($$, $4.c);
1454 $$ = abc_iftrue($$, loopstart);
1455 code_t*out = $$ = abc_nop($$);
1456 breakjumpsto($$, $1, out);
1457 continuejumpsto($$, $1, cont);
1463 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1465 code_t*loopstart = $$ = abc_label($$);
1466 $$ = code_append($$, $3);
1467 code_t*cont = $$ = abc_nop($$);
1468 $$ = code_append($$, $6.c);
1469 $$ = abc_iftrue($$, loopstart);
1470 code_t*out = $$ = abc_nop($$);
1471 breakjumpsto($$, $1, out);
1472 continuejumpsto($$, $1, cont);
1477 BREAK : "break" %prec prec_none {
1478 $$ = abc___break__(0, "");
1480 BREAK : "break" T_IDENTIFIER {
1481 $$ = abc___break__(0, $2);
1483 CONTINUE : "continue" %prec prec_none {
1484 $$ = abc___continue__(0, "");
1486 CONTINUE : "continue" T_IDENTIFIER {
1487 $$ = abc___continue__(0, $2);
1490 MAYBE_CASE_LIST : {$$=0;}
1491 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1492 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1493 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1494 CASE_LIST: CASE {$$=$1}
1495 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1497 CASE: "case" E ':' MAYBECODE {
1499 $$ = code_append($$, $2.c);
1500 code_t*j = $$ = abc_ifne($$, 0);
1501 $$ = code_append($$, $4);
1502 if($$->opcode != OPCODE___BREAK__) {
1503 $$ = abc___fallthrough__($$, "");
1505 code_t*e = $$ = abc_nop($$);
1508 DEFAULT: "default" ':' MAYBECODE {
1511 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1513 $$ = code_append($$, $7);
1514 code_t*out = $$ = abc_pop($$);
1515 breakjumpsto($$, $1, out);
1517 code_t*c = $$,*lastblock=0;
1519 if(c->opcode == OPCODE_IFNE) {
1520 if(!c->next) syntaxerror("internal error in fallthrough handling");
1522 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1524 c->opcode = OPCODE_JUMP;
1525 c->branch = lastblock;
1527 /* fall through end of switch */
1528 c->opcode = OPCODE_NOP;
1536 /* ------------ packages and imports ---------------- */
1538 X_IDENTIFIER: T_IDENTIFIER
1539 | "package" {$$="package";}
1541 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1542 PACKAGE: X_IDENTIFIER {$$=strdup($1);}
1544 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBECODE '}' {endpackage()}
1545 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1547 IMPORT : "import" QNAME {
1550 syntaxerror("Couldn't import class\n");
1551 state_has_imports();
1552 dict_put(state->imports, c->name, c);
1555 IMPORT : "import" PACKAGE '.' '*' {
1558 state_has_imports();
1559 list_append(state->wildcard_imports, i);
1563 /* ------------ classes and interfaces (header) -------------- */
1565 MAYBE_MODIFIERS : {$$=0;}
1566 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1567 MODIFIER_LIST : MODIFIER {$$=$1;}
1568 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1570 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1571 | KW_PRIVATE {$$=FLAG_PRIVATE;}
1572 | KW_PROTECTED {$$=FLAG_PROTECTED;}
1573 | KW_STATIC {$$=FLAG_STATIC;}
1574 | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1575 | KW_FINAL {$$=FLAG_FINAL;}
1576 | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1577 | KW_NATIVE {$$=FLAG_NATIVE;}
1578 | KW_INTERNAL {$$=FLAG_INTERNAL;}
1580 EXTENDS : {$$=registry_getobjectclass();}
1581 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1583 EXTENDS_LIST : {$$=list_new();}
1584 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1586 IMPLEMENTS_LIST : {$$=list_new();}
1587 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1589 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
1590 EXTENDS IMPLEMENTS_LIST
1591 '{' {startclass($1,$3,$4,$5, 0);}
1592 MAYBE_DECLARATION_LIST
1595 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
1597 '{' {startclass($1,$3,0,$4,1);}
1598 MAYBE_IDECLARATION_LIST
1601 /* ------------ classes and interfaces (body) -------------- */
1603 MAYBE_DECLARATION_LIST :
1604 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1605 DECLARATION_LIST : DECLARATION
1606 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1608 DECLARATION : SLOT_DECLARATION
1609 DECLARATION : FUNCTION_DECLARATION
1611 MAYBE_IDECLARATION_LIST :
1612 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1613 IDECLARATION_LIST : IDECLARATION
1614 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1616 IDECLARATION : "var" T_IDENTIFIER {
1617 syntaxerror("variable declarations not allowed in interfaces");
1619 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1621 if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1622 syntaxerror("invalid method modifiers: interface methods always need to be public");
1624 startfunction(0,$1,$3,$4,&$6,$8);
1625 endfunction(0,$1,$3,$4,&$6,$8, 0);
1628 /* ------------ classes and interfaces (body, slots ) ------- */
1630 VARCONST: "var" | "const"
1632 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1634 memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1636 info->flags = flags;
1639 namespace_t mname_ns = {flags2access(flags), ""};
1640 multiname_t mname = {QNAME, &mname_ns, 0, $3};
1642 if(!(flags&FLAG_STATIC)) {
1645 t=abc_class_slot(state->cls->abc, &mname, &m);
1647 t=abc_class_slot(state->cls->abc, &mname, 0);
1649 info->slot = t->slot_id;
1653 t=abc_class_staticslot(state->cls->abc, &mname, &m);
1655 t=abc_class_staticslot(state->cls->abc, &mname, 0);
1657 info->slot = t->slot_id;
1659 if($5.c && !is_pushundefined($5.c)) {
1661 c = abc_getlocal_0(c);
1662 c = code_append(c, $5.c);
1663 c = converttype(c, $5.t, $4);
1664 c = abc_setslot(c, t->slot_id);
1665 if(!(flags&FLAG_STATIC))
1666 state->cls->init = code_append(state->cls->init, c);
1668 state->cls->static_init = code_append(state->cls->static_init, c);
1671 t->kind= TRAIT_CONST;
1675 /* ------------ constants -------------------------------------- */
1677 MAYBESTATICCONSTANT: {$$=0;}
1678 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1680 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1681 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1682 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1683 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1684 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1685 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1686 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1687 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1688 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1690 /* ------------ classes and interfaces (body, functions) ------- */
1692 // non-vararg version
1694 memset(&$$,0,sizeof($$));
1696 MAYBE_PARAM_LIST: PARAM_LIST {
1701 MAYBE_PARAM_LIST: "..." PARAM {
1702 memset(&$$,0,sizeof($$));
1704 list_append($$.list, $2);
1706 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1709 list_append($$.list, $4);
1713 PARAM_LIST: PARAM_LIST ',' PARAM {
1715 list_append($$.list, $3);
1718 memset(&$$,0,sizeof($$));
1719 list_append($$.list, $1);
1722 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1723 $$ = malloc(sizeof(param_t));
1728 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1729 $$ = malloc(sizeof(param_t));
1731 $$->type = TYPE_ANY;
1734 GETSET : "get" {$$=$1;}
1738 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1739 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1742 if(state->method->late_binding) {
1743 c = abc_getlocal_0(c);
1744 c = abc_pushscope(c);
1746 if(state->method->is_constructor && !state->method->has_super) {
1747 // call default constructor
1748 c = abc_getlocal_0(c);
1749 c = abc_constructsuper(c, 0);
1751 c = wrap_function(c, state->method->initcode, $11);
1752 endfunction(0,$1,$3,$4,&$6,$8,c);
1755 /* ------------- package + class ids --------------- */
1757 CLASS: T_IDENTIFIER {
1759 /* try current package */
1760 $$ = find_class($1);
1761 if(!$$) syntaxerror("Could not find class %s\n", $1);
1764 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1765 $$ = registry_findclass($1, $3);
1766 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1770 QNAME: PACKAGEANDCLASS
1773 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1774 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1776 TYPE : QNAME {$$=$1;}
1777 | '*' {$$=registry_getanytype();}
1778 | "void" {$$=registry_getanytype();}
1780 | "String" {$$=registry_getstringclass();}
1781 | "int" {$$=registry_getintclass();}
1782 | "uint" {$$=registry_getuintclass();}
1783 | "Boolean" {$$=registry_getbooleanclass();}
1784 | "Number" {$$=registry_getnumberclass();}
1787 MAYBETYPE: ':' TYPE {$$=$2;}
1790 /* ----------function calls, delete, constructor calls ------ */
1792 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
1793 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1795 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1796 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1797 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
1800 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1802 $$.cc = code_append($1.cc, $3.c);
1805 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1810 $$.c = abc_getglobalscope($$.c);
1811 $$.c = abc_getslot($$.c, $2->slot);
1813 $$.c = abc_findpropstrict2($$.c, &m);
1816 $$.c = code_append($$.c, $3.cc);
1819 $$.c = abc_construct($$.c, $3.len);
1821 $$.c = abc_constructprop2($$.c, &m, $3.len);
1825 /* TODO: use abc_call (for calling local variables),
1826 abc_callstatic (for calling own methods)
1829 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1832 if($$.c->opcode == OPCODE_COERCE_A) {
1833 $$.c = code_cutlast($$.c);
1835 code_t*paramcode = $3.cc;
1838 if($$.c->opcode == OPCODE_GETPROPERTY) {
1839 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1840 $$.c = code_cutlast($$.c);
1841 $$.c = code_append($$.c, paramcode);
1842 $$.c = abc_callproperty2($$.c, name, $3.len);
1843 multiname_destroy(name);
1844 } else if($$.c->opcode == OPCODE_GETSLOT) {
1845 int slot = (int)(ptroff_t)$$.c->data[0];
1846 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1847 if(t->kind!=TRAIT_METHOD) {
1848 //ok: flash allows to assign closures to members.
1850 multiname_t*name = t->name;
1851 $$.c = code_cutlast($$.c);
1852 $$.c = code_append($$.c, paramcode);
1853 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1854 $$.c = abc_callproperty2($$.c, name, $3.len);
1855 } else if($$.c->opcode == OPCODE_GETSUPER) {
1856 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1857 $$.c = code_cutlast($$.c);
1858 $$.c = code_append($$.c, paramcode);
1859 $$.c = abc_callsuper2($$.c, name, $3.len);
1860 multiname_destroy(name);
1862 $$.c = abc_getlocal_0($$.c);
1863 $$.c = code_append($$.c, paramcode);
1864 $$.c = abc_call($$.c, $3.len);
1869 if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1870 $$.t = $1.t->function->return_type;
1872 $$.c = abc_coerce_a($$.c);
1877 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1878 if(!state->cls) syntaxerror("super() not allowed outside of a class");
1879 if(!state->method) syntaxerror("super() not allowed outside of a function");
1880 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1883 $$.c = abc_getlocal_0($$.c);
1885 $$.c = code_append($$.c, $3.cc);
1887 this is dependent on the control path, check this somewhere else
1888 if(state->method->has_super)
1889 syntaxerror("constructor may call super() only once");
1891 state->method->has_super = 1;
1892 $$.c = abc_constructsuper($$.c, $3.len);
1893 $$.c = abc_pushundefined($$.c);
1897 DELETE: "delete" E {
1899 if($$.c->opcode == OPCODE_COERCE_A) {
1900 $$.c = code_cutlast($$.c);
1902 multiname_t*name = 0;
1903 if($$.c->opcode == OPCODE_GETPROPERTY) {
1904 $$.c->opcode = OPCODE_DELETEPROPERTY;
1905 } else if($$.c->opcode == OPCODE_GETSLOT) {
1906 int slot = (int)(ptroff_t)$$.c->data[0];
1907 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1908 $$.c = code_cutlast($$.c);
1909 $$.c = abc_deleteproperty2($$.c, name);
1911 $$.c = abc_getlocal_0($$.c);
1912 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1913 $$.c = abc_deleteproperty2($$.c, &m);
1915 $$.t = TYPE_BOOLEAN;
1918 RETURN: "return" %prec prec_none {
1919 $$ = abc_returnvoid(0);
1921 RETURN: "return" EXPRESSION {
1923 $$ = abc_returnvalue($$);
1926 // ----------------------- expression types -------------------------------------
1928 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
1929 EXPRESSION : E %prec below_minus {$$ = $1;}
1930 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1932 $$.c = cut_last_push($$.c);
1933 $$.c = code_append($$.c,$3.c);
1936 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1937 $$=cut_last_push($1.c);
1940 // ----------------------- expression evaluation -------------------------------------
1943 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1945 E : DELETE {$$ = $1;}
1946 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1950 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1951 //MULTINAME(m, registry_getintclass());
1952 //$$.c = abc_coerce2($$.c, &m); // FIXME
1955 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1958 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1961 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1964 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1967 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1970 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1973 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1974 $$.t = TYPE_BOOLEAN;
1976 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1977 $$.t = TYPE_BOOLEAN;
1979 CONSTANT : "null" {$$.c = abc_pushnull(0);
1984 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1985 $$.t = TYPE_BOOLEAN;
1987 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1988 $$.t = TYPE_BOOLEAN;
1990 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1991 $$.t = TYPE_BOOLEAN;
1993 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1994 $$.t = TYPE_BOOLEAN;
1996 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1997 $$.t = TYPE_BOOLEAN;
1999 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2000 $$.t = TYPE_BOOLEAN;
2002 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2003 $$.t = TYPE_BOOLEAN;
2005 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2006 $$.t = TYPE_BOOLEAN;
2009 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2011 $$.c = converttype($$.c, $1.t, $$.t);
2012 $$.c = abc_dup($$.c);
2013 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2014 $$.c = cut_last_push($$.c);
2015 $$.c = code_append($$.c,$3.c);
2016 $$.c = converttype($$.c, $3.t, $$.t);
2017 code_t*label = $$.c = abc_label($$.c);
2018 jmp->branch = label;
2021 $$.t = join_types($1.t, $3.t, 'A');
2022 /*printf("%08x:\n",$1.t);
2023 code_dump($1.c, 0, 0, "", stdout);
2024 printf("%08x:\n",$3.t);
2025 code_dump($3.c, 0, 0, "", stdout);
2026 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2028 $$.c = converttype($$.c, $1.t, $$.t);
2029 $$.c = abc_dup($$.c);
2030 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2031 $$.c = cut_last_push($$.c);
2032 $$.c = code_append($$.c,$3.c);
2033 $$.c = converttype($$.c, $3.t, $$.t);
2034 code_t*label = $$.c = abc_label($$.c);
2035 jmp->branch = label;
2038 E : '!' E {$$.c=$2.c;
2039 $$.c = abc_not($$.c);
2040 $$.t = TYPE_BOOLEAN;
2043 E : '~' E {$$.c=$2.c;
2044 $$.c = abc_bitnot($$.c);
2048 E : E '&' E {$$.c = code_append($1.c,$3.c);
2049 $$.c = abc_bitand($$.c);
2053 E : E '^' E {$$.c = code_append($1.c,$3.c);
2054 $$.c = abc_bitxor($$.c);
2058 E : E '|' E {$$.c = code_append($1.c,$3.c);
2059 $$.c = abc_bitor($$.c);
2063 E : E '-' E {$$.c = code_append($1.c,$3.c);
2064 if(BOTH_INT($1,$3)) {
2065 $$.c = abc_subtract_i($$.c);
2068 $$.c = abc_subtract($$.c);
2072 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2073 $$.c = abc_rshift($$.c);
2076 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2077 $$.c = abc_urshift($$.c);
2080 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2081 $$.c = abc_lshift($$.c);
2085 E : E '/' E {$$.c = code_append($1.c,$3.c);
2086 $$.c = abc_divide($$.c);
2089 E : E '+' E {$$.c = code_append($1.c,$3.c);
2090 $$.c = abc_add($$.c);
2093 E : E '%' E {$$.c = code_append($1.c,$3.c);
2094 $$.c = abc_modulo($$.c);
2097 E : E '*' E {$$.c = code_append($1.c,$3.c);
2098 if(BOTH_INT($1,$3)) {
2099 $$.c = abc_multiply_i($$.c);
2102 $$.c = abc_multiply($$.c);
2107 E : E "in" E {$$.c = code_append($1.c,$3.c);
2108 $$.c = abc_in($$.c);
2109 $$.t = TYPE_BOOLEAN;
2112 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2113 if(use_astype && TYPE_IS_CLASS($3.t)) {
2114 MULTINAME(m,$3.t->cls);
2115 $$.c = abc_astype2($1.c, &m);
2118 $$.c = code_append($1.c, $3.c);
2119 $$.c = abc_astypelate($$.c);
2124 E : E "instanceof" E
2125 {$$.c = code_append($1.c, $3.c);
2126 $$.c = abc_instanceof($$.c);
2127 $$.t = TYPE_BOOLEAN;
2130 E : E "is" E {$$.c = code_append($1.c, $3.c);
2131 $$.c = abc_istypelate($$.c);
2132 $$.t = TYPE_BOOLEAN;
2135 E : "typeof" '(' E ')' {
2137 $$.c = abc_typeof($$.c);
2142 $$.c = cut_last_push($2.c);
2143 $$.c = abc_pushundefined($$.c);
2147 E : "void" { $$.c = abc_pushundefined(0);
2151 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2156 $$.c=abc_negate_i($$.c);
2159 $$.c=abc_negate($$.c);
2166 $$.c = code_append($$.c, $3.c);
2168 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2169 $$.c = abc_getproperty2($$.c, &m);
2170 $$.t = 0; // array elements have unknown type
2173 E : '[' MAYBE_EXPRESSION_LIST ']' {
2175 $$.c = code_append($$.c, $2.cc);
2176 $$.c = abc_newarray($$.c, $2.len);
2177 $$.t = registry_getarrayclass();
2180 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2181 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2183 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2185 $$.cc = code_append($$.cc, $1.c);
2186 $$.cc = code_append($$.cc, $3.c);
2189 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2192 $$.cc = code_append($$.cc, $3.c);
2193 $$.cc = code_append($$.cc, $5.c);
2198 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2200 $$.c = code_append($$.c, $2.cc);
2201 $$.c = abc_newobject($$.c, $2.len/2);
2202 $$.t = registry_getobjectclass();
2207 if(BOTH_INT($1,$3)) {
2208 c=abc_multiply_i(c);
2212 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2213 $$.c = toreadwrite($1.c, c, 0, 0);
2218 code_t*c = abc_modulo($3.c);
2219 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2220 $$.c = toreadwrite($1.c, c, 0, 0);
2224 code_t*c = abc_lshift($3.c);
2225 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2226 $$.c = toreadwrite($1.c, c, 0, 0);
2230 code_t*c = abc_rshift($3.c);
2231 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2232 $$.c = toreadwrite($1.c, c, 0, 0);
2236 code_t*c = abc_urshift($3.c);
2237 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2238 $$.c = toreadwrite($1.c, c, 0, 0);
2242 code_t*c = abc_divide($3.c);
2243 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2244 $$.c = toreadwrite($1.c, c, 0, 0);
2249 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2254 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2256 $$.c = toreadwrite($1.c, c, 0, 0);
2259 E : E "-=" E { code_t*c = $3.c;
2260 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2261 c=abc_subtract_i(c);
2265 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2267 $$.c = toreadwrite($1.c, c, 0, 0);
2270 E : E '=' E { code_t*c = 0;
2271 c = code_append(c, $3.c);
2272 c = converttype(c, $3.t, $1.t);
2273 $$.c = toreadwrite($1.c, c, 1, 0);
2277 E : E '?' E ':' E %prec below_assignment {
2279 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2280 $$.c = code_append($$.c, $3.c);
2281 code_t*j2 = $$.c = abc_jump($$.c, 0);
2282 $$.c = j1->branch = abc_label($$.c);
2283 $$.c = code_append($$.c, $5.c);
2284 $$.c = j2->branch = abc_label($$.c);
2285 $$.t = join_types($3.t,$5.t,'?');
2288 // TODO: use inclocal where appropriate
2289 E : E "++" { code_t*c = 0;
2290 classinfo_t*type = $1.t;
2291 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2292 c=abc_increment_i(c);
2298 c=converttype(c, type, $1.t);
2299 $$.c = toreadwrite($1.c, c, 0, 1);
2302 E : E "--" { code_t*c = 0;
2303 classinfo_t*type = $1.t;
2304 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2305 c=abc_decrement_i(c);
2311 c=converttype(c, type, $1.t);
2312 $$.c = toreadwrite($1.c, c, 0, 1);
2316 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2317 classinfo_t*type = $2.t;
2318 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2319 c=abc_increment_i(c);
2325 c=converttype(c, type, $2.t);
2326 $$.c = toreadwrite($2.c, c, 0, 0);
2330 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2331 classinfo_t*type = $2.t;
2332 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2333 c=abc_decrement_i(c);
2339 c=converttype(c, type, $2.t);
2340 $$.c = toreadwrite($2.c, c, 0, 0);
2344 E : "super" '.' T_IDENTIFIER
2345 { if(!state->cls->info)
2346 syntaxerror("super keyword not allowed outside a class");
2347 classinfo_t*t = state->cls->info->superclass;
2348 if(!t) t = TYPE_OBJECT;
2350 memberinfo_t*f = registry_findmember(t, $3, 1);
2351 namespace_t ns = {flags2access(f->flags), ""};
2352 MEMBER_MULTINAME(m, f, $3);
2354 $$.c = abc_getlocal_0($$.c);
2355 $$.c = abc_getsuper2($$.c, &m);
2356 $$.t = memberinfo_gettype(f);
2359 E : E '.' T_IDENTIFIER
2361 classinfo_t*t = $1.t;
2363 if(TYPE_IS_CLASS(t) && t->cls) {
2368 memberinfo_t*f = registry_findmember(t, $3, 1);
2370 if(f && !is_static != !(f->flags&FLAG_STATIC))
2372 if(f && f->slot && !noslot) {
2373 $$.c = abc_getslot($$.c, f->slot);
2375 MEMBER_MULTINAME(m, f, $3);
2376 $$.c = abc_getproperty2($$.c, &m);
2378 /* determine type */
2379 $$.t = memberinfo_gettype(f);
2381 $$.c = abc_coerce_a($$.c);
2383 /* when resolving a property on an unknown type, we do know the
2384 name of the property (and don't seem to need the package), but
2385 we need to make avm2 try out all access modes */
2386 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2387 $$.c = abc_getproperty2($$.c, &m);
2388 $$.c = abc_coerce_a($$.c);
2389 $$.t = registry_getanytype();
2393 VAR_READ : T_IDENTIFIER {
2400 /* look at variables */
2401 if((v = find_variable($1))) {
2402 // $1 is a local variable
2403 $$.c = abc_getlocal($$.c, v->index);
2406 /* look at current class' members */
2407 } else if((f = registry_findmember(state->cls->info, $1, 1))) {
2408 // $1 is a function in this class
2409 int var_is_static = (f->flags&FLAG_STATIC);
2410 int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2411 if(var_is_static != i_am_static) {
2412 /* there doesn't seem to be any "static" way to access
2413 static properties of a class */
2414 state->method->late_binding = 1;
2416 namespace_t ns = {flags2access(f->flags), ""};
2417 multiname_t m = {QNAME, &ns, 0, $1};
2418 $$.c = abc_findpropstrict2($$.c, &m);
2419 $$.c = abc_getproperty2($$.c, &m);
2422 $$.c = abc_getlocal_0($$.c);
2423 $$.c = abc_getslot($$.c, f->slot);
2425 namespace_t ns = {flags2access(f->flags), ""};
2426 multiname_t m = {QNAME, &ns, 0, $1};
2427 $$.c = abc_getlocal_0($$.c);
2428 $$.c = abc_getproperty2($$.c, &m);
2431 if(f->kind == MEMBER_METHOD) {
2432 $$.t = TYPE_FUNCTION(f);
2437 /* look at actual classes, in the current package and imported */
2438 } else if((a = find_class($1))) {
2439 if(a->flags & FLAG_METHOD) {
2441 $$.c = abc_findpropstrict2($$.c, &m);
2442 $$.c = abc_getproperty2($$.c, &m);
2443 $$.t = TYPE_FUNCTION(a->function);
2446 $$.c = abc_getglobalscope($$.c);
2447 $$.c = abc_getslot($$.c, a->slot);
2450 $$.c = abc_getlex2($$.c, &m);
2452 $$.t = TYPE_CLASS(a);
2455 /* unknown object, let the avm2 resolve it */
2457 if(strcmp($1,"trace"))
2458 warning("Couldn't resolve '%s', doing late binding", $1);
2459 state->method->late_binding = 1;
2461 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2464 $$.c = abc_findpropstrict2($$.c, &m);
2465 $$.c = abc_getproperty2($$.c, &m);
2470 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2471 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2472 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2474 // ----------------- namespaces -------------------------------------------------
2476 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2477 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2478 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2480 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER