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"
45 enum yytokentype token;
48 classinfo_t*classinfo;
49 classinfo_list_t*classinfo_list;
52 unsigned int number_uint;
56 //typedcode_list_t*value_list;
57 codeandnumber_t value_list;
63 for_start_t for_start;
64 abc_exception_t *exception;
67 abc_exception_list_t *l;
73 %token<id> T_IDENTIFIER T_NAMESPACE
75 %token<regexp> T_REGEXP
77 %token<number_int> T_INT
78 %token<number_uint> T_UINT
79 %token<number_uint> T_BYTE
80 %token<number_uint> T_SHORT
81 %token<number_float> T_FLOAT
83 %token<id> T_FOR "for"
84 %token<id> T_WHILE "while"
86 %token<id> T_SWITCH "switch"
88 %token<token> KW_IMPLEMENTS "implements"
89 %token<token> KW_NAMESPACE "namespace"
90 %token<token> KW_PACKAGE "package"
91 %token<token> KW_PROTECTED "protected"
92 %token<token> KW_PUBLIC "public"
93 %token<token> KW_PRIVATE "private"
94 %token<token> KW_USE "use"
95 %token<token> KW_INTERNAL "internal"
96 %token<token> KW_NEW "new"
97 %token<token> KW_NATIVE "native"
98 %token<token> KW_FUNCTION "function"
99 %token<token> KW_FINALLY "finally"
100 %token<token> KW_UNDEFINED "undefined"
101 %token<token> KW_CONTINUE "continue"
102 %token<token> KW_CLASS "class"
103 %token<token> KW_CONST "const"
104 %token<token> KW_CATCH "catch"
105 %token<token> KW_CASE "case"
106 %token<token> KW_SET "set"
107 %token<token> KW_VOID "void"
108 %token<token> KW_THROW "throw"
109 %token<token> KW_STATIC "static"
110 %token<token> KW_WITH "with"
111 %token<token> KW_INSTANCEOF "instanceof"
112 %token<token> KW_IMPORT "import"
113 %token<token> KW_RETURN "return"
114 %token<token> KW_TYPEOF "typeof"
115 %token<token> KW_INTERFACE "interface"
116 %token<token> KW_NULL "null"
117 %token<token> KW_VAR "var"
118 %token<token> KW_DYNAMIC "dynamic"
119 %token<token> KW_OVERRIDE "override"
120 %token<token> KW_FINAL "final"
121 %token<token> KW_EACH "each"
122 %token<token> KW_GET "get"
123 %token<token> KW_TRY "try"
124 %token<token> KW_SUPER "super"
125 %token<token> KW_EXTENDS "extends"
126 %token<token> KW_FALSE "false"
127 %token<token> KW_TRUE "true"
128 %token<token> KW_BOOLEAN "Boolean"
129 %token<token> KW_UINT "uint"
130 %token<token> KW_INT "int"
131 %token<token> KW_NUMBER "Number"
132 %token<token> KW_STRING "String"
133 %token<token> KW_DEFAULT "default"
134 %token<token> KW_DELETE "delete"
135 %token<token> KW_IF "if"
136 %token<token> KW_ELSE "else"
137 %token<token> KW_BREAK "break"
138 %token<token> KW_IS "is"
139 %token<token> KW_IN "in"
140 %token<token> KW_AS "as"
142 %token<token> T_EQEQ "=="
143 %token<token> T_EQEQEQ "==="
144 %token<token> T_NE "!="
145 %token<token> T_NEE "!=="
146 %token<token> T_LE "<="
147 %token<token> T_GE ">="
148 %token<token> T_ORBY "|="
149 %token<token> T_DIVBY "/="
150 %token<token> T_MODBY "%="
151 %token<token> T_MULBY "*="
152 %token<token> T_PLUSBY "+="
153 %token<token> T_MINUSBY "-="
154 %token<token> T_SHRBY ">>="
155 %token<token> T_SHLBY "<<="
156 %token<token> T_USHRBY ">>>="
157 %token<token> T_OROR "||"
158 %token<token> T_ANDAND "&&"
159 %token<token> T_COLONCOLON "::"
160 %token<token> T_MINUSMINUS "--"
161 %token<token> T_PLUSPLUS "++"
162 %token<token> T_DOTDOT ".."
163 %token<token> T_DOTDOTDOT "..."
164 %token<token> T_SHL "<<"
165 %token<token> T_USHR ">>>"
166 %token<token> T_SHR ">>"
168 %type <for_start> FOR_START
169 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
170 %type <token> VARCONST
172 %type <code> CODEPIECE CODE_STATEMENT
173 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
174 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
175 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
176 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
177 %type <exception> CATCH FINALLY
178 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
179 %type <code> CLASS_DECLARATION
180 %type <code> NAMESPACE_DECLARATION
181 %type <code> INTERFACE_DECLARATION
182 %type <code> VOIDEXPRESSION
183 %type <value> EXPRESSION NONCOMMAEXPRESSION
184 %type <value> MAYBEEXPRESSION
185 %type <value> E DELETE
186 %type <value> CONSTANT
187 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
188 %type <value> INNERFUNCTION
189 %type <code> USE_NAMESPACE
190 %type <code> FOR_INIT
192 %type <classinfo> MAYBETYPE
195 %type <params> PARAM_LIST
196 %type <params> MAYBE_PARAM_LIST
197 %type <flags> MAYBE_MODIFIERS
198 %type <flags> MODIFIER_LIST
199 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
200 %type <classinfo_list> IMPLEMENTS_LIST
201 %type <classinfo> EXTENDS
202 %type <classinfo_list> EXTENDS_LIST
203 %type <classinfo> CLASS PACKAGEANDCLASS CLASS_SPEC
204 %type <classinfo_list> CLASS_SPEC_LIST
205 %type <classinfo> TYPE
206 //%type <token> VARIABLE
207 %type <value> VAR_READ
209 //%type <token> T_IDENTIFIER
210 %type <token> MODIFIER
211 %type <value> FUNCTIONCALL
212 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
214 // precedence: from low to high
218 %left below_semicolon
221 %nonassoc below_assignment // for ?:, contrary to spec
222 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
229 %nonassoc "==" "!=" "===" "!=="
230 %nonassoc "is" "as" "in"
231 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
232 %left "<<" ">>" ">>>"
236 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
238 %nonassoc below_curly
242 %left '[' ']' "new" '{' '.' ".." "::" '@'
244 %nonassoc T_IDENTIFIER
245 %left above_identifier
249 // needed for "return" precedence:
250 %nonassoc T_STRING T_REGEXP
251 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
252 %nonassoc "false" "true" "null" "undefined" "super" "function"
259 static int a3_error(char*s)
261 syntaxerror("%s", s);
262 return 0; //make gcc happy
266 static char* concat2(const char* t1, const char* t2)
270 char*text = malloc(l1+l2+1);
271 memcpy(text , t1, l1);
272 memcpy(text+l1, t2, l2);
276 static char* concat3(const char* t1, const char* t2, const char* t3)
281 char*text = malloc(l1+l2+l3+1);
282 memcpy(text , t1, l1);
283 memcpy(text+l1, t2, l2);
284 memcpy(text+l1+l2, t3, l3);
289 typedef struct _import {
293 DECLARE_LIST(import);
295 typedef struct _classstate {
301 char has_constructor;
304 DECLARE_LIST(methodstate);
306 typedef struct _methodstate {
317 int var_index; // for inner methods
319 abc_exception_list_t*exceptions;
321 methodstate_list_t*innerfunctions;
324 typedef struct _state {
329 import_list_t*wildcard_imports;
331 char has_own_imports;
332 char new_vars; // e.g. transition between two functions
335 methodstate_t*method;
342 typedef struct _global {
346 dict_t*file2token2info;
349 static global_t*global = 0;
350 static state_t* state = 0;
354 #define MULTINAME(m,x) \
358 registry_fill_multiname(&m, &m##_ns, (slotinfo_t*)(x));
360 #define MEMBER_MULTINAME(m,f,n) \
364 m##_ns.access = (f)->access; \
368 m.namespace_set = 0; \
371 m.type = MULTINAME; \
373 m.namespace_set = &nopackage_namespace_set; \
377 /* warning: list length of namespace set is undefined */
378 #define MULTINAME_LATE(m, access, package) \
379 namespace_t m##_ns = {access, package}; \
380 namespace_set_t m##_nsset; \
381 namespace_list_t m##_l;m##_l.next = 0; \
382 m##_nsset.namespaces = &m##_l; \
383 m##_nsset = m##_nsset; \
384 m##_l.namespace = &m##_ns; \
385 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
387 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
388 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
389 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
390 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
391 static namespace_list_t nl4 = {&ns4,0};
392 static namespace_list_t nl3 = {&ns3,&nl4};
393 static namespace_list_t nl2 = {&ns2,&nl3};
394 static namespace_list_t nl1 = {&ns1,&nl2};
395 static namespace_set_t nopackage_namespace_set = {&nl1};
397 static void new_state()
400 state_t*oldstate = state;
402 memcpy(s, state, sizeof(state_t)); //shallow copy
404 s->imports = dict_new();
408 state->has_own_imports = 0;
409 state->vars = dict_new();
410 state->old = oldstate;
412 static void state_has_imports()
414 state->wildcard_imports = list_clone(state->wildcard_imports);
415 state->imports = dict_clone(state->imports);
416 state->has_own_imports = 1;
419 static void state_destroy(state_t*state)
421 if(state->has_own_imports) {
422 list_free(state->wildcard_imports);
423 dict_destroy(state->imports);state->imports=0;
425 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
426 dict_destroy(state->imports);state->imports=0;
430 for(t=0;t<state->vars->hashsize;t++) {
431 dictentry_t*e =state->vars->slots[t];
433 free(e->data);e->data=0;
437 dict_destroy(state->vars);state->vars=0;
443 static void old_state()
445 if(!state || !state->old)
446 syntaxerror("invalid nesting");
447 state_t*leaving = state;
451 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
452 free(leaving->method);
455 if(leaving->cls && leaving->cls != state->cls) {
460 state_destroy(leaving);
463 static char* internal_filename_package = 0;
464 void initialize_file(char*filename)
467 syntaxerror("invalid call to initialize_file during parsing of another file");
470 state->package = internal_filename_package = strdup(filename);
472 state->method = rfx_calloc(sizeof(methodstate_t));
473 state->method->variable_count = 1;
475 global->token2info = dict_lookup(global->file2token2info,
476 current_filename // use long version
478 if(!global->token2info) {
479 global->token2info = dict_new2(&ptr_type);
480 dict_put(global->file2token2info, current_filename, global->token2info);
486 if(!state || state->level!=1) {
487 syntaxerror("unexpected end of file in pass %d", as3_pass);
489 free(state->method);state->method=0;
491 //free(state->package);state->package=0; // used in registry
493 state_destroy(state);state=0;
496 void initialize_parser()
498 global = rfx_calloc(sizeof(global_t));
499 global->file = abc_file_new();
500 global->file->flags &= ~ABCFILE_LAZY;
501 global->file2token2info = dict_new();
502 global->token2info = 0;
504 global->init = abc_initscript(global->file);
505 code_t*c = global->init->method->body->code;
506 c = abc_getlocal_0(c);
507 c = abc_pushscope(c);
508 global->init->method->body->code = c;
511 void* finish_parser()
513 code_t*c = global->init->method->body->code;
514 /*c = abc_findpropstrict(c, "[package]::trace");
515 c = abc_pushstring(c, "[leaving global init function]");
516 c = abc_callpropvoid(c, "[package]::trace", 1);*/
517 c = abc_returnvoid(c);
518 global->init->method->body->code = c;
520 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
522 global->token2info=0;
528 static void xx_scopetest()
530 /* findpropstrict doesn't just return a scope object- it
531 also makes it "active" somehow. Push local_0 on the
532 scope stack and read it back with findpropstrict, it'll
533 contain properties like "trace". Trying to find the same
534 property on a "vanilla" local_0 yields only a "undefined" */
535 //c = abc_findpropstrict(c, "[package]::trace");
537 /*c = abc_getlocal_0(c);
538 c = abc_findpropstrict(c, "[package]::trace");
540 c = abc_setlocal_1(c);
542 c = abc_pushbyte(c, 0);
543 c = abc_setlocal_2(c);
545 code_t*xx = c = abc_label(c);
546 c = abc_findpropstrict(c, "[package]::trace");
547 c = abc_pushstring(c, "prop:");
548 c = abc_hasnext2(c, 1, 2);
550 c = abc_setlocal_3(c);
551 c = abc_callpropvoid(c, "[package]::trace", 2);
552 c = abc_getlocal_3(c);
554 c = abc_iftrue(c,xx);*/
558 typedef struct _variable {
564 static variable_t* find_variable(char*name)
570 v = dict_lookup(s->vars, name);
580 static variable_t* find_variable_safe(char*name)
582 variable_t* v = find_variable(name);
584 syntaxerror("undefined variable: %s", name);
587 static char variable_exists(char*name)
589 return dict_lookup(state->vars, name)!=0;
591 code_t*defaultvalue(code_t*c, classinfo_t*type);
592 static int new_variable(const char*name, classinfo_t*type, char init)
595 v->index = state->method->variable_count;
599 dict_put(state->vars, name, v);
601 return state->method->variable_count++;
603 #define TEMPVARNAME "__as3_temp__"
604 static int gettempvar()
606 variable_t*v = find_variable(TEMPVARNAME);
609 return new_variable(TEMPVARNAME, 0, 0);
612 code_t* var_block(code_t*body)
618 for(t=0;t<state->vars->hashsize;t++) {
619 dictentry_t*e = state->vars->slots[t];
621 variable_t*v = (variable_t*)e->data;
622 if(v->type && v->init) {
623 c = defaultvalue(c, v->type);
624 c = abc_setlocal(c, v->index);
625 k = abc_kill(k, v->index);
635 if(x->opcode== OPCODE___BREAK__ ||
636 x->opcode== OPCODE___CONTINUE__) {
637 /* link kill code before break/continue */
638 code_t*e = code_dup(k);
639 code_t*s = code_start(e);
651 c = code_append(c, body);
652 c = code_append(c, k);
656 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
658 static void parsererror(const char*file, int line, const char*f)
660 syntaxerror("internal error in %s, %s:%d", f, file, line);
664 code_t* method_header()
667 if(state->method->late_binding && !state->method->inner) {
668 c = abc_getlocal_0(c);
669 c = abc_pushscope(c);
671 /*if(state->method->innerfunctions) {
672 c = abc_newactivation(c);
673 c = abc_pushscope(c);
675 if(state->method->is_constructor && !state->method->has_super) {
676 // call default constructor
677 c = abc_getlocal_0(c);
678 c = abc_constructsuper(c, 0);
680 methodstate_list_t*l = state->method->innerfunctions;
682 parserassert(l->methodstate->abc);
683 c = abc_newfunction(c, l->methodstate->abc);
684 c = abc_setlocal(c, l->methodstate->var_index);
685 free(l->methodstate);l->methodstate=0;
688 list_free(state->method->innerfunctions);
689 state->method->innerfunctions = 0;
694 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
696 c = code_append(c, header);
697 c = code_append(c, var_block(body));
698 /* append return if necessary */
699 if(!c || (c->opcode != OPCODE_RETURNVOID &&
700 c->opcode != OPCODE_RETURNVALUE)) {
701 c = abc_returnvoid(c);
707 static void startpackage(char*name)
710 /*printf("entering package \"%s\"\n", name);*/
711 state->package = strdup(name);
713 static void endpackage()
715 /*printf("leaving package \"%s\"\n", state->package);*/
717 //used e.g. in classinfo_register:
718 //free(state->package);state->package=0;
723 #define FLAG_PUBLIC 256
724 #define FLAG_PROTECTED 512
725 #define FLAG_PRIVATE 1024
726 #define FLAG_PACKAGEINTERNAL 2048
727 #define FLAG_NAMESPACE 4096
729 static int flags2access(int flags)
732 if(flags&FLAG_PUBLIC) {
733 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
734 syntaxerror("invalid combination of access levels");
735 access = ACCESS_PACKAGE;
736 } else if(flags&FLAG_PRIVATE) {
737 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
738 syntaxerror("invalid combination of access levels");
739 access = ACCESS_PRIVATE;
740 } else if(flags&FLAG_PROTECTED) {
741 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
742 syntaxerror("invalid combination of access levels");
743 access = ACCESS_PROTECTED;
745 access = ACCESS_PACKAGEINTERNAL;
750 char*as3_globalclass=0;
751 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements)
754 syntaxerror("inner classes now allowed");
757 state->cls = rfx_calloc(sizeof(classstate_t));
760 classinfo_list_t*mlist=0;
762 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
763 syntaxerror("invalid modifier(s)");
765 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
766 syntaxerror("public and internal not supported at the same time.");
768 /* create the class name, together with the proper attributes */
772 if(!(flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
773 access = ACCESS_PRIVATE; package = internal_filename_package;
774 } else if(!(flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
775 access = ACCESS_PACKAGEINTERNAL; package = state->package;
776 } else if(state->package!=internal_filename_package) {
777 access = ACCESS_PACKAGE; package = state->package;
779 syntaxerror("public classes only allowed inside a package");
783 state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
784 state->method->variable_count = 1;
785 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
787 if(registry_find(package, classname)) {
788 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
790 /* build info struct */
791 int num_interfaces = (list_length(implements));
792 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
793 state->cls->info->flags |= flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
797 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
799 state->cls->info = (classinfo_t*)registry_find(package, classname);
800 parserassert((int)state->cls->info);
802 if(extends && (extends->flags & FLAG_FINAL))
803 syntaxerror("Can't extend final class '%s'", extends->name);
805 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
806 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
808 classinfo_list_t*l = implements;
809 for(l=implements;l;l=l->next) {
810 if(!(l->classinfo->flags & FLAG_INTERFACE))
811 syntaxerror("'%s' is not an interface", l->classinfo->name);
812 state->cls->info->interfaces[pos++] = l->classinfo;
815 /* generate the abc code for this class */
816 MULTINAME(classname2,state->cls->info);
817 multiname_t*extends2 = sig2mname(extends);
819 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
820 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
821 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
822 if(state->cls->info->flags&FLAG_INTERFACE) {
823 abc_class_interface(state->cls->abc);
826 abc_class_protectedNS(state->cls->abc, classname);
828 for(mlist=implements;mlist;mlist=mlist->next) {
829 MULTINAME(m, mlist->classinfo);
830 abc_class_add_interface(state->cls->abc, &m);
833 /* write the construction code for this class to the global init
835 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
837 abc_method_body_t*m = global->init->method->body;
838 __ getglobalscope(m);
839 classinfo_t*s = extends;
844 //TODO: take a look at the current scope stack, maybe
845 // we can re-use something
850 multiname_t*s2 = sig2mname(s);
852 multiname_destroy(s2);
854 __ pushscope(m); count++;
855 m->code = m->code->prev->prev; // invert
857 /* continue appending after last op end */
858 while(m->code && m->code->next) m->code = m->code->next;
860 /* TODO: if this is one of *our* classes, we can also
861 do a getglobalscope/getslot <nr> (which references
862 the init function's slots) */
864 __ getlex2(m, extends2);
866 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
867 stack is not the superclass */
868 __ pushscope(m);count++;
871 /* notice: we get a verify error #1107 if the top element on the scope
872 stack is not the global object */
874 __ pushscope(m);count++;
876 __ newclass(m,state->cls->abc);
880 __ setslot(m, slotindex);
881 multiname_destroy(extends2);
883 /* flash.display.MovieClip handling */
885 if(!as3_globalclass && (flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
886 if(state->package && state->package[0]) {
887 as3_globalclass = concat3(state->package, ".", classname);
889 as3_globalclass = strdup(classname);
895 static void endclass()
898 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
900 c = abc_getlocal_0(c);
901 c = abc_constructsuper(c, 0);
902 state->cls->init = code_append(state->cls->init, c);
904 if(!state->method->late_binding) {
905 // class initialization code uses late binding
907 c = abc_getlocal_0(c);
908 c = abc_pushscope(c);
909 state->cls->static_init = code_append(c, state->cls->static_init);
912 if(state->cls->init) {
913 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
914 m->body->code = wrap_function(0, state->cls->init, m->body->code);
916 if(state->cls->static_init) {
917 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
918 m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
925 void check_code_for_break(code_t*c)
928 if(c->opcode == OPCODE___BREAK__) {
929 char*name = string_cstr(c->data[0]);
930 syntaxerror("Unresolved \"break %s\"", name);
932 if(c->opcode == OPCODE___CONTINUE__) {
933 char*name = string_cstr(c->data[0]);
934 syntaxerror("Unresolved \"continue %s\"", name);
941 static void check_constant_against_type(classinfo_t*t, constant_t*c)
943 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
944 if(TYPE_IS_NUMBER(t)) {
945 xassert(c->type == CONSTANT_FLOAT
946 || c->type == CONSTANT_INT
947 || c->type == CONSTANT_UINT);
948 } else if(TYPE_IS_UINT(t)) {
949 xassert(c->type == CONSTANT_UINT ||
950 (c->type == CONSTANT_INT && c->i>0));
951 } else if(TYPE_IS_INT(t)) {
952 xassert(c->type == CONSTANT_INT);
953 } else if(TYPE_IS_BOOLEAN(t)) {
954 xassert(c->type == CONSTANT_TRUE
955 || c->type == CONSTANT_FALSE);
959 static void check_override(memberinfo_t*m, int flags)
963 if(m->parent == state->cls->info)
964 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
966 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
967 if(m->access==ACCESS_PRIVATE)
969 if(m->flags & FLAG_FINAL)
970 syntaxerror("can't override final member %s", m->name);
971 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
972 syntaxerror("can't override static member %s", m->name);
973 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
974 syntaxerror("can't override non-static member %s with static declaration", m->name);
976 if(!(flags&FLAG_OVERRIDE)) {
977 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
978 if(m->kind == INFOTYPE_METHOD)
979 syntaxerror("can't override without explicit 'override' declaration");
981 syntaxerror("can't override '%s'", m->name);
986 static methodinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
988 methodinfo_t*minfo = 0;
989 U8 access = flags2access(flags);
992 minfo = methodinfo_register_global(access, state->package, name);
993 minfo->return_type = return_type;
994 } else if(getset != KW_GET && getset != KW_SET) {
996 memberinfo_t* m = registry_findmember(state->cls->info, name, 0);
998 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1000 minfo = methodinfo_register_onclass(state->cls->info, access, name);
1001 minfo->return_type = return_type;
1002 // getslot on a member slot only returns "undefined", so no need
1003 // to actually store these
1004 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1006 //class getter/setter
1007 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1009 if(getset == KW_GET)
1011 else if(params->list && params->list->param)
1012 type = params->list->param->type;
1013 // not sure wether to look into superclasses here, too
1014 minfo = (methodinfo_t*)registry_findmember(state->cls->info, name, 1);
1016 if(minfo->kind!=INFOTYPE_SLOT)
1017 syntaxerror("class already contains a method called '%s'", name);
1018 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1019 syntaxerror("class already contains a field called '%s'", name);
1020 if(minfo->subtype & gs)
1021 syntaxerror("getter/setter for '%s' already defined", name);
1022 /* make a setter or getter into a getset */
1023 minfo->subtype |= gs;
1024 if(!minfo->return_type) {
1025 minfo->return_type = type;
1027 if(minfo && minfo->return_type != type)
1028 syntaxerror("different type in getter and setter");
1031 minfo = methodinfo_register_onclass(state->cls->info, access, name);
1032 minfo->kind = INFOTYPE_SLOT; //hack
1033 minfo->subtype = gs;
1034 minfo->return_type = type;
1036 /* can't assign a slot as getter and setter might have different slots */
1037 //minfo->slot = slot;
1039 if(flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1040 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1041 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1045 static void function_initvars(params_t*params, int flags)
1047 if(state->method->inner)
1048 new_variable("this", 0, 0);
1049 else if(!state->method->is_global)
1050 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
1052 new_variable("globalscope", 0, 0);
1055 for(p=params->list;p;p=p->next) {
1056 new_variable(p->param->name, p->param->type, 0);
1059 methodstate_list_t*l = state->method->innerfunctions;
1061 methodstate_t*m = l->methodstate;
1062 m->var_index = new_variable(m->info->name, TYPE_FUNCTION(m->info), 0);
1067 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1069 parserassert(state->method && state->method->info);
1071 methodstate_t*parent_method = state->method;
1080 state->new_vars = 1;
1083 state->method = rfx_calloc(sizeof(methodstate_t));
1084 state->method->inner = 1;
1085 state->method->variable_count = 0;
1086 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1088 NEW(methodinfo_t,minfo);
1090 state->method->info = minfo;
1092 list_append(parent_method->innerfunctions, state->method);
1094 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1098 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1099 parserassert(state->method);
1101 state->method->info->return_type = return_type;
1102 function_initvars(params, 0);
1106 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
1107 params_t*params, classinfo_t*return_type)
1109 if(state->method && state->method->info) {
1110 syntaxerror("not able to start another method scope");
1115 state->method = rfx_calloc(sizeof(methodstate_t));
1116 state->method->has_super = 0;
1117 state->method->variable_count = 0;
1120 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1122 state->method->is_global = 1;
1123 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1125 if(state->method->is_constructor)
1126 name = "__as3_constructor__";
1129 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
1131 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1135 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1136 parserassert(state->method);
1139 memberinfo_t*m = registry_findmember(state->cls->info, name, 2);
1140 check_override(m, flags);
1144 state->cls->has_constructor |= state->method->is_constructor;
1147 state->method->info->return_type = return_type;
1148 function_initvars(params, flags);
1152 static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
1153 params_t*params, classinfo_t*return_type, code_t*body)
1162 multiname_t*type2 = sig2mname(return_type);
1164 if(state->method->inner) {
1165 f = state->method->abc;
1166 abc_method_init(f, global->file, type2, 1);
1167 } else if(state->method->is_constructor) {
1168 f = abc_class_getconstructor(state->cls->abc, type2);
1169 } else if(!state->method->is_global) {
1170 namespace_t mname_ns = {state->method->info->access, ""};
1171 multiname_t mname = {QNAME, &mname_ns, 0, name};
1173 if(flags&FLAG_STATIC)
1174 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1176 f = abc_class_method(state->cls->abc, type2, &mname);
1177 slot = f->trait->slot_id;
1179 namespace_t mname_ns = {state->method->info->access, state->package};
1180 multiname_t mname = {QNAME, &mname_ns, 0, name};
1182 f = abc_method_new(global->file, type2, 1);
1183 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1184 //abc_code_t*c = global->init->method->body->code;
1186 //flash doesn't seem to allow us to access function slots
1187 //state->method->info->slot = slot;
1189 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1190 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1191 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1192 if(params->varargs) f->flags |= METHOD_NEED_REST;
1196 for(p=params->list;p;p=p->next) {
1197 if(params->varargs && !p->next) {
1198 break; //varargs: omit last parameter in function signature
1200 multiname_t*m = sig2mname(p->param->type);
1201 list_append(f->parameters, m);
1202 if(p->param->value) {
1203 check_constant_against_type(p->param->type, p->param->value);
1204 opt=1;list_append(f->optional_parameters, p->param->value);
1206 syntaxerror("non-optional parameter not allowed after optional parameters");
1209 check_code_for_break(body);
1212 f->body->code = body;
1213 f->body->exceptions = state->method->exceptions;
1214 } else { //interface
1216 syntaxerror("interface methods can't have a method body");
1223 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1228 void breakjumpsto(code_t*c, char*name, code_t*jump)
1231 if(c->opcode == OPCODE___BREAK__) {
1232 string_t*name2 = c->data[0];
1233 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1234 c->opcode = OPCODE_JUMP;
1241 void continuejumpsto(code_t*c, char*name, code_t*jump)
1244 if(c->opcode == OPCODE___CONTINUE__) {
1245 string_t*name2 = c->data[0];
1246 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1247 c->opcode = OPCODE_JUMP;
1255 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1256 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1257 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1259 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1261 if(!type1 || !type2)
1262 return registry_getanytype();
1263 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1264 return registry_getanytype();
1267 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1276 return registry_getanytype();
1278 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1283 return abc_coerce_a(c);
1287 // cast an "any" type to a specific type. subject to
1288 // runtime exceptions
1289 return abc_coerce2(c, &m);
1292 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1293 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1294 // allow conversion between number types
1295 return abc_coerce2(c, &m);
1297 //printf("%s.%s\n", from.package, from.name);
1298 //printf("%s.%s\n", to.package, to.name);
1300 classinfo_t*supertype = from;
1302 if(supertype == to) {
1303 // target type is one of from's superclasses
1304 return abc_coerce2(c, &m);
1307 while(supertype->interfaces[t]) {
1308 if(supertype->interfaces[t]==to) {
1309 // target type is one of from's interfaces
1310 return abc_coerce2(c, &m);
1314 supertype = supertype->superclass;
1316 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1318 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1320 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1322 syntaxerror("can't convert type %s to %s", from->name, to->name);
1323 return 0; // make gcc happy
1326 code_t*defaultvalue(code_t*c, classinfo_t*type)
1328 if(TYPE_IS_INT(type)) {
1329 c = abc_pushbyte(c, 0);
1330 } else if(TYPE_IS_UINT(type)) {
1331 c = abc_pushuint(c, 0);
1332 } else if(TYPE_IS_FLOAT(type)) {
1334 } else if(TYPE_IS_BOOLEAN(type)) {
1335 c = abc_pushfalse(c);
1337 //c = abc_pushundefined(c);
1339 c = abc_pushnull(c);
1341 c = abc_coerce2(c, &m);
1346 char is_pushundefined(code_t*c)
1348 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1351 static slotinfo_t* find_class(char*name)
1355 c = registry_find(state->package, name);
1358 /* try explicit imports */
1359 dictentry_t* e = dict_get_slot(state->imports, name);
1362 if(!strcmp(e->key, name)) {
1363 c = (slotinfo_t*)e->data;
1369 /* try package.* imports */
1370 import_list_t*l = state->wildcard_imports;
1372 //printf("does package %s contain a class %s?\n", l->import->package, name);
1373 c = registry_find(l->import->package, name);
1378 /* try global package */
1379 c = registry_find("", name);
1382 /* try local "filename" package */
1383 c = registry_find(internal_filename_package, name);
1389 static char is_getlocal(code_t*c)
1391 if(!c || c->prev || c->next)
1393 return(c->opcode == OPCODE_GETLOCAL
1394 || c->opcode == OPCODE_GETLOCAL_0
1395 || c->opcode == OPCODE_GETLOCAL_1
1396 || c->opcode == OPCODE_GETLOCAL_2
1397 || c->opcode == OPCODE_GETLOCAL_3);
1399 static int getlocalnr(code_t*c)
1401 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1402 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1403 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1404 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1405 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1406 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1410 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1414 [prefix code] [read instruction]
1418 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1420 if(in && in->opcode == OPCODE_COERCE_A) {
1421 in = code_cutlast(in);
1424 syntaxerror("internal error");
1426 /* chop off read instruction */
1430 prefix = r->prev;r->prev = 0;
1436 char use_temp_var = readbefore;
1438 /* generate the write instruction, and maybe append a dup to the prefix code */
1439 code_t* write = abc_nop(0);
1440 if(r->opcode == OPCODE_GETPROPERTY) {
1441 write->opcode = OPCODE_SETPROPERTY;
1442 multiname_t*m = (multiname_t*)r->data[0];
1443 write->data[0] = multiname_clone(m);
1444 if(m->type == QNAME || m->type == MULTINAME) {
1446 prefix = abc_dup(prefix); // we need the object, too
1449 } else if(m->type == MULTINAMEL) {
1451 /* dupping two values on the stack requires 5 operations and one register-
1452 couldn't adobe just have given us a dup2? */
1453 int temp = gettempvar();
1454 prefix = abc_setlocal(prefix, temp);
1455 prefix = abc_dup(prefix);
1456 prefix = abc_getlocal(prefix, temp);
1457 prefix = abc_swap(prefix);
1458 prefix = abc_getlocal(prefix, temp);
1460 prefix = abc_kill(prefix, temp);
1464 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1466 } else if(r->opcode == OPCODE_GETSLOT) {
1467 write->opcode = OPCODE_SETSLOT;
1468 write->data[0] = r->data[0];
1470 prefix = abc_dup(prefix); // we need the object, too
1473 } else if(r->opcode == OPCODE_GETLOCAL) {
1474 write->opcode = OPCODE_SETLOCAL;
1475 write->data[0] = r->data[0];
1476 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1477 write->opcode = OPCODE_SETLOCAL_0;
1478 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1479 write->opcode = OPCODE_SETLOCAL_1;
1480 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1481 write->opcode = OPCODE_SETLOCAL_2;
1482 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1483 write->opcode = OPCODE_SETLOCAL_3;
1486 syntaxerror("illegal lvalue: can't assign a value to this expression");
1493 /* with getproperty/getslot, we have to be extra careful not
1494 to execute the read code twice, as it might have side-effects
1495 (e.g. if the property is in fact a setter/getter combination)
1497 So read the value, modify it, and write it again,
1498 using prefix only once and making sure (by using a temporary
1499 register) that the return value is what we just wrote */
1500 temp = gettempvar();
1501 c = code_append(c, prefix);
1502 c = code_append(c, r);
1505 c = abc_setlocal(c, temp);
1507 c = code_append(c, middlepart);
1510 c = abc_setlocal(c, temp);
1512 c = code_append(c, write);
1513 c = abc_getlocal(c, temp);
1514 c = abc_kill(c, temp);
1516 /* if we're allowed to execute the read code twice *and*
1517 the middlepart doesn't modify the code, things are easier.
1519 code_t* r2 = code_dup(r);
1520 //c = code_append(c, prefix);
1521 parserassert(!prefix);
1522 c = code_append(c, r);
1523 c = code_append(c, middlepart);
1524 c = code_append(c, write);
1525 c = code_append(c, r2);
1528 /* even smaller version: overwrite the value without reading
1532 c = code_append(c, prefix);
1535 c = code_append(c, middlepart);
1536 c = code_append(c, write);
1537 c = code_append(c, r);
1540 temp = gettempvar();
1542 c = code_append(c, prefix);
1544 c = code_append(c, middlepart);
1546 c = abc_setlocal(c, temp);
1547 c = code_append(c, write);
1548 c = abc_getlocal(c, temp);
1549 c = abc_kill(c, temp);
1555 char is_break_or_jump(code_t*c)
1559 if(c->opcode == OPCODE_JUMP ||
1560 c->opcode == OPCODE___BREAK__ ||
1561 c->opcode == OPCODE___CONTINUE__ ||
1562 c->opcode == OPCODE_THROW ||
1563 c->opcode == OPCODE_RETURNVOID ||
1564 c->opcode == OPCODE_RETURNVALUE) {
1571 #define IS_FINALLY_TARGET(op) \
1572 ((op) == OPCODE___CONTINUE__ || \
1573 (op) == OPCODE___BREAK__ || \
1574 (op) == OPCODE_RETURNVOID || \
1575 (op) == OPCODE_RETURNVALUE || \
1576 (op) == OPCODE___RETHROW__)
1578 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1580 #define NEED_EXTRA_STACK_ARG
1581 code_t*finally_label = abc_nop(0);
1582 NEW(lookupswitch_t, l);
1588 code_t*prev = i->prev;
1589 if(IS_FINALLY_TARGET(i->opcode)) {
1592 if(i->opcode == OPCODE___RETHROW__ ||
1593 i->opcode == OPCODE_RETURNVALUE) {
1594 if(i->opcode == OPCODE___RETHROW__)
1595 i->opcode = OPCODE_THROW;
1597 p = abc_coerce_a(p);
1598 p = abc_setlocal(p, tempvar);
1600 p = abc_pushbyte(p, count++);
1601 p = abc_jump(p, finally_label);
1602 code_t*target = p = abc_label(p);
1603 #ifdef NEED_EXTRA_STACK_ARG
1607 p = abc_getlocal(p, tempvar);
1610 p->next = i;i->prev = p;
1611 list_append(l->targets, target);
1617 c = abc_pushbyte(c, -1);
1618 c = code_append(c, finally_label);
1619 c = code_append(c, finally);
1621 #ifdef NEED_EXTRA_STACK_ARG
1624 c = abc_lookupswitch(c, l);
1625 c = l->def = abc_label(c);
1626 #ifdef NEED_EXTRA_STACK_ARG
1633 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1637 code_t*prev = i->prev;
1638 if(IS_FINALLY_TARGET(i->opcode)) {
1639 if(i->opcode == OPCODE___RETHROW__)
1640 i->opcode = OPCODE_THROW;
1641 code_t*end = code_dup(finally);
1642 code_t*start = code_start(end);
1643 if(prev) prev->next = start;
1650 return code_append(c, finally);
1653 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1659 int num_insertion_points=0;
1661 if(IS_FINALLY_TARGET(i->opcode))
1662 num_insertion_points++;
1669 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1674 int simple_version_cost = (1+num_insertion_points)*code_size;
1675 int lookup_version_cost = 4*num_insertion_points + 5;
1677 if(cantdup || simple_version_cost > lookup_version_cost) {
1678 printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
1679 return insert_finally_lookup(c, finally, tempvar);
1681 printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
1682 return insert_finally_simple(c, finally, tempvar);
1686 #define PASS1 }} if(as3_pass == 1) {{
1687 #define PASS1END }} if(as3_pass == 2) {{
1688 #define PASS2 }} if(as3_pass == 2) {{
1689 #define PASS12 }} {{
1690 #define PASS12END }} if(as3_pass == 2) {{
1696 /* ------------ code blocks / statements ---------------- */
1698 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1700 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1701 PROGRAM_CODE_LIST: PROGRAM_CODE
1702 | PROGRAM_CODE_LIST PROGRAM_CODE
1704 PROGRAM_CODE: PACKAGE_DECLARATION
1705 | INTERFACE_DECLARATION
1707 | FUNCTION_DECLARATION
1710 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' // conditional compilation
1713 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1714 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1715 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1717 INPACKAGE_CODE: INTERFACE_DECLARATION
1719 | FUNCTION_DECLARATION
1722 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' // conditional compilation
1725 MAYBECODE: CODE {$$=$1;}
1726 MAYBECODE: {$$=code_new();}
1728 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1729 CODE: CODEPIECE {$$=$1;}
1731 // code which also may appear outside a method
1732 CODE_STATEMENT: IMPORT
1734 CODE_STATEMENT: FOR_IN
1735 CODE_STATEMENT: WHILE
1736 CODE_STATEMENT: DO_WHILE
1737 CODE_STATEMENT: SWITCH
1739 CODE_STATEMENT: WITH
1741 CODE_STATEMENT: VOIDEXPRESSION
1742 CODE_STATEMENT: USE_NAMESPACE
1744 // code which may appear anywhere
1745 CODEPIECE: ';' {$$=0;}
1746 CODEPIECE: CODE_STATEMENT
1747 CODEPIECE: VARIABLE_DECLARATION
1752 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
1754 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1756 CODEBLOCK : '{' CODE '}' {$$=$2;}
1757 CODEBLOCK : '{' '}' {$$=0;}
1758 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1759 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1761 /* ------------ package init code ------------------- */
1763 PACKAGE_INITCODE: CODE_STATEMENT {
1764 code_t**cc = &global->init->method->body->code;
1765 *cc = code_append(*cc, $1);
1768 /* ------------ conditional compilation ------------- */
1770 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER
1772 /* ------------ variables --------------------------- */
1774 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1775 | {$$.c=abc_pushundefined(0);
1779 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1780 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1782 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1783 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1785 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1787 if(variable_exists($1))
1788 syntaxerror("Variable %s already defined", $1);
1790 if(!is_subtype_of($3.t, $2)) {
1791 syntaxerror("Can't convert %s to %s", $3.t->name,
1795 int index = new_variable($1, $2, 1);
1798 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1800 $$ = converttype($$, $3.t, $2);
1801 $$ = abc_setlocal($$, index);
1804 $$ = defaultvalue(0, $2);
1805 $$ = abc_setlocal($$, index);
1808 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1810 $$ = abc_coerce_a($$);
1811 $$ = abc_setlocal($$, index);
1818 /* that's the default for a local register, anyway
1820 state->method->initcode = abc_pushundefined(state->method->initcode);
1821 state->method->initcode = abc_setlocal(state->method->initcode, index);
1823 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1826 /* ------------ control flow ------------------------- */
1828 MAYBEELSE: %prec below_else {$$ = code_new();}
1829 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1830 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1832 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1835 $$ = code_append($$, $4.c);
1836 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1838 $$ = code_append($$, $6);
1840 myjmp = $$ = abc_jump($$, 0);
1842 myif->branch = $$ = abc_nop($$);
1844 $$ = code_append($$, $7);
1845 myjmp->branch = $$ = abc_nop($$);
1851 FOR_INIT : {$$=code_new();}
1852 FOR_INIT : VARIABLE_DECLARATION
1853 FOR_INIT : VOIDEXPRESSION
1855 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1856 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1857 $$=$2;new_variable($2,$3,1);
1859 FOR_IN_INIT : T_IDENTIFIER {
1863 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1864 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1866 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1867 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1869 $$ = code_append($$, $2);
1870 code_t*loopstart = $$ = abc_label($$);
1871 $$ = code_append($$, $4.c);
1872 code_t*myif = $$ = abc_iffalse($$, 0);
1873 $$ = code_append($$, $8);
1874 code_t*cont = $$ = abc_nop($$);
1875 $$ = code_append($$, $6);
1876 $$ = abc_jump($$, loopstart);
1877 code_t*out = $$ = abc_nop($$);
1878 breakjumpsto($$, $1.name, out);
1879 continuejumpsto($$, $1.name, cont);
1886 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1887 variable_t*var = find_variable($2);
1888 char*tmp1name = concat2($2, "__tmp1__");
1889 int it = new_variable(tmp1name, TYPE_INT, 0);
1890 char*tmp2name = concat2($2, "__array__");
1891 int array = new_variable(tmp1name, 0, 0);
1894 $$ = code_append($$, $4.c);
1895 $$ = abc_coerce_a($$);
1896 $$ = abc_setlocal($$, array);
1897 $$ = abc_pushbyte($$, 0);
1898 $$ = abc_setlocal($$, it);
1900 code_t*loopstart = $$ = abc_label($$);
1902 $$ = abc_hasnext2($$, array, it);
1903 code_t*myif = $$ = abc_iffalse($$, 0);
1904 $$ = abc_getlocal($$, array);
1905 $$ = abc_getlocal($$, it);
1907 $$ = abc_nextname($$);
1909 $$ = abc_nextvalue($$);
1910 $$ = converttype($$, 0, var->type);
1911 $$ = abc_setlocal($$, var->index);
1913 $$ = code_append($$, $6);
1914 $$ = abc_jump($$, loopstart);
1916 code_t*out = $$ = abc_nop($$);
1917 breakjumpsto($$, $1.name, out);
1918 continuejumpsto($$, $1.name, loopstart);
1929 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1933 code_t*myjmp = $$ = abc_jump($$, 0);
1934 code_t*loopstart = $$ = abc_label($$);
1935 $$ = code_append($$, $6);
1936 code_t*cont = $$ = abc_nop($$);
1937 myjmp->branch = cont;
1938 $$ = code_append($$, $4.c);
1939 $$ = abc_iftrue($$, loopstart);
1940 code_t*out = $$ = abc_nop($$);
1941 breakjumpsto($$, $1, out);
1942 continuejumpsto($$, $1, cont);
1948 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1950 code_t*loopstart = $$ = abc_label($$);
1951 $$ = code_append($$, $3);
1952 code_t*cont = $$ = abc_nop($$);
1953 $$ = code_append($$, $6.c);
1954 $$ = abc_iftrue($$, loopstart);
1955 code_t*out = $$ = abc_nop($$);
1956 breakjumpsto($$, $1, out);
1957 continuejumpsto($$, $1, cont);
1963 BREAK : "break" %prec prec_none {
1964 $$ = abc___break__(0, "");
1966 BREAK : "break" T_IDENTIFIER {
1967 $$ = abc___break__(0, $2);
1969 CONTINUE : "continue" %prec prec_none {
1970 $$ = abc___continue__(0, "");
1972 CONTINUE : "continue" T_IDENTIFIER {
1973 $$ = abc___continue__(0, $2);
1976 MAYBE_CASE_LIST : {$$=0;}
1977 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1978 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
1979 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1980 CASE_LIST: CASE {$$=$1;}
1981 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
1983 CASE: "case" E ':' MAYBECODE {
1985 $$ = code_append($$, $2.c);
1986 code_t*j = $$ = abc_ifne($$, 0);
1987 $$ = code_append($$, $4);
1988 if($$->opcode != OPCODE___BREAK__) {
1989 $$ = abc___fallthrough__($$, "");
1991 code_t*e = $$ = abc_nop($$);
1994 DEFAULT: "default" ':' MAYBECODE {
1997 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1999 $$ = code_append($$, $7);
2000 code_t*out = $$ = abc_pop($$);
2001 breakjumpsto($$, $1, out);
2003 code_t*c = $$,*lastblock=0;
2005 if(c->opcode == OPCODE_IFNE) {
2006 if(!c->next) syntaxerror("internal error in fallthrough handling");
2008 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2010 c->opcode = OPCODE_JUMP;
2011 c->branch = lastblock;
2013 /* fall through end of switch */
2014 c->opcode = OPCODE_NOP;
2024 /* ------------ try / catch /finally ---------------- */
2026 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
2028 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2029 multiname_t name = {QNAME, &name_ns, 0, $3};
2031 NEW(abc_exception_t, e)
2032 e->exc_type = sig2mname($4);
2033 e->var_name = multiname_clone(&name);
2037 int i = find_variable_safe($3)->index;
2038 e->target = c = abc_nop(0);
2039 c = abc_setlocal(c, i);
2040 c = code_append(c, $8);
2046 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
2052 NEW(abc_exception_t, e)
2053 e->exc_type = 0; //all exceptions
2054 e->var_name = 0; //no name
2057 e->to = code_append(e->to, $4);
2063 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2064 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2065 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2066 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2070 list_append($$.l,$2);
2071 $$.finally = $2->to;$2->to=0;
2074 CATCH_FINALLY_LIST: FINALLY {
2078 list_append($$.l,$1);
2079 $$.finally = $1->to;$1->to=0;
2083 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
2084 code_t*out = abc_nop(0);
2086 code_t*start = abc_nop(0);
2087 $$ = code_append(start, $4);
2088 if(!is_break_or_jump($4)) {
2089 $$ = abc_jump($$, out);
2091 code_t*end = $$ = abc_nop($$);
2095 tmp = new_variable("__finally__", 0, 0);
2097 abc_exception_list_t*l = $6.l;
2100 abc_exception_t*e = l->abc_exception;
2102 $$ = code_append($$, e->target);
2103 $$ = abc_jump($$, out);
2105 parserassert((ptroff_t)$6.finally);
2107 e->target = $$ = abc_nop($$);
2108 $$ = abc___rethrow__($$);
2116 $$ = code_append($$, out);
2118 $$ = insert_finally($$, $6.finally, tmp);
2120 list_concat(state->method->exceptions, $6.l);
2126 /* ------------ throw ------------------------------- */
2128 THROW : "throw" EXPRESSION {
2132 THROW : "throw" %prec prec_none {
2133 if(!state->exception_name)
2134 syntaxerror("re-throw only possible within a catch block");
2135 variable_t*v = find_variable(state->exception_name);
2137 $$=abc_getlocal($$, v->index);
2141 /* ------------ with -------------------------------- */
2143 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
2145 $$ = abc_pushscope($$);
2146 $$ = code_append($$, $5);
2147 $$ = abc_popscope($$);
2150 /* ------------ packages and imports ---------------- */
2152 X_IDENTIFIER: T_IDENTIFIER
2153 | "package" {PASS12 $$="package";}
2155 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2156 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2158 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2159 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2160 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2161 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2163 IMPORT : "import" PACKAGEANDCLASS {
2165 if(!registry_find($2->package, $2->name)) {
2166 as3_schedule_class($2->package, $2->name);
2172 syntaxerror("Couldn't import class\n");
2173 state_has_imports();
2174 dict_put(state->imports, c->name, c);
2177 IMPORT : "import" PACKAGE '.' '*' {
2179 if(strncmp("flash.", $2, 6)) {
2180 as3_schedule_package($2);
2186 state_has_imports();
2187 list_append(state->wildcard_imports, i);
2191 /* ------------ classes and interfaces (header) -------------- */
2193 MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
2194 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2195 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2196 MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
2198 MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
2199 | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
2200 | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
2201 | KW_STATIC {PASS12 $$=FLAG_STATIC;}
2202 | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
2203 | KW_FINAL {PASS12 $$=FLAG_FINAL;}
2204 | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
2205 | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
2206 | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
2207 | T_NAMESPACE {PASS12 $$=FLAG_NAMESPACE;}
2209 EXTENDS : {$$=registry_getobjectclass();}
2210 EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
2212 EXTENDS_LIST : {PASS12 $$=list_new();}
2213 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2215 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2216 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2218 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2219 EXTENDS IMPLEMENTS_LIST
2220 '{' {PASS12 startclass($1,$3,$4,$5);}
2222 '}' {PASS12 endclass();$$=0;}
2224 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2226 '{' {PASS12 startclass($1|FLAG_INTERFACE,$3,0,$4);}
2227 MAYBE_INTERFACE_BODY
2228 '}' {PASS12 endclass();$$=0;}
2230 /* ------------ classes and interfaces (body) -------------- */
2233 MAYBE_CLASS_BODY : CLASS_BODY
2234 CLASS_BODY : CLASS_BODY_ITEM
2235 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2236 CLASS_BODY_ITEM : ';'
2237 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}'
2238 CLASS_BODY_ITEM : SLOT_DECLARATION
2239 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2241 CLASS_BODY_ITEM : CODE_STATEMENT {
2242 code_t*c = state->cls->static_init;
2243 c = code_append(c, $1);
2244 state->cls->static_init = c;
2247 MAYBE_INTERFACE_BODY :
2248 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2249 INTERFACE_BODY : IDECLARATION
2250 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2252 IDECLARATION : "var" T_IDENTIFIER {
2253 syntaxerror("variable declarations not allowed in interfaces");
2255 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2258 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2259 syntaxerror("invalid method modifiers: interface methods always need to be public");
2261 startfunction(0,$1,$3,$4,&$6,$8);
2262 endfunction(0,$1,$3,$4,&$6,$8, 0);
2263 list_deep_free($6.list);
2266 /* ------------ classes and interfaces (body, slots ) ------- */
2268 VARCONST: "var" | "const"
2270 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
2272 U8 access = flags2access($1);
2274 varinfo_t* info = 0;
2276 memberinfo_t*i = registry_findmember(state->cls->info, $3, 1);
2278 check_override(i, flags);
2281 info = varinfo_register_onclass(state->cls->info, access, $3);
2283 slotinfo_t*i = registry_find(state->package, $3);
2285 syntaxerror("package %s already contains '%s'", state->package, $3);
2287 info = varinfo_register_global(access, state->package, $3);
2291 info->flags = flags;
2294 namespace_t mname_ns = {access, ""};
2295 multiname_t mname = {QNAME, &mname_ns, 0, $3};
2297 trait_list_t**traits;
2301 mname_ns.name = state->package;
2302 traits = &global->init->traits;
2303 code = &global->init->method->body->code;
2304 } else if(flags&FLAG_STATIC) {
2306 traits = &state->cls->abc->static_traits;
2307 code = &state->cls->static_init;
2309 // instance variable
2310 traits = &state->cls->abc->traits;
2311 code = &state->cls->init;
2317 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2319 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2321 info->slot = t->slot_id;
2323 /* initalization code (if needed) */
2325 if($5.c && !is_pushundefined($5.c)) {
2326 c = abc_getlocal_0(c);
2327 c = code_append(c, $5.c);
2328 c = converttype(c, $5.t, $4);
2329 c = abc_setslot(c, t->slot_id);
2332 *code = code_append(*code, c);
2335 t->kind= TRAIT_CONST;
2341 /* ------------ constants -------------------------------------- */
2343 MAYBESTATICCONSTANT: {$$=0;}
2344 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2346 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2347 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2348 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2349 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2350 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2351 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2352 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2353 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2354 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2355 STATICCONSTANT : T_IDENTIFIER {
2357 as3_warning("Couldn't resolve %s", $1);
2358 $$ = constant_new_null($1);
2361 /* ------------ classes and interfaces (body, functions) ------- */
2363 // non-vararg version
2366 memset(&$$,0,sizeof($$));
2368 MAYBE_PARAM_LIST: PARAM_LIST {
2374 MAYBE_PARAM_LIST: "..." PARAM {
2376 memset(&$$,0,sizeof($$));
2378 list_append($$.list, $2);
2380 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2384 list_append($$.list, $4);
2388 PARAM_LIST: PARAM_LIST ',' PARAM {
2391 list_append($$.list, $3);
2395 memset(&$$,0,sizeof($$));
2396 list_append($$.list, $1);
2399 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2402 $$ = malloc(sizeof(param_t));
2407 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2410 $$ = malloc(sizeof(param_t));
2412 $$->type = TYPE_ANY;
2415 GETSET : "get" {$$=$1;}
2419 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2420 MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}'
2422 PASS1 old_state();list_deep_free($6.list);
2424 if(!state->method->info) syntaxerror("internal error");
2426 code_t*c = method_header();
2427 c = wrap_function(c, 0, $11);
2429 endfunction(0,$1,$3,$4,&$6,$8,c);
2430 list_deep_free($6.list);
2434 MAYBE_IDENTIFIER: T_IDENTIFIER
2435 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2436 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2437 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2439 PASS1 old_state();list_deep_free($4.list);
2441 methodinfo_t*f = state->method->info;
2442 if(!f) syntaxerror("internal error");
2444 code_t*c = method_header();
2445 c = wrap_function(c, 0, $9);
2447 int index = state->method->var_index;
2448 endfunction(0,0,0,$2,&$4,$6,c);
2449 list_deep_free($4.list);
2451 $$.c = abc_getlocal(0, index);
2452 $$.t = TYPE_FUNCTION(f);
2456 /* ------------- package + class ids --------------- */
2458 CLASS: T_IDENTIFIER {
2461 /* try current package */
2462 slotinfo_t*s = find_class($1);
2463 if(!s) syntaxerror("Could not find class/method %s\n", $1);
2464 $$ = (classinfo_t*)s;
2467 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2468 PASS1 static classinfo_t c;
2469 memset(&c, 0, sizeof(c));
2474 slotinfo_t*s = registry_find($1, $3);
2475 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2477 $$ = (classinfo_t*)s;
2480 CLASS_SPEC: PACKAGEANDCLASS
2483 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2484 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2486 TYPE : CLASS_SPEC {$$=$1;}
2487 | '*' {$$=registry_getanytype();}
2488 | "void" {$$=registry_getanytype();}
2490 | "String" {$$=registry_getstringclass();}
2491 | "int" {$$=registry_getintclass();}
2492 | "uint" {$$=registry_getuintclass();}
2493 | "Boolean" {$$=registry_getbooleanclass();}
2494 | "Number" {$$=registry_getnumberclass();}
2497 MAYBETYPE: ':' TYPE {$$=$2;}
2500 /* ----------function calls, delete, constructor calls ------ */
2502 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2503 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2505 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2506 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2507 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2509 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2513 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
2514 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
2516 $$.cc = code_append($1.cc, $2.c);
2520 NEW : "new" E XX MAYBE_PARAM_VALUES {
2522 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2524 code_t*paramcode = $4.cc;
2525 if($$.c->opcode == OPCODE_GETPROPERTY) {
2526 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2527 $$.c = code_cutlast($$.c);
2528 $$.c = code_append($$.c, paramcode);
2529 $$.c = abc_constructprop2($$.c, name, $4.len);
2530 multiname_destroy(name);
2531 } else if($$.c->opcode == OPCODE_GETSLOT) {
2532 int slot = (int)(ptroff_t)$$.c->data[0];
2533 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2534 multiname_t*name = t->name;
2535 $$.c = code_cutlast($$.c);
2536 $$.c = code_append($$.c, paramcode);
2537 $$.c = abc_constructprop2($$.c, name, $4.len);
2539 $$.c = code_append($$.c, paramcode);
2540 $$.c = abc_construct($$.c, $4.len);
2544 if(TYPE_IS_CLASS($2.t) && $2.t->data) {
2547 $$.c = abc_coerce_a($$.c);
2552 /* TODO: use abc_call (for calling local variables),
2553 abc_callstatic (for calling own methods)
2556 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2559 if($$.c->opcode == OPCODE_COERCE_A) {
2560 $$.c = code_cutlast($$.c);
2562 code_t*paramcode = $3.cc;
2565 if($$.c->opcode == OPCODE_GETPROPERTY) {
2566 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2567 $$.c = code_cutlast($$.c);
2568 $$.c = code_append($$.c, paramcode);
2569 $$.c = abc_callproperty2($$.c, name, $3.len);
2570 multiname_destroy(name);
2571 } else if($$.c->opcode == OPCODE_GETSLOT) {
2572 int slot = (int)(ptroff_t)$$.c->data[0];
2573 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2574 if(t->kind!=TRAIT_METHOD) {
2575 //ok: flash allows to assign closures to members.
2577 multiname_t*name = t->name;
2578 $$.c = code_cutlast($$.c);
2579 $$.c = code_append($$.c, paramcode);
2580 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2581 $$.c = abc_callproperty2($$.c, name, $3.len);
2582 } else if($$.c->opcode == OPCODE_GETSUPER) {
2583 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2584 $$.c = code_cutlast($$.c);
2585 $$.c = code_append($$.c, paramcode);
2586 $$.c = abc_callsuper2($$.c, name, $3.len);
2587 multiname_destroy(name);
2589 $$.c = abc_getglobalscope($$.c);
2590 $$.c = code_append($$.c, paramcode);
2591 $$.c = abc_call($$.c, $3.len);
2594 if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
2595 $$.t = ((methodinfo_t*)($1.t->data))->return_type;
2597 $$.c = abc_coerce_a($$.c);
2602 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2603 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2604 if(!state->method) syntaxerror("super() not allowed outside of a function");
2605 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2608 $$.c = abc_getlocal_0($$.c);
2610 $$.c = code_append($$.c, $3.cc);
2612 this is dependent on the control path, check this somewhere else
2613 if(state->method->has_super)
2614 syntaxerror("constructor may call super() only once");
2616 state->method->has_super = 1;
2618 $$.c = abc_constructsuper($$.c, $3.len);
2619 $$.c = abc_pushundefined($$.c);
2623 DELETE: "delete" E {
2625 if($$.c->opcode == OPCODE_COERCE_A) {
2626 $$.c = code_cutlast($$.c);
2628 multiname_t*name = 0;
2629 if($$.c->opcode == OPCODE_GETPROPERTY) {
2630 $$.c->opcode = OPCODE_DELETEPROPERTY;
2631 } else if($$.c->opcode == OPCODE_GETSLOT) {
2632 int slot = (int)(ptroff_t)$$.c->data[0];
2633 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2634 $$.c = code_cutlast($$.c);
2635 $$.c = abc_deleteproperty2($$.c, name);
2637 $$.c = abc_getlocal_0($$.c);
2638 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2639 $$.c = abc_deleteproperty2($$.c, &m);
2641 $$.t = TYPE_BOOLEAN;
2644 RETURN: "return" %prec prec_none {
2645 $$ = abc_returnvoid(0);
2647 RETURN: "return" EXPRESSION {
2649 $$ = abc_returnvalue($$);
2652 // ----------------------- expression types -------------------------------------
2654 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2655 EXPRESSION : E %prec below_minus {$$ = $1;}
2656 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2658 $$.c = cut_last_push($$.c);
2659 $$.c = code_append($$.c,$3.c);
2662 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2663 $$=cut_last_push($1.c);
2666 // ----------------------- expression evaluation -------------------------------------
2668 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2669 //V : CONSTANT {$$ = 0;}
2671 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2672 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2673 //V : NEW {$$ = $1.c;}
2675 //V : DELETE {$$ = $1.c;}
2676 E : DELETE {$$ = $1;}
2682 namespace_t ns = {ACCESS_PACKAGE, ""};
2683 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2685 $$.c = abc_getlex2($$.c, &m);
2686 $$.c = abc_pushstring($$.c, $1.pattern);
2687 $$.c = abc_construct($$.c, 1);
2689 $$.c = abc_getlex2($$.c, &m);
2690 $$.c = abc_pushstring($$.c, $1.pattern);
2691 $$.c = abc_pushstring($$.c, $1.options);
2692 $$.c = abc_construct($$.c, 2);
2697 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2698 //MULTINAME(m, registry_getintclass());
2699 //$$.c = abc_coerce2($$.c, &m); // FIXME
2702 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2705 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2708 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2711 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2714 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
2717 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2720 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2721 $$.t = TYPE_BOOLEAN;
2723 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2724 $$.t = TYPE_BOOLEAN;
2726 CONSTANT : "null" {$$.c = abc_pushnull(0);
2730 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2731 $$.t = TYPE_BOOLEAN;
2733 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2734 $$.t = TYPE_BOOLEAN;
2736 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2737 $$.t = TYPE_BOOLEAN;
2739 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2740 $$.t = TYPE_BOOLEAN;
2742 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2743 $$.t = TYPE_BOOLEAN;
2745 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2746 $$.t = TYPE_BOOLEAN;
2748 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2749 $$.t = TYPE_BOOLEAN;
2751 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2752 $$.t = TYPE_BOOLEAN;
2755 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2757 $$.c = converttype($$.c, $1.t, $$.t);
2758 $$.c = abc_dup($$.c);
2759 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2760 $$.c = cut_last_push($$.c);
2761 $$.c = code_append($$.c,$3.c);
2762 $$.c = converttype($$.c, $3.t, $$.t);
2763 code_t*label = $$.c = abc_label($$.c);
2764 jmp->branch = label;
2767 $$.t = join_types($1.t, $3.t, 'A');
2768 /*printf("%08x:\n",$1.t);
2769 code_dump($1.c, 0, 0, "", stdout);
2770 printf("%08x:\n",$3.t);
2771 code_dump($3.c, 0, 0, "", stdout);
2772 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2774 $$.c = converttype($$.c, $1.t, $$.t);
2775 $$.c = abc_dup($$.c);
2776 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2777 $$.c = cut_last_push($$.c);
2778 $$.c = code_append($$.c,$3.c);
2779 $$.c = converttype($$.c, $3.t, $$.t);
2780 code_t*label = $$.c = abc_label($$.c);
2781 jmp->branch = label;
2784 E : '!' E {$$.c=$2.c;
2785 $$.c = abc_not($$.c);
2786 $$.t = TYPE_BOOLEAN;
2789 E : '~' E {$$.c=$2.c;
2790 $$.c = abc_bitnot($$.c);
2794 E : E '&' E {$$.c = code_append($1.c,$3.c);
2795 $$.c = abc_bitand($$.c);
2799 E : E '^' E {$$.c = code_append($1.c,$3.c);
2800 $$.c = abc_bitxor($$.c);
2804 E : E '|' E {$$.c = code_append($1.c,$3.c);
2805 $$.c = abc_bitor($$.c);
2809 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2810 $$.c = abc_rshift($$.c);
2813 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2814 $$.c = abc_urshift($$.c);
2817 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2818 $$.c = abc_lshift($$.c);
2822 E : E '/' E {$$.c = code_append($1.c,$3.c);
2823 $$.c = abc_divide($$.c);
2826 E : E '%' E {$$.c = code_append($1.c,$3.c);
2827 $$.c = abc_modulo($$.c);
2830 E : E '+' E {$$.c = code_append($1.c,$3.c);
2831 if(BOTH_INT($1.t, $3.t)) {
2832 $$.c = abc_add_i($$.c);
2835 $$.c = abc_add($$.c);
2836 $$.t = join_types($1.t,$3.t,'+');
2839 E : E '-' E {$$.c = code_append($1.c,$3.c);
2840 if(BOTH_INT($1.t,$3.t)) {
2841 $$.c = abc_subtract_i($$.c);
2844 $$.c = abc_subtract($$.c);
2848 E : E '*' E {$$.c = code_append($1.c,$3.c);
2849 if(BOTH_INT($1.t,$3.t)) {
2850 $$.c = abc_multiply_i($$.c);
2853 $$.c = abc_multiply($$.c);
2858 E : E "in" E {$$.c = code_append($1.c,$3.c);
2859 $$.c = abc_in($$.c);
2860 $$.t = TYPE_BOOLEAN;
2863 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2864 if(use_astype && TYPE_IS_CLASS($3.t) && $3.t->data) {
2865 MULTINAME(m, (classinfo_t*)($3.t->data));
2866 $$.c = abc_astype2($1.c, &m);
2869 $$.c = code_append($1.c, $3.c);
2870 $$.c = abc_astypelate($$.c);
2875 E : E "instanceof" E
2876 {$$.c = code_append($1.c, $3.c);
2877 $$.c = abc_instanceof($$.c);
2878 $$.t = TYPE_BOOLEAN;
2881 E : E "is" E {$$.c = code_append($1.c, $3.c);
2882 $$.c = abc_istypelate($$.c);
2883 $$.t = TYPE_BOOLEAN;
2886 E : "typeof" '(' E ')' {
2888 $$.c = abc_typeof($$.c);
2893 $$.c = cut_last_push($2.c);
2894 $$.c = abc_pushundefined($$.c);
2898 E : "void" { $$.c = abc_pushundefined(0);
2902 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2907 $$.c=abc_negate_i($$.c);
2910 $$.c=abc_negate($$.c);
2917 $$.c = code_append($$.c, $3.c);
2919 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2920 $$.c = abc_getproperty2($$.c, &m);
2921 $$.t = 0; // array elements have unknown type
2924 E : '[' MAYBE_EXPRESSION_LIST ']' {
2926 $$.c = code_append($$.c, $2.cc);
2927 $$.c = abc_newarray($$.c, $2.len);
2928 $$.t = registry_getarrayclass();
2931 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2932 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
2934 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2936 $$.cc = code_append($$.cc, $1.c);
2937 $$.cc = code_append($$.cc, $3.c);
2940 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2943 $$.cc = code_append($$.cc, $3.c);
2944 $$.cc = code_append($$.cc, $5.c);
2949 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2951 $$.c = code_append($$.c, $2.cc);
2952 $$.c = abc_newobject($$.c, $2.len/2);
2953 $$.t = registry_getobjectclass();
2958 if(BOTH_INT($1.t,$3.t)) {
2959 c=abc_multiply_i(c);
2963 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2964 $$.c = toreadwrite($1.c, c, 0, 0);
2969 code_t*c = abc_modulo($3.c);
2970 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2971 $$.c = toreadwrite($1.c, c, 0, 0);
2975 code_t*c = abc_lshift($3.c);
2976 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2977 $$.c = toreadwrite($1.c, c, 0, 0);
2981 code_t*c = abc_rshift($3.c);
2982 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2983 $$.c = toreadwrite($1.c, c, 0, 0);
2987 code_t*c = abc_urshift($3.c);
2988 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2989 $$.c = toreadwrite($1.c, c, 0, 0);
2993 code_t*c = abc_divide($3.c);
2994 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2995 $$.c = toreadwrite($1.c, c, 0, 0);
2999 code_t*c = abc_bitor($3.c);
3000 c=converttype(c, TYPE_INT, $1.t);
3001 $$.c = toreadwrite($1.c, c, 0, 0);
3007 if(TYPE_IS_INT($1.t)) {
3011 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
3014 $$.c = toreadwrite($1.c, c, 0, 0);
3017 E : E "-=" E { code_t*c = $3.c;
3018 if(TYPE_IS_INT($1.t)) {
3019 c=abc_subtract_i(c);
3022 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
3025 $$.c = toreadwrite($1.c, c, 0, 0);
3028 E : E '=' E { code_t*c = 0;
3029 c = code_append(c, $3.c);
3030 c = converttype(c, $3.t, $1.t);
3031 $$.c = toreadwrite($1.c, c, 1, 0);
3035 E : E '?' E ':' E %prec below_assignment {
3036 $$.t = join_types($3.t,$5.t,'?');
3038 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
3039 $$.c = code_append($$.c, $3.c);
3040 $$.c = converttype($$.c, $3.t, $$.t);
3041 code_t*j2 = $$.c = abc_jump($$.c, 0);
3042 $$.c = j1->branch = abc_label($$.c);
3043 $$.c = code_append($$.c, $5.c);
3044 $$.c = converttype($$.c, $3.t, $$.t);
3045 $$.c = j2->branch = abc_label($$.c);
3048 E : E "++" { code_t*c = 0;
3049 classinfo_t*type = $1.t;
3050 if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
3051 int nr = getlocalnr($1.c);
3052 code_free($1.c);$1.c=0;
3053 if(TYPE_IS_INT($1.t)) {
3054 $$.c = abc_getlocal(0, nr);
3055 $$.c = abc_inclocal_i($$.c, nr);
3056 } else if(TYPE_IS_NUMBER($1.t)) {
3057 $$.c = abc_getlocal(0, nr);
3058 $$.c = abc_inclocal($$.c, nr);
3059 } else syntaxerror("internal error");
3061 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3062 c=abc_increment_i(c);
3068 c=converttype(c, type, $1.t);
3069 $$.c = toreadwrite($1.c, c, 0, 1);
3074 // TODO: use inclocal, like with ++
3075 E : E "--" { code_t*c = 0;
3076 classinfo_t*type = $1.t;
3077 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3078 c=abc_decrement_i(c);
3084 c=converttype(c, type, $1.t);
3085 $$.c = toreadwrite($1.c, c, 0, 1);
3089 E : "++" %prec plusplus_prefix E { code_t*c = 0;
3090 classinfo_t*type = $2.t;
3091 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3092 c=abc_increment_i(c);
3098 c=converttype(c, type, $2.t);
3099 $$.c = toreadwrite($2.c, c, 0, 0);
3103 E : "--" %prec minusminus_prefix E { code_t*c = 0;
3104 classinfo_t*type = $2.t;
3105 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3106 c=abc_decrement_i(c);
3112 c=converttype(c, type, $2.t);
3113 $$.c = toreadwrite($2.c, c, 0, 0);
3117 E : "super" '.' T_IDENTIFIER
3118 { if(!state->cls->info)
3119 syntaxerror("super keyword not allowed outside a class");
3120 classinfo_t*t = state->cls->info->superclass;
3121 if(!t) t = TYPE_OBJECT;
3123 memberinfo_t*f = registry_findmember(t, $3, 1);
3124 namespace_t ns = {f->access, ""};
3125 MEMBER_MULTINAME(m, f, $3);
3127 $$.c = abc_getlocal_0($$.c);
3128 $$.c = abc_getsuper2($$.c, &m);
3129 $$.t = slotinfo_gettype((slotinfo_t*)f);
3132 E : '@' T_IDENTIFIER {
3134 $$.c = abc_pushundefined(0);
3136 as3_warning("ignored @ operator");
3139 E : E '.' '@' T_IDENTIFIER {
3140 // child attribute TODO
3141 $$.c = abc_pushundefined(0);
3143 as3_warning("ignored .@ operator");
3146 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3147 // namespace declaration TODO
3148 $$.c = abc_pushundefined(0);
3150 as3_warning("ignored :: operator");
3153 E : E ".." T_IDENTIFIER {
3155 $$.c = abc_pushundefined(0);
3157 as3_warning("ignored .. operator");
3160 E : E '.' '(' E ')' {
3162 $$.c = abc_pushundefined(0);
3164 as3_warning("ignored .() operator");
3167 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
3171 E : E '.' T_IDENTIFIER
3173 classinfo_t*t = $1.t;
3175 if(TYPE_IS_CLASS(t) && t->data) {
3180 memberinfo_t*f = registry_findmember(t, $3, 1);
3182 if(f && !is_static != !(f->flags&FLAG_STATIC))
3184 if(f && f->slot && !noslot) {
3185 $$.c = abc_getslot($$.c, f->slot);
3187 MEMBER_MULTINAME(m, f, $3);
3188 $$.c = abc_getproperty2($$.c, &m);
3190 /* determine type */
3191 $$.t = slotinfo_gettype((slotinfo_t*)f);
3193 $$.c = abc_coerce_a($$.c);
3195 /* when resolving a property on an unknown type, we do know the
3196 name of the property (and don't seem to need the package), but
3197 we need to make avm2 try out all access modes */
3198 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3199 $$.c = abc_getproperty2($$.c, &m);
3200 $$.c = abc_coerce_a($$.c);
3201 $$.t = registry_getanytype();
3205 VAR_READ : T_IDENTIFIER {
3212 /* look at variables */
3213 if((v = find_variable($1))) {
3214 // $1 is a local variable
3215 $$.c = abc_getlocal($$.c, v->index);
3220 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3222 /* look at current class' members */
3223 if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
3224 (f->flags&FLAG_STATIC) >= i_am_static) {
3225 // $1 is a function in this class
3226 int var_is_static = (f->flags&FLAG_STATIC);
3228 if(f->kind == INFOTYPE_METHOD) {
3229 $$.t = TYPE_FUNCTION(f);
3233 if(var_is_static && !i_am_static) {
3234 /* access to a static member from a non-static location.
3235 do this via findpropstrict:
3236 there doesn't seem to be any non-lookup way to access
3237 static properties of a class */
3238 state->method->late_binding = 1;
3240 namespace_t ns = {f->access, ""};
3241 multiname_t m = {QNAME, &ns, 0, $1};
3242 $$.c = abc_findpropstrict2($$.c, &m);
3243 $$.c = abc_getproperty2($$.c, &m);
3245 } else if(f->slot>0) {
3246 $$.c = abc_getlocal_0($$.c);
3247 $$.c = abc_getslot($$.c, f->slot);
3250 namespace_t ns = {f->access, ""};
3251 multiname_t m = {QNAME, &ns, 0, $1};
3252 $$.c = abc_getlocal_0($$.c);
3253 $$.c = abc_getproperty2($$.c, &m);
3258 /* look at actual classes, in the current package and imported */
3259 if((a = find_class($1))) {
3260 if(a->access == ACCESS_PACKAGEINTERNAL &&
3261 strcmp(a->package, state->package) &&
3262 strcmp(a->package, internal_filename_package)
3264 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
3265 infotypename(a),$1, a->package, state->package);
3267 if(a->kind != INFOTYPE_CLASS) {
3269 $$.c = abc_findpropstrict2($$.c, &m);
3270 $$.c = abc_getproperty2($$.c, &m);
3271 if(a->kind == INFOTYPE_METHOD) {
3272 methodinfo_t*f = (methodinfo_t*)a;
3273 $$.t = TYPE_FUNCTION(f);
3275 varinfo_t*v = (varinfo_t*)a;
3279 classinfo_t*c = (classinfo_t*)a;
3281 $$.c = abc_getglobalscope($$.c);
3282 $$.c = abc_getslot($$.c, c->slot);
3285 $$.c = abc_getlex2($$.c, &m);
3287 $$.t = TYPE_CLASS(c);
3292 /* unknown object, let the avm2 resolve it */
3294 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3295 state->method->late_binding = 1;
3297 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3300 $$.c = abc_findpropstrict2($$.c, &m);
3301 $$.c = abc_getproperty2($$.c, &m);
3305 // ----------------- namespaces -------------------------------------------------
3307 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
3308 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
3309 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
3311 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {
3313 tokenizer_register_namespace($3);