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_DICTSTART "{ (dictionary)"
143 %token<token> T_EQEQ "=="
144 %token<token> T_EQEQEQ "==="
145 %token<token> T_NE "!="
146 %token<token> T_NEE "!=="
147 %token<token> T_LE "<="
148 %token<token> T_GE ">="
149 %token<token> T_ORBY "|="
150 %token<token> T_DIVBY "/="
151 %token<token> T_MODBY "%="
152 %token<token> T_MULBY "*="
153 %token<token> T_PLUSBY "+="
154 %token<token> T_MINUSBY "-="
155 %token<token> T_XORBY "^="
156 %token<token> T_SHRBY ">>="
157 %token<token> T_SHLBY "<<="
158 %token<token> T_USHRBY ">>>="
159 %token<token> T_OROR "||"
160 %token<token> T_ANDAND "&&"
161 %token<token> T_COLONCOLON "::"
162 %token<token> T_MINUSMINUS "--"
163 %token<token> T_PLUSPLUS "++"
164 %token<token> T_DOTDOT ".."
165 %token<token> T_DOTDOTDOT "..."
166 %token<token> T_SHL "<<"
167 %token<token> T_USHR ">>>"
168 %token<token> T_SHR ">>"
170 %type <for_start> FOR_START
171 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
172 %type <token> VARCONST
174 %type <code> CODEPIECE CODE_STATEMENT
175 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
176 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
177 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
178 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
179 %type <exception> CATCH FINALLY
180 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
181 %type <code> CLASS_DECLARATION
182 %type <code> NAMESPACE_DECLARATION
183 %type <code> INTERFACE_DECLARATION
184 %type <code> VOIDEXPRESSION
185 %type <value> EXPRESSION NONCOMMAEXPRESSION
186 %type <value> MAYBEEXPRESSION
187 %type <value> E DELETE
188 %type <value> CONSTANT
189 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
190 %type <value> INNERFUNCTION
191 %type <code> USE_NAMESPACE
192 %type <code> FOR_INIT
194 %type <classinfo> MAYBETYPE
197 %type <params> PARAM_LIST
198 %type <params> MAYBE_PARAM_LIST
199 %type <flags> MAYBE_MODIFIERS
200 %type <flags> MODIFIER_LIST
201 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
202 %type <classinfo_list> IMPLEMENTS_LIST
203 %type <classinfo> EXTENDS
204 %type <classinfo_list> EXTENDS_LIST
205 %type <classinfo> CLASS PACKAGEANDCLASS CLASS_SPEC
206 %type <classinfo_list> CLASS_SPEC_LIST
207 %type <classinfo> TYPE
208 //%type <token> VARIABLE
209 %type <value> VAR_READ
211 //%type <token> T_IDENTIFIER
212 %type <token> MODIFIER
213 %type <value> FUNCTIONCALL
214 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
216 // precedence: from low to high
220 %left below_semicolon
223 %nonassoc below_assignment // for ?:, contrary to spec
224 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
231 %nonassoc "==" "!=" "===" "!=="
232 %nonassoc "is" "as" "in"
233 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
234 %left "<<" ">>" ">>>"
238 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
240 %nonassoc below_curly
244 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
247 %left above_identifier
251 // needed for "return" precedence:
252 %nonassoc T_STRING T_REGEXP
253 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
254 %nonassoc "false" "true" "null" "undefined" "super" "function"
261 static int a3_error(char*s)
263 syntaxerror("%s", s);
264 return 0; //make gcc happy
268 static char* concat2(const char* t1, const char* t2)
272 char*text = malloc(l1+l2+1);
273 memcpy(text , t1, l1);
274 memcpy(text+l1, t2, l2);
278 static char* concat3(const char* t1, const char* t2, const char* t3)
283 char*text = malloc(l1+l2+l3+1);
284 memcpy(text , t1, l1);
285 memcpy(text+l1, t2, l2);
286 memcpy(text+l1+l2, t3, l3);
291 typedef struct _import {
295 DECLARE_LIST(import);
297 DECLARE(methodstate);
298 DECLARE_LIST(methodstate);
300 typedef struct _classstate {
306 methodstate_t*static_init;
308 //code_t*static_init;
310 char has_constructor;
313 struct _methodstate {
324 int var_index; // for inner methods
327 abc_exception_list_t*exceptions;
329 methodstate_list_t*innerfunctions;
332 typedef struct _state {
337 import_list_t*wildcard_imports;
339 char has_own_imports;
340 char new_vars; // e.g. transition between two functions
343 methodstate_t*method;
350 typedef struct _global {
354 dict_t*file2token2info;
357 static global_t*global = 0;
358 static state_t* state = 0;
362 #define MULTINAME(m,x) \
366 registry_fill_multiname(&m, &m##_ns, (slotinfo_t*)(x));
368 #define MEMBER_MULTINAME(m,f,n) \
372 m##_ns.access = (f)->access; \
376 m.namespace_set = 0; \
379 m.type = MULTINAME; \
381 m.namespace_set = &nopackage_namespace_set; \
385 /* warning: list length of namespace set is undefined */
386 #define MULTINAME_LATE(m, access, package) \
387 namespace_t m##_ns = {access, package}; \
388 namespace_set_t m##_nsset; \
389 namespace_list_t m##_l;m##_l.next = 0; \
390 m##_nsset.namespaces = &m##_l; \
391 m##_nsset = m##_nsset; \
392 m##_l.namespace = &m##_ns; \
393 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
395 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
396 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
397 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
398 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
399 static namespace_list_t nl4 = {&ns4,0};
400 static namespace_list_t nl3 = {&ns3,&nl4};
401 static namespace_list_t nl2 = {&ns2,&nl3};
402 static namespace_list_t nl1 = {&ns1,&nl2};
403 static namespace_set_t nopackage_namespace_set = {&nl1};
405 static void new_state()
408 state_t*oldstate = state;
410 memcpy(s, state, sizeof(state_t)); //shallow copy
412 s->imports = dict_new();
416 state->has_own_imports = 0;
417 state->vars = dict_new();
418 state->old = oldstate;
420 static void state_has_imports()
422 state->wildcard_imports = list_clone(state->wildcard_imports);
423 state->imports = dict_clone(state->imports);
424 state->has_own_imports = 1;
427 static void state_destroy(state_t*state)
429 if(state->has_own_imports) {
430 list_free(state->wildcard_imports);
431 dict_destroy(state->imports);state->imports=0;
433 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
434 dict_destroy(state->imports);state->imports=0;
438 for(t=0;t<state->vars->hashsize;t++) {
439 dictentry_t*e =state->vars->slots[t];
441 free(e->data);e->data=0;
445 dict_destroy(state->vars);state->vars=0;
451 static void old_state()
453 if(!state || !state->old)
454 syntaxerror("invalid nesting");
455 state_t*leaving = state;
459 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
460 free(leaving->method);
463 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
468 state_destroy(leaving);
471 static code_t* method_header(methodstate_t*m);
472 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
473 static void function_initvars(methodstate_t*m, params_t*params, int flags);
476 static char* internal_filename_package = 0;
477 void initialize_file(char*filename)
480 syntaxerror("invalid call to initialize_file during parsing of another file");
483 state->package = internal_filename_package = strdup(filename);
485 global->token2info = dict_lookup(global->file2token2info,
486 current_filename // use long version
488 if(!global->token2info) {
489 global->token2info = dict_new2(&ptr_type);
490 dict_put(global->file2token2info, current_filename, global->token2info);
494 state->method = rfx_calloc(sizeof(methodstate_t));
495 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
497 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
498 function_initvars(state->method, 0, 0);
499 global->init = abc_initscript(global->file);
500 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
506 if(!state || state->level!=1) {
507 syntaxerror("unexpected end of file in pass %d", as3_pass);
511 code_t*header = method_header(state->method);
512 code_t*c = wrap_function(header, 0, global->init->method->body->code);
513 global->init->method->body->code = c;
514 free(state->method);state->method=0;
517 //free(state->package);state->package=0; // used in registry
518 state_destroy(state);state=0;
521 void initialize_parser()
523 global = rfx_calloc(sizeof(global_t));
524 global->file = abc_file_new();
525 global->file->flags &= ~ABCFILE_LAZY;
526 global->file2token2info = dict_new();
527 global->token2info = 0;
530 void* finish_parser()
532 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
534 global->token2info=0;
540 static void xx_scopetest()
542 /* findpropstrict doesn't just return a scope object- it
543 also makes it "active" somehow. Push local_0 on the
544 scope stack and read it back with findpropstrict, it'll
545 contain properties like "trace". Trying to find the same
546 property on a "vanilla" local_0 yields only a "undefined" */
547 //c = abc_findpropstrict(c, "[package]::trace");
549 /*c = abc_getlocal_0(c);
550 c = abc_findpropstrict(c, "[package]::trace");
552 c = abc_setlocal_1(c);
554 c = abc_pushbyte(c, 0);
555 c = abc_setlocal_2(c);
557 code_t*xx = c = abc_label(c);
558 c = abc_findpropstrict(c, "[package]::trace");
559 c = abc_pushstring(c, "prop:");
560 c = abc_hasnext2(c, 1, 2);
562 c = abc_setlocal_3(c);
563 c = abc_callpropvoid(c, "[package]::trace", 2);
564 c = abc_getlocal_3(c);
566 c = abc_iftrue(c,xx);*/
570 typedef struct _variable {
576 static variable_t* find_variable(char*name)
582 v = dict_lookup(s->vars, name);
592 static variable_t* find_variable_safe(char*name)
594 variable_t* v = find_variable(name);
596 syntaxerror("undefined variable: %s", name);
599 static char variable_exists(char*name)
601 return dict_lookup(state->vars, name)!=0;
603 code_t*defaultvalue(code_t*c, classinfo_t*type);
604 static int new_variable(const char*name, classinfo_t*type, char init)
607 v->index = state->method->variable_count;
611 dict_put(state->vars, name, v);
613 return state->method->variable_count++;
615 #define TEMPVARNAME "__as3_temp__"
616 static int gettempvar()
618 variable_t*v = find_variable(TEMPVARNAME);
621 return new_variable(TEMPVARNAME, 0, 0);
624 code_t* var_block(code_t*body)
630 for(t=0;t<state->vars->hashsize;t++) {
631 dictentry_t*e = state->vars->slots[t];
633 variable_t*v = (variable_t*)e->data;
634 if(v->type && v->init) {
635 c = defaultvalue(c, v->type);
636 c = abc_setlocal(c, v->index);
637 k = abc_kill(k, v->index);
647 if(x->opcode== OPCODE___BREAK__ ||
648 x->opcode== OPCODE___CONTINUE__) {
649 /* link kill code before break/continue */
650 code_t*e = code_dup(k);
651 code_t*s = code_start(e);
663 c = code_append(c, body);
664 c = code_append(c, k);
668 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
670 static void parsererror(const char*file, int line, const char*f)
672 syntaxerror("internal error in %s, %s:%d", f, file, line);
676 static code_t* method_header(methodstate_t*m)
679 if(m->late_binding && !m->inner) {
680 c = abc_getlocal_0(c);
681 c = abc_pushscope(c);
683 /*if(m->innerfunctions) {
684 c = abc_newactivation(c);
685 c = abc_pushscope(c);
687 methodstate_list_t*l = m->innerfunctions;
689 parserassert(l->methodstate->abc);
690 c = abc_newfunction(c, l->methodstate->abc);
691 c = abc_setlocal(c, l->methodstate->var_index);
692 free(l->methodstate);l->methodstate=0;
696 c = code_append(c, m->header);
699 if(m->is_constructor && !m->has_super) {
700 // call default constructor
701 c = abc_getlocal_0(c);
702 c = abc_constructsuper(c, 0);
704 list_free(m->innerfunctions);
705 m->innerfunctions = 0;
710 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
712 c = code_append(c, header);
713 c = code_append(c, var_block(body));
714 /* append return if necessary */
715 if(!c || (c->opcode != OPCODE_RETURNVOID &&
716 c->opcode != OPCODE_RETURNVALUE)) {
717 c = abc_returnvoid(c);
723 static void startpackage(char*name)
726 /*printf("entering package \"%s\"\n", name);*/
727 state->package = strdup(name);
729 static void endpackage()
731 /*printf("leaving package \"%s\"\n", state->package);*/
733 //used e.g. in classinfo_register:
734 //free(state->package);state->package=0;
739 #define FLAG_PUBLIC 256
740 #define FLAG_PROTECTED 512
741 #define FLAG_PRIVATE 1024
742 #define FLAG_PACKAGEINTERNAL 2048
743 #define FLAG_NAMESPACE 4096
745 static int flags2access(int flags)
748 if(flags&FLAG_PUBLIC) {
749 if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
750 syntaxerror("invalid combination of access levels");
751 access = ACCESS_PACKAGE;
752 } else if(flags&FLAG_PRIVATE) {
753 if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
754 syntaxerror("invalid combination of access levels");
755 access = ACCESS_PRIVATE;
756 } else if(flags&FLAG_PROTECTED) {
757 if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
758 syntaxerror("invalid combination of access levels");
759 access = ACCESS_PROTECTED;
761 access = ACCESS_PACKAGEINTERNAL;
766 static void function_initvars(methodstate_t*m, params_t*params, int flags)
769 new_variable("this", 0, 0);
770 else if(!m->is_global)
771 new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0);
773 new_variable("globalscope", 0, 0);
777 for(p=params->list;p;p=p->next) {
778 new_variable(p->param->name, p->param->type, 0);
782 methodstate_list_t*l = m->innerfunctions;
784 methodstate_t*m = l->methodstate;
785 m->var_index = new_variable(m->info->name, TYPE_FUNCTION(m->info), 0);
791 char*as3_globalclass=0;
792 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements)
795 syntaxerror("inner classes now allowed");
799 classinfo_list_t*mlist=0;
801 if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
802 syntaxerror("invalid modifier(s)");
804 if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
805 syntaxerror("public and internal not supported at the same time.");
807 /* create the class name, together with the proper attributes */
811 if(!(flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
812 access = ACCESS_PRIVATE; package = internal_filename_package;
813 } else if(!(flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
814 access = ACCESS_PACKAGEINTERNAL; package = state->package;
815 } else if(state->package!=internal_filename_package) {
816 access = ACCESS_PACKAGE; package = state->package;
818 syntaxerror("public classes only allowed inside a package");
822 state->cls = rfx_calloc(sizeof(classstate_t));
823 state->cls->init = rfx_calloc(sizeof(methodstate_t));
824 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
825 /* notice: we make no effort to initialize the top variable (local0) here,
826 even though it has special meaning. We just rely on the facat
827 that pass 1 won't do anything with variables */
829 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
831 /* set current method to constructor- all code within the class-level (except
832 static variable initializations) will be executed during construction time */
833 state->method = state->cls->init;
835 if(registry_find(package, classname)) {
836 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
838 /* build info struct */
839 int num_interfaces = (list_length(implements));
840 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
841 state->cls->info->flags |= flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
845 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
847 state->method = state->cls->init;
848 parserassert(state->cls && state->cls->info);
850 function_initvars(state->cls->init, 0, 0);
851 function_initvars(state->cls->static_init, 0, 0);
853 if(extends && (extends->flags & FLAG_FINAL))
854 syntaxerror("Can't extend final class '%s'", extends->name);
856 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
857 state->cls->info->superclass = extends?extends:TYPE_OBJECT;
859 classinfo_list_t*l = implements;
860 for(l=implements;l;l=l->next) {
861 if(!(l->classinfo->flags & FLAG_INTERFACE))
862 syntaxerror("'%s' is not an interface", l->classinfo->name);
863 state->cls->info->interfaces[pos++] = l->classinfo;
866 /* generate the abc code for this class */
867 MULTINAME(classname2,state->cls->info);
868 multiname_t*extends2 = sig2mname(extends);
870 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
871 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
872 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
873 if(state->cls->info->flags&FLAG_INTERFACE) {
874 abc_class_interface(state->cls->abc);
877 abc_class_protectedNS(state->cls->abc, classname);
879 for(mlist=implements;mlist;mlist=mlist->next) {
880 MULTINAME(m, mlist->classinfo);
881 abc_class_add_interface(state->cls->abc, &m);
884 /* write the construction code for this class to the global init
886 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
888 abc_method_body_t*m = global->init->method->body;
889 __ getglobalscope(m);
890 classinfo_t*s = extends;
895 //TODO: take a look at the current scope stack, maybe
896 // we can re-use something
901 multiname_t*s2 = sig2mname(s);
903 multiname_destroy(s2);
905 __ pushscope(m); count++;
906 m->code = m->code->prev->prev; // invert
908 /* continue appending after last op end */
909 while(m->code && m->code->next) m->code = m->code->next;
911 /* TODO: if this is one of *our* classes, we can also
912 do a getglobalscope/getslot <nr> (which references
913 the init function's slots) */
915 __ getlex2(m, extends2);
917 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
918 stack is not the superclass */
919 __ pushscope(m);count++;
922 /* notice: we get a verify error #1107 if the top element on the scope
923 stack is not the global object */
925 __ pushscope(m);count++;
927 __ newclass(m,state->cls->abc);
931 __ setslot(m, slotindex);
932 multiname_destroy(extends2);
934 /* flash.display.MovieClip handling */
936 if(!as3_globalclass && (flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
937 if(state->package && state->package[0]) {
938 as3_globalclass = concat3(state->package, ".", classname);
940 as3_globalclass = strdup(classname);
946 static void setstaticfunction(int x)
950 state->method = state->cls->static_init;
952 state->method = state->cls->init;
955 parserassert(state->method);
959 static void endclass()
962 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
964 c = abc_getlocal_0(c);
965 c = abc_constructsuper(c, 0);
966 state->cls->init->header = code_append(state->cls->init->header, c);
967 state->cls->has_constructor=1;
969 if(state->cls->init) {
970 if(state->cls->info->flags&FLAG_INTERFACE) {
971 if(state->cls->init->header)
972 syntaxerror("interface can not have class-level code");
974 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
975 code_t*c = method_header(state->cls->init);
976 m->body->code = wrap_function(c, 0, m->body->code);
979 if(state->cls->static_init) {
980 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
981 code_t*c = method_header(state->cls->static_init);
982 m->body->code = wrap_function(c, 0, m->body->code);
989 void check_code_for_break(code_t*c)
992 if(c->opcode == OPCODE___BREAK__) {
993 char*name = string_cstr(c->data[0]);
994 syntaxerror("Unresolved \"break %s\"", name);
996 if(c->opcode == OPCODE___CONTINUE__) {
997 char*name = string_cstr(c->data[0]);
998 syntaxerror("Unresolved \"continue %s\"", name);
1005 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1007 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1008 if(TYPE_IS_NUMBER(t)) {
1009 xassert(c->type == CONSTANT_FLOAT
1010 || c->type == CONSTANT_INT
1011 || c->type == CONSTANT_UINT);
1012 } else if(TYPE_IS_UINT(t)) {
1013 xassert(c->type == CONSTANT_UINT ||
1014 (c->type == CONSTANT_INT && c->i>=0));
1015 } else if(TYPE_IS_INT(t)) {
1016 xassert(c->type == CONSTANT_INT);
1017 } else if(TYPE_IS_BOOLEAN(t)) {
1018 xassert(c->type == CONSTANT_TRUE
1019 || c->type == CONSTANT_FALSE);
1023 static void check_override(memberinfo_t*m, int flags)
1027 if(m->parent == state->cls->info)
1028 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1030 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1031 if(m->access==ACCESS_PRIVATE)
1033 if(m->flags & FLAG_FINAL)
1034 syntaxerror("can't override final member %s", m->name);
1035 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1036 syntaxerror("can't override static member %s", m->name);
1037 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1038 syntaxerror("can't override non-static member %s with static declaration", m->name);
1040 if(!(flags&FLAG_OVERRIDE)) {
1041 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1042 if(m->kind == INFOTYPE_METHOD)
1043 syntaxerror("can't override without explicit 'override' declaration");
1045 syntaxerror("can't override '%s'", m->name);
1050 static methodinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
1052 methodinfo_t*minfo = 0;
1053 U8 access = flags2access(flags);
1056 minfo = methodinfo_register_global(access, state->package, name);
1057 minfo->return_type = return_type;
1058 } else if(getset != KW_GET && getset != KW_SET) {
1060 memberinfo_t* m = registry_findmember(state->cls->info, name, 0);
1062 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1064 minfo = methodinfo_register_onclass(state->cls->info, access, name);
1065 minfo->return_type = return_type;
1066 // getslot on a member slot only returns "undefined", so no need
1067 // to actually store these
1068 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1070 //class getter/setter
1071 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1073 if(getset == KW_GET)
1075 else if(params->list && params->list->param)
1076 type = params->list->param->type;
1077 // not sure wether to look into superclasses here, too
1078 minfo = (methodinfo_t*)registry_findmember(state->cls->info, name, 1);
1080 if(minfo->kind!=INFOTYPE_SLOT)
1081 syntaxerror("class already contains a method called '%s'", name);
1082 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1083 syntaxerror("class already contains a field called '%s'", name);
1084 if(minfo->subtype & gs)
1085 syntaxerror("getter/setter for '%s' already defined", name);
1086 /* make a setter or getter into a getset */
1087 minfo->subtype |= gs;
1088 if(!minfo->return_type) {
1089 minfo->return_type = type;
1091 if(minfo && minfo->return_type != type)
1092 syntaxerror("different type in getter and setter");
1095 minfo = methodinfo_register_onclass(state->cls->info, access, name);
1096 minfo->kind = INFOTYPE_SLOT; //hack
1097 minfo->subtype = gs;
1098 minfo->return_type = type;
1100 /* can't assign a slot as getter and setter might have different slots */
1101 //minfo->slot = slot;
1103 if(flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1104 if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1105 if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1109 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1111 //parserassert(state->method && state->method->info);
1113 methodstate_t*parent_method = state->method;
1122 state->new_vars = 1;
1125 state->method = rfx_calloc(sizeof(methodstate_t));
1126 state->method->inner = 1;
1127 state->method->variable_count = 0;
1128 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1130 NEW(methodinfo_t,minfo);
1131 minfo->kind = INFOTYPE_METHOD;
1132 minfo->access = ACCESS_PACKAGEINTERNAL;
1134 state->method->info = minfo;
1137 list_append(parent_method->innerfunctions, state->method);
1139 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1143 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1144 parserassert(state->method);
1146 state->method->info->return_type = return_type;
1147 function_initvars(state->method, params, 0);
1151 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
1152 params_t*params, classinfo_t*return_type)
1154 if(state->method && state->method->info) {
1155 syntaxerror("not able to start another method scope");
1160 state->method = rfx_calloc(sizeof(methodstate_t));
1161 state->method->has_super = 0;
1164 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1166 state->method->is_global = 1;
1167 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1169 if(state->method->is_constructor)
1170 name = "__as3_constructor__";
1173 state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
1175 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1179 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1180 parserassert(state->method);
1183 memberinfo_t*m = registry_findmember(state->cls->info, name, 2);
1184 check_override(m, flags);
1188 state->cls->has_constructor |= state->method->is_constructor;
1191 state->method->info->return_type = return_type;
1192 function_initvars(state->method, params, flags);
1196 static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
1197 params_t*params, classinfo_t*return_type, code_t*body)
1206 multiname_t*type2 = sig2mname(return_type);
1208 if(state->method->inner) {
1209 f = state->method->abc;
1210 abc_method_init(f, global->file, type2, 1);
1211 } else if(state->method->is_constructor) {
1212 f = abc_class_getconstructor(state->cls->abc, type2);
1213 } else if(!state->method->is_global) {
1214 namespace_t mname_ns = {state->method->info->access, ""};
1215 multiname_t mname = {QNAME, &mname_ns, 0, name};
1217 if(flags&FLAG_STATIC)
1218 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1220 f = abc_class_method(state->cls->abc, type2, &mname);
1221 slot = f->trait->slot_id;
1223 namespace_t mname_ns = {state->method->info->access, state->package};
1224 multiname_t mname = {QNAME, &mname_ns, 0, name};
1226 f = abc_method_new(global->file, type2, 1);
1227 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1228 //abc_code_t*c = global->init->method->body->code;
1230 //flash doesn't seem to allow us to access function slots
1231 //state->method->info->slot = slot;
1233 if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1234 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1235 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1236 if(params->varargs) f->flags |= METHOD_NEED_REST;
1240 for(p=params->list;p;p=p->next) {
1241 if(params->varargs && !p->next) {
1242 break; //varargs: omit last parameter in function signature
1244 multiname_t*m = sig2mname(p->param->type);
1245 list_append(f->parameters, m);
1246 if(p->param->value) {
1247 check_constant_against_type(p->param->type, p->param->value);
1248 opt=1;list_append(f->optional_parameters, p->param->value);
1250 syntaxerror("non-optional parameter not allowed after optional parameters");
1253 check_code_for_break(body);
1256 f->body->code = body;
1257 f->body->exceptions = state->method->exceptions;
1258 } else { //interface
1260 syntaxerror("interface methods can't have a method body");
1267 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1272 void breakjumpsto(code_t*c, char*name, code_t*jump)
1275 if(c->opcode == OPCODE___BREAK__) {
1276 string_t*name2 = c->data[0];
1277 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1278 c->opcode = OPCODE_JUMP;
1285 void continuejumpsto(code_t*c, char*name, code_t*jump)
1288 if(c->opcode == OPCODE___CONTINUE__) {
1289 string_t*name2 = c->data[0];
1290 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1291 c->opcode = OPCODE_JUMP;
1299 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1300 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1301 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1303 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1305 if(!type1 || !type2)
1306 return registry_getanytype();
1307 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1308 return registry_getanytype();
1311 if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1320 return registry_getanytype();
1322 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1327 return abc_coerce_a(c);
1331 // cast an "any" type to a specific type. subject to
1332 // runtime exceptions
1333 return abc_coerce2(c, &m);
1336 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1337 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1338 // allow conversion between number types
1339 return abc_coerce2(c, &m);
1341 //printf("%s.%s\n", from.package, from.name);
1342 //printf("%s.%s\n", to.package, to.name);
1344 classinfo_t*supertype = from;
1346 if(supertype == to) {
1347 // target type is one of from's superclasses
1348 return abc_coerce2(c, &m);
1351 while(supertype->interfaces[t]) {
1352 if(supertype->interfaces[t]==to) {
1353 // target type is one of from's interfaces
1354 return abc_coerce2(c, &m);
1358 supertype = supertype->superclass;
1360 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1362 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1364 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1367 as3_error("can't convert type %s%s%s to %s%s%s",
1368 from->package, from->package?".":"", from->name,
1369 to->package, to->package?".":"", to->name);
1373 code_t*defaultvalue(code_t*c, classinfo_t*type)
1375 if(TYPE_IS_INT(type)) {
1376 c = abc_pushbyte(c, 0);
1377 } else if(TYPE_IS_UINT(type)) {
1378 c = abc_pushuint(c, 0);
1379 } else if(TYPE_IS_FLOAT(type)) {
1381 } else if(TYPE_IS_BOOLEAN(type)) {
1382 c = abc_pushfalse(c);
1384 //c = abc_pushundefined(c);
1386 c = abc_pushnull(c);
1388 c = abc_coerce2(c, &m);
1393 char is_pushundefined(code_t*c)
1395 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1398 static slotinfo_t* find_class(char*name)
1402 c = registry_find(state->package, name);
1405 /* try explicit imports */
1406 dictentry_t* e = dict_get_slot(state->imports, name);
1409 if(!strcmp(e->key, name)) {
1410 c = (slotinfo_t*)e->data;
1416 /* try package.* imports */
1417 import_list_t*l = state->wildcard_imports;
1419 //printf("does package %s contain a class %s?\n", l->import->package, name);
1420 c = registry_find(l->import->package, name);
1425 /* try global package */
1426 c = registry_find("", name);
1429 /* try local "filename" package */
1430 c = registry_find(internal_filename_package, name);
1436 static char is_getlocal(code_t*c)
1438 if(!c || c->prev || c->next)
1440 return(c->opcode == OPCODE_GETLOCAL
1441 || c->opcode == OPCODE_GETLOCAL_0
1442 || c->opcode == OPCODE_GETLOCAL_1
1443 || c->opcode == OPCODE_GETLOCAL_2
1444 || c->opcode == OPCODE_GETLOCAL_3);
1446 static int getlocalnr(code_t*c)
1448 if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1449 else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1450 else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1451 else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1452 else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1453 else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1457 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1461 [prefix code] [read instruction]
1465 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1467 if(in && in->opcode == OPCODE_COERCE_A) {
1468 in = code_cutlast(in);
1471 syntaxerror("internal error");
1473 /* chop off read instruction */
1477 prefix = r->prev;r->prev = 0;
1483 char use_temp_var = readbefore;
1485 /* generate the write instruction, and maybe append a dup to the prefix code */
1486 code_t* write = abc_nop(0);
1487 if(r->opcode == OPCODE_GETPROPERTY) {
1488 write->opcode = OPCODE_SETPROPERTY;
1489 multiname_t*m = (multiname_t*)r->data[0];
1490 write->data[0] = multiname_clone(m);
1491 if(m->type == QNAME || m->type == MULTINAME) {
1493 prefix = abc_dup(prefix); // we need the object, too
1496 } else if(m->type == MULTINAMEL) {
1498 /* dupping two values on the stack requires 5 operations and one register-
1499 couldn't adobe just have given us a dup2? */
1500 int temp = gettempvar();
1501 prefix = abc_setlocal(prefix, temp);
1502 prefix = abc_dup(prefix);
1503 prefix = abc_getlocal(prefix, temp);
1504 prefix = abc_swap(prefix);
1505 prefix = abc_getlocal(prefix, temp);
1507 prefix = abc_kill(prefix, temp);
1511 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1513 } else if(r->opcode == OPCODE_GETSLOT) {
1514 write->opcode = OPCODE_SETSLOT;
1515 write->data[0] = r->data[0];
1517 prefix = abc_dup(prefix); // we need the object, too
1520 } else if(r->opcode == OPCODE_GETLOCAL) {
1521 write->opcode = OPCODE_SETLOCAL;
1522 write->data[0] = r->data[0];
1523 } else if(r->opcode == OPCODE_GETLOCAL_0) {
1524 write->opcode = OPCODE_SETLOCAL_0;
1525 } else if(r->opcode == OPCODE_GETLOCAL_1) {
1526 write->opcode = OPCODE_SETLOCAL_1;
1527 } else if(r->opcode == OPCODE_GETLOCAL_2) {
1528 write->opcode = OPCODE_SETLOCAL_2;
1529 } else if(r->opcode == OPCODE_GETLOCAL_3) {
1530 write->opcode = OPCODE_SETLOCAL_3;
1533 syntaxerror("illegal lvalue: can't assign a value to this expression");
1540 /* with getproperty/getslot, we have to be extra careful not
1541 to execute the read code twice, as it might have side-effects
1542 (e.g. if the property is in fact a setter/getter combination)
1544 So read the value, modify it, and write it again,
1545 using prefix only once and making sure (by using a temporary
1546 register) that the return value is what we just wrote */
1547 temp = gettempvar();
1548 c = code_append(c, prefix);
1549 c = code_append(c, r);
1552 c = abc_setlocal(c, temp);
1554 c = code_append(c, middlepart);
1557 c = abc_setlocal(c, temp);
1559 c = code_append(c, write);
1560 c = abc_getlocal(c, temp);
1561 c = abc_kill(c, temp);
1563 /* if we're allowed to execute the read code twice *and*
1564 the middlepart doesn't modify the code, things are easier.
1566 code_t* r2 = code_dup(r);
1567 //c = code_append(c, prefix);
1568 parserassert(!prefix);
1569 c = code_append(c, r);
1570 c = code_append(c, middlepart);
1571 c = code_append(c, write);
1572 c = code_append(c, r2);
1575 /* even smaller version: overwrite the value without reading
1579 c = code_append(c, prefix);
1582 c = code_append(c, middlepart);
1583 c = code_append(c, write);
1584 c = code_append(c, r);
1587 temp = gettempvar();
1589 c = code_append(c, prefix);
1591 c = code_append(c, middlepart);
1593 c = abc_setlocal(c, temp);
1594 c = code_append(c, write);
1595 c = abc_getlocal(c, temp);
1596 c = abc_kill(c, temp);
1602 char is_break_or_jump(code_t*c)
1606 if(c->opcode == OPCODE_JUMP ||
1607 c->opcode == OPCODE___BREAK__ ||
1608 c->opcode == OPCODE___CONTINUE__ ||
1609 c->opcode == OPCODE_THROW ||
1610 c->opcode == OPCODE_RETURNVOID ||
1611 c->opcode == OPCODE_RETURNVALUE) {
1618 #define IS_FINALLY_TARGET(op) \
1619 ((op) == OPCODE___CONTINUE__ || \
1620 (op) == OPCODE___BREAK__ || \
1621 (op) == OPCODE_RETURNVOID || \
1622 (op) == OPCODE_RETURNVALUE || \
1623 (op) == OPCODE___RETHROW__)
1625 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1627 #define NEED_EXTRA_STACK_ARG
1628 code_t*finally_label = abc_nop(0);
1629 NEW(lookupswitch_t, l);
1635 code_t*prev = i->prev;
1636 if(IS_FINALLY_TARGET(i->opcode)) {
1639 if(i->opcode == OPCODE___RETHROW__ ||
1640 i->opcode == OPCODE_RETURNVALUE) {
1641 if(i->opcode == OPCODE___RETHROW__)
1642 i->opcode = OPCODE_THROW;
1644 p = abc_coerce_a(p);
1645 p = abc_setlocal(p, tempvar);
1647 p = abc_pushbyte(p, count++);
1648 p = abc_jump(p, finally_label);
1649 code_t*target = p = abc_label(p);
1650 #ifdef NEED_EXTRA_STACK_ARG
1654 p = abc_getlocal(p, tempvar);
1657 p->next = i;i->prev = p;
1658 list_append(l->targets, target);
1664 c = abc_pushbyte(c, -1);
1665 c = code_append(c, finally_label);
1666 c = code_append(c, finally);
1668 #ifdef NEED_EXTRA_STACK_ARG
1671 c = abc_lookupswitch(c, l);
1672 c = l->def = abc_label(c);
1673 #ifdef NEED_EXTRA_STACK_ARG
1680 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1684 code_t*prev = i->prev;
1685 if(IS_FINALLY_TARGET(i->opcode)) {
1686 if(i->opcode == OPCODE___RETHROW__)
1687 i->opcode = OPCODE_THROW;
1688 code_t*end = code_dup(finally);
1689 code_t*start = code_start(end);
1690 if(prev) prev->next = start;
1697 return code_append(c, finally);
1700 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1706 int num_insertion_points=0;
1708 if(IS_FINALLY_TARGET(i->opcode))
1709 num_insertion_points++;
1716 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1721 int simple_version_cost = (1+num_insertion_points)*code_size;
1722 int lookup_version_cost = 4*num_insertion_points + 5;
1724 if(cantdup || simple_version_cost > lookup_version_cost) {
1725 printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
1726 return insert_finally_lookup(c, finally, tempvar);
1728 printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
1729 return insert_finally_simple(c, finally, tempvar);
1733 #define PASS1 }} if(as3_pass == 1) {{
1734 #define PASS1END }} if(as3_pass == 2) {{
1735 #define PASS2 }} if(as3_pass == 2) {{
1736 #define PASS12 }} {{
1737 #define PASS12END }} if(as3_pass == 2) {{
1743 /* ------------ code blocks / statements ---------------- */
1745 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1747 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1748 PROGRAM_CODE_LIST: PROGRAM_CODE
1749 | PROGRAM_CODE_LIST PROGRAM_CODE
1751 PROGRAM_CODE: PACKAGE_DECLARATION
1752 | INTERFACE_DECLARATION
1754 | FUNCTION_DECLARATION
1757 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' // conditional compilation
1760 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1761 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1762 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1764 INPACKAGE_CODE: INTERFACE_DECLARATION
1766 | FUNCTION_DECLARATION
1769 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' // conditional compilation
1772 MAYBECODE: CODE {$$=$1;}
1773 MAYBECODE: {$$=code_new();}
1775 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1776 CODE: CODEPIECE {$$=$1;}
1778 // code which also may appear outside a method
1779 CODE_STATEMENT: IMPORT
1781 CODE_STATEMENT: FOR_IN
1782 CODE_STATEMENT: WHILE
1783 CODE_STATEMENT: DO_WHILE
1784 CODE_STATEMENT: SWITCH
1786 CODE_STATEMENT: WITH
1788 CODE_STATEMENT: VOIDEXPRESSION
1789 CODE_STATEMENT: USE_NAMESPACE
1790 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1791 CODE_STATEMENT: '{' '}' {$$=0;}
1793 // code which may appear anywhere
1794 CODEPIECE: ';' {$$=0;}
1795 CODEPIECE: CODE_STATEMENT
1796 CODEPIECE: VARIABLE_DECLARATION
1801 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
1803 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1805 //CODEBLOCK : '{' CODE '}' {$$=$2;}
1806 //CODEBLOCK : '{' '}' {$$=0;}
1807 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1808 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1810 /* ------------ package init code ------------------- */
1812 PACKAGE_INITCODE: CODE_STATEMENT {
1813 code_t**cc = &global->init->method->body->code;
1814 *cc = code_append(*cc, $1);
1817 /* ------------ conditional compilation ------------- */
1819 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER
1821 /* ------------ variables --------------------------- */
1823 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1824 | {$$.c=abc_pushundefined(0);
1828 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1829 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1831 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1832 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1834 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1836 if(variable_exists($1))
1837 syntaxerror("Variable %s already defined", $1);
1839 if(!is_subtype_of($3.t, $2)) {
1840 syntaxerror("Can't convert %s to %s", $3.t->name,
1844 int index = new_variable($1, $2, 1);
1847 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1849 $$ = converttype($$, $3.t, $2);
1850 $$ = abc_setlocal($$, index);
1853 $$ = defaultvalue(0, $2);
1854 $$ = abc_setlocal($$, index);
1857 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1859 $$ = abc_coerce_a($$);
1860 $$ = abc_setlocal($$, index);
1867 /* that's the default for a local register, anyway
1869 state->method->initcode = abc_pushundefined(state->method->initcode);
1870 state->method->initcode = abc_setlocal(state->method->initcode, index);
1872 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1875 /* ------------ control flow ------------------------- */
1877 MAYBEELSE: %prec below_else {$$ = code_new();}
1878 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1879 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1881 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1884 $$ = code_append($$, $4.c);
1885 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1887 $$ = code_append($$, $6);
1889 myjmp = $$ = abc_jump($$, 0);
1891 myif->branch = $$ = abc_nop($$);
1893 $$ = code_append($$, $7);
1894 myjmp->branch = $$ = abc_nop($$);
1900 FOR_INIT : {$$=code_new();}
1901 FOR_INIT : VARIABLE_DECLARATION
1902 FOR_INIT : VOIDEXPRESSION
1904 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1905 // (I don't see any easy way to revolve this conflict otherwise, as we
1906 // can't touch VAR_READ without upsetting the precedence about "return")
1907 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1908 $$=$2;new_variable($2,$3,1);
1910 FOR_IN_INIT : T_IDENTIFIER {
1914 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1915 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1917 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1918 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1920 $$ = code_append($$, $2);
1921 code_t*loopstart = $$ = abc_label($$);
1922 $$ = code_append($$, $4.c);
1923 code_t*myif = $$ = abc_iffalse($$, 0);
1924 $$ = code_append($$, $8);
1925 code_t*cont = $$ = abc_nop($$);
1926 $$ = code_append($$, $6);
1927 $$ = abc_jump($$, loopstart);
1928 code_t*out = $$ = abc_nop($$);
1929 breakjumpsto($$, $1.name, out);
1930 continuejumpsto($$, $1.name, cont);
1937 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1938 variable_t*var = find_variable($2);
1939 char*tmp1name = concat2($2, "__tmp1__");
1940 int it = new_variable(tmp1name, TYPE_INT, 0);
1941 char*tmp2name = concat2($2, "__array__");
1942 int array = new_variable(tmp1name, 0, 0);
1945 $$ = code_append($$, $4.c);
1946 $$ = abc_coerce_a($$);
1947 $$ = abc_setlocal($$, array);
1948 $$ = abc_pushbyte($$, 0);
1949 $$ = abc_setlocal($$, it);
1951 code_t*loopstart = $$ = abc_label($$);
1953 $$ = abc_hasnext2($$, array, it);
1954 code_t*myif = $$ = abc_iffalse($$, 0);
1955 $$ = abc_getlocal($$, array);
1956 $$ = abc_getlocal($$, it);
1958 $$ = abc_nextname($$);
1960 $$ = abc_nextvalue($$);
1961 $$ = converttype($$, 0, var->type);
1962 $$ = abc_setlocal($$, var->index);
1964 $$ = code_append($$, $6);
1965 $$ = abc_jump($$, loopstart);
1967 code_t*out = $$ = abc_nop($$);
1968 breakjumpsto($$, $1.name, out);
1969 continuejumpsto($$, $1.name, loopstart);
1980 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1984 code_t*myjmp = $$ = abc_jump($$, 0);
1985 code_t*loopstart = $$ = abc_label($$);
1986 $$ = code_append($$, $6);
1987 code_t*cont = $$ = abc_nop($$);
1988 myjmp->branch = cont;
1989 $$ = code_append($$, $4.c);
1990 $$ = abc_iftrue($$, loopstart);
1991 code_t*out = $$ = abc_nop($$);
1992 breakjumpsto($$, $1, out);
1993 continuejumpsto($$, $1, cont);
1999 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2001 code_t*loopstart = $$ = abc_label($$);
2002 $$ = code_append($$, $3);
2003 code_t*cont = $$ = abc_nop($$);
2004 $$ = code_append($$, $6.c);
2005 $$ = abc_iftrue($$, loopstart);
2006 code_t*out = $$ = abc_nop($$);
2007 breakjumpsto($$, $1, out);
2008 continuejumpsto($$, $1, cont);
2014 BREAK : "break" %prec prec_none {
2015 $$ = abc___break__(0, "");
2017 BREAK : "break" T_IDENTIFIER {
2018 $$ = abc___break__(0, $2);
2020 CONTINUE : "continue" %prec prec_none {
2021 $$ = abc___continue__(0, "");
2023 CONTINUE : "continue" T_IDENTIFIER {
2024 $$ = abc___continue__(0, $2);
2027 MAYBE_CASE_LIST : {$$=0;}
2028 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2029 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2030 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2031 CASE_LIST: CASE {$$=$1;}
2032 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2034 CASE: "case" E ':' MAYBECODE {
2036 $$ = code_append($$, $2.c);
2037 code_t*j = $$ = abc_ifne($$, 0);
2038 $$ = code_append($$, $4);
2039 if($$->opcode != OPCODE___BREAK__) {
2040 $$ = abc___fallthrough__($$, "");
2042 code_t*e = $$ = abc_nop($$);
2045 DEFAULT: "default" ':' MAYBECODE {
2048 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
2050 $$ = code_append($$, $7);
2051 code_t*out = $$ = abc_pop($$);
2052 breakjumpsto($$, $1, out);
2054 code_t*c = $$,*lastblock=0;
2056 if(c->opcode == OPCODE_IFNE) {
2057 if(!c->next) syntaxerror("internal error in fallthrough handling");
2059 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2061 c->opcode = OPCODE_JUMP;
2062 c->branch = lastblock;
2064 /* fall through end of switch */
2065 c->opcode = OPCODE_NOP;
2075 /* ------------ try / catch /finally ---------------- */
2077 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
2079 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2080 multiname_t name = {QNAME, &name_ns, 0, $3};
2082 NEW(abc_exception_t, e)
2083 e->exc_type = sig2mname($4);
2084 e->var_name = multiname_clone(&name);
2088 int i = find_variable_safe($3)->index;
2089 e->target = c = abc_nop(0);
2090 c = abc_setlocal(c, i);
2091 c = code_append(c, $8);
2097 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
2103 NEW(abc_exception_t, e)
2104 e->exc_type = 0; //all exceptions
2105 e->var_name = 0; //no name
2108 e->to = code_append(e->to, $4);
2114 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2115 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2116 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2117 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2121 list_append($$.l,$2);
2122 $$.finally = $2->to;$2->to=0;
2125 CATCH_FINALLY_LIST: FINALLY {
2129 list_append($$.l,$1);
2130 $$.finally = $1->to;$1->to=0;
2134 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
2135 code_t*out = abc_nop(0);
2137 code_t*start = abc_nop(0);
2138 $$ = code_append(start, $4);
2139 if(!is_break_or_jump($4)) {
2140 $$ = abc_jump($$, out);
2142 code_t*end = $$ = abc_nop($$);
2146 tmp = new_variable("__finally__", 0, 0);
2148 abc_exception_list_t*l = $6.l;
2151 abc_exception_t*e = l->abc_exception;
2153 $$ = code_append($$, e->target);
2154 $$ = abc_jump($$, out);
2156 parserassert((ptroff_t)$6.finally);
2158 e->target = $$ = abc_nop($$);
2159 $$ = abc___rethrow__($$);
2167 $$ = code_append($$, out);
2169 $$ = insert_finally($$, $6.finally, tmp);
2171 list_concat(state->method->exceptions, $6.l);
2177 /* ------------ throw ------------------------------- */
2179 THROW : "throw" EXPRESSION {
2183 THROW : "throw" %prec prec_none {
2184 if(!state->exception_name)
2185 syntaxerror("re-throw only possible within a catch block");
2186 variable_t*v = find_variable(state->exception_name);
2188 $$=abc_getlocal($$, v->index);
2192 /* ------------ with -------------------------------- */
2194 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
2196 $$ = abc_pushscope($$);
2197 $$ = code_append($$, $5);
2198 $$ = abc_popscope($$);
2201 /* ------------ packages and imports ---------------- */
2203 X_IDENTIFIER: T_IDENTIFIER
2204 | "package" {PASS12 $$="package";}
2206 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2207 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2209 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2210 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2211 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2212 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2214 IMPORT : "import" PACKAGEANDCLASS {
2216 slotinfo_t*s = registry_find($2->package, $2->name);
2217 if(!s) {// || !(s->flags&FLAG_BUILTIN)) {
2218 as3_schedule_class($2->package, $2->name);
2224 syntaxerror("Couldn't import class\n");
2225 state_has_imports();
2226 dict_put(state->imports, c->name, c);
2229 IMPORT : "import" PACKAGE '.' '*' {
2231 if(strncmp("flash.", $2, 6)) {
2232 as3_schedule_package($2);
2238 state_has_imports();
2239 list_append(state->wildcard_imports, i);
2243 /* ------------ classes and interfaces (header) -------------- */
2245 MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
2246 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2247 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2248 MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
2250 MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
2251 | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
2252 | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
2253 | KW_STATIC {PASS12 $$=FLAG_STATIC;}
2254 | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
2255 | KW_FINAL {PASS12 $$=FLAG_FINAL;}
2256 | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
2257 | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
2258 | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
2259 | T_NAMESPACE {PASS12 $$=FLAG_NAMESPACE;}
2261 EXTENDS : {$$=registry_getobjectclass();}
2262 EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
2264 EXTENDS_LIST : {PASS12 $$=list_new();}
2265 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2267 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2268 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2270 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2271 EXTENDS IMPLEMENTS_LIST
2272 '{' {PASS12 startclass($1,$3,$4,$5);}
2274 '}' {PASS12 endclass();$$=0;}
2276 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2278 '{' {PASS12 startclass($1|FLAG_INTERFACE,$3,0,$4);}
2279 MAYBE_INTERFACE_BODY
2280 '}' {PASS12 endclass();$$=0;}
2282 /* ------------ classes and interfaces (body) -------------- */
2285 MAYBE_CLASS_BODY : CLASS_BODY
2286 CLASS_BODY : CLASS_BODY_ITEM
2287 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2288 CLASS_BODY_ITEM : ';'
2289 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}'
2290 CLASS_BODY_ITEM : SLOT_DECLARATION
2291 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2293 CLASS_BODY_ITEM : CODE_STATEMENT {
2294 code_t*c = state->cls->static_init->header;
2295 c = code_append(c, $1);
2296 state->cls->static_init->header = c;
2299 MAYBE_INTERFACE_BODY :
2300 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2301 INTERFACE_BODY : IDECLARATION
2302 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2304 IDECLARATION : "var" T_IDENTIFIER {
2305 syntaxerror("variable declarations not allowed in interfaces");
2307 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2310 if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2311 syntaxerror("invalid method modifiers: interface methods always need to be public");
2313 startfunction(0,$1,$3,$4,&$6,$8);
2314 endfunction(0,$1,$3,$4,&$6,$8, 0);
2315 list_deep_free($6.list);
2318 /* ------------ classes and interfaces (body, slots ) ------- */
2320 VARCONST: "var" | "const"
2322 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1);} MAYBETYPE MAYBEEXPRESSION {
2324 U8 access = flags2access($1);
2326 varinfo_t* info = 0;
2328 memberinfo_t*i = registry_findmember(state->cls->info, $3, 1);
2330 check_override(i, flags);
2332 info = varinfo_register_onclass(state->cls->info, access, $3);
2334 slotinfo_t*i = registry_find(state->package, $3);
2336 syntaxerror("package %s already contains '%s'", state->package, $3);
2338 info = varinfo_register_global(access, state->package, $3);
2342 info->flags = flags;
2345 namespace_t mname_ns = {access, ""};
2346 multiname_t mname = {QNAME, &mname_ns, 0, $3};
2348 trait_list_t**traits;
2352 mname_ns.name = state->package;
2353 traits = &global->init->traits;
2354 code = &global->init->method->body->code;
2355 } else if(flags&FLAG_STATIC) {
2357 traits = &state->cls->abc->static_traits;
2358 code = &state->cls->static_init->header;
2360 // instance variable
2361 traits = &state->cls->abc->traits;
2362 code = &state->cls->init->header;
2368 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2370 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2372 info->slot = t->slot_id;
2374 /* initalization code (if needed) */
2376 if($6.c && !is_pushundefined($6.c)) {
2377 c = abc_getlocal_0(c);
2378 c = code_append(c, $6.c);
2379 c = converttype(c, $6.t, $5);
2380 c = abc_setslot(c, t->slot_id);
2383 *code = code_append(*code, c);
2386 t->kind= TRAIT_CONST;
2390 setstaticfunction(0);
2393 /* ------------ constants -------------------------------------- */
2395 MAYBESTATICCONSTANT: {$$=0;}
2396 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2398 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2399 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2400 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2401 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2402 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2403 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2404 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2405 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2406 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2407 STATICCONSTANT : T_IDENTIFIER {
2409 as3_warning("Couldn't resolve %s", $1);
2410 $$ = constant_new_null($1);
2413 /* ------------ classes and interfaces (body, functions) ------- */
2415 // non-vararg version
2418 memset(&$$,0,sizeof($$));
2420 MAYBE_PARAM_LIST: PARAM_LIST {
2426 MAYBE_PARAM_LIST: "..." PARAM {
2428 memset(&$$,0,sizeof($$));
2430 list_append($$.list, $2);
2432 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2436 list_append($$.list, $4);
2440 PARAM_LIST: PARAM_LIST ',' PARAM {
2443 list_append($$.list, $3);
2447 memset(&$$,0,sizeof($$));
2448 list_append($$.list, $1);
2451 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2454 $$ = malloc(sizeof(param_t));
2459 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
2462 $$ = malloc(sizeof(param_t));
2464 $$->type = TYPE_ANY;
2467 GETSET : "get" {$$=$1;}
2471 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2472 MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}'
2474 PASS1 old_state();list_deep_free($6.list);
2476 if(!state->method->info) syntaxerror("internal error");
2478 code_t*c = method_header(state->method);
2479 c = wrap_function(c, 0, $11);
2481 endfunction(0,$1,$3,$4,&$6,$8,c);
2482 list_deep_free($6.list);
2486 MAYBE_IDENTIFIER: T_IDENTIFIER
2487 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2488 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2489 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2491 PASS1 old_state();list_deep_free($4.list);
2493 methodinfo_t*f = state->method->info;
2494 if(!f || !f->kind) syntaxerror("internal error");
2496 code_t*c = method_header(state->method);
2497 c = wrap_function(c, 0, $9);
2499 int index = state->method->var_index;
2500 endfunction(0,0,0,$2,&$4,$6,c);
2501 list_deep_free($4.list);
2503 $$.c = abc_getlocal(0, index);
2504 $$.t = TYPE_FUNCTION(f);
2508 /* ------------- package + class ids --------------- */
2510 CLASS: T_IDENTIFIER {
2513 slotinfo_t*s = find_class($1);
2514 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2515 $$ = (classinfo_t*)s;
2518 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2519 PASS1 static classinfo_t c;
2520 memset(&c, 0, sizeof(c));
2525 slotinfo_t*s = registry_find($1, $3);
2526 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2528 $$ = (classinfo_t*)s;
2531 CLASS_SPEC: PACKAGEANDCLASS
2534 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2535 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2537 TYPE : CLASS_SPEC {$$=$1;}
2538 | '*' {$$=registry_getanytype();}
2539 | "void" {$$=registry_getanytype();}
2541 | "String" {$$=registry_getstringclass();}
2542 | "int" {$$=registry_getintclass();}
2543 | "uint" {$$=registry_getuintclass();}
2544 | "Boolean" {$$=registry_getbooleanclass();}
2545 | "Number" {$$=registry_getnumberclass();}
2548 MAYBETYPE: ':' TYPE {$$=$2;}
2551 /* ----------function calls, delete, constructor calls ------ */
2553 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
2554 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2556 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2557 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2558 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2560 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
2564 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
2565 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
2567 $$.cc = code_append($1.cc, $2.c);
2571 NEW : "new" E XX MAYBE_PARAM_VALUES {
2573 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2575 code_t*paramcode = $4.cc;
2576 if($$.c->opcode == OPCODE_GETPROPERTY) {
2577 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2578 $$.c = code_cutlast($$.c);
2579 $$.c = code_append($$.c, paramcode);
2580 $$.c = abc_constructprop2($$.c, name, $4.len);
2581 multiname_destroy(name);
2582 } else if($$.c->opcode == OPCODE_GETSLOT) {
2583 int slot = (int)(ptroff_t)$$.c->data[0];
2584 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2585 multiname_t*name = t->name;
2586 $$.c = code_cutlast($$.c);
2587 $$.c = code_append($$.c, paramcode);
2588 $$.c = abc_constructprop2($$.c, name, $4.len);
2590 $$.c = code_append($$.c, paramcode);
2591 $$.c = abc_construct($$.c, $4.len);
2595 if(TYPE_IS_CLASS($2.t) && $2.t->data) {
2598 $$.c = abc_coerce_a($$.c);
2603 /* TODO: use abc_call (for calling local variables),
2604 abc_callstatic (for calling own methods)
2607 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2610 if($$.c->opcode == OPCODE_COERCE_A) {
2611 $$.c = code_cutlast($$.c);
2613 code_t*paramcode = $3.cc;
2616 if($$.c->opcode == OPCODE_GETPROPERTY) {
2617 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2618 $$.c = code_cutlast($$.c);
2619 $$.c = code_append($$.c, paramcode);
2620 $$.c = abc_callproperty2($$.c, name, $3.len);
2621 multiname_destroy(name);
2622 } else if($$.c->opcode == OPCODE_GETSLOT) {
2623 int slot = (int)(ptroff_t)$$.c->data[0];
2624 trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2625 if(t->kind!=TRAIT_METHOD) {
2626 //ok: flash allows to assign closures to members.
2628 multiname_t*name = t->name;
2629 $$.c = code_cutlast($$.c);
2630 $$.c = code_append($$.c, paramcode);
2631 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2632 $$.c = abc_callproperty2($$.c, name, $3.len);
2633 } else if($$.c->opcode == OPCODE_GETSUPER) {
2634 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2635 $$.c = code_cutlast($$.c);
2636 $$.c = code_append($$.c, paramcode);
2637 $$.c = abc_callsuper2($$.c, name, $3.len);
2638 multiname_destroy(name);
2640 $$.c = abc_getglobalscope($$.c);
2641 $$.c = code_append($$.c, paramcode);
2642 $$.c = abc_call($$.c, $3.len);
2645 if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
2646 $$.t = ((methodinfo_t*)($1.t->data))->return_type;
2648 $$.c = abc_coerce_a($$.c);
2653 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2654 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2655 if(!state->method) syntaxerror("super() not allowed outside of a function");
2656 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2659 $$.c = abc_getlocal_0($$.c);
2661 $$.c = code_append($$.c, $3.cc);
2663 this is dependent on the control path, check this somewhere else
2664 if(state->method->has_super)
2665 syntaxerror("constructor may call super() only once");
2667 state->method->has_super = 1;
2669 $$.c = abc_constructsuper($$.c, $3.len);
2670 $$.c = abc_pushundefined($$.c);
2674 DELETE: "delete" E {
2676 if($$.c->opcode == OPCODE_COERCE_A) {
2677 $$.c = code_cutlast($$.c);
2679 multiname_t*name = 0;
2680 if($$.c->opcode == OPCODE_GETPROPERTY) {
2681 $$.c->opcode = OPCODE_DELETEPROPERTY;
2682 } else if($$.c->opcode == OPCODE_GETSLOT) {
2683 int slot = (int)(ptroff_t)$$.c->data[0];
2684 multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2685 $$.c = code_cutlast($$.c);
2686 $$.c = abc_deleteproperty2($$.c, name);
2688 $$.c = abc_getlocal_0($$.c);
2689 MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2690 $$.c = abc_deleteproperty2($$.c, &m);
2692 $$.t = TYPE_BOOLEAN;
2695 RETURN: "return" %prec prec_none {
2696 $$ = abc_returnvoid(0);
2698 RETURN: "return" EXPRESSION {
2700 $$ = abc_returnvalue($$);
2703 // ----------------------- expression types -------------------------------------
2705 NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
2706 EXPRESSION : E %prec below_minus {$$ = $1;}
2707 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2709 $$.c = cut_last_push($$.c);
2710 $$.c = code_append($$.c,$3.c);
2713 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2714 $$=cut_last_push($1.c);
2717 // ----------------------- expression evaluation -------------------------------------
2719 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2720 //V : CONSTANT {$$ = 0;}
2722 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2723 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2724 //V : NEW {$$ = $1.c;}
2726 //V : DELETE {$$ = $1.c;}
2727 E : DELETE {$$ = $1;}
2733 namespace_t ns = {ACCESS_PACKAGE, ""};
2734 multiname_t m = {QNAME, &ns, 0, "RegExp"};
2736 $$.c = abc_getlex2($$.c, &m);
2737 $$.c = abc_pushstring($$.c, $1.pattern);
2738 $$.c = abc_construct($$.c, 1);
2740 $$.c = abc_getlex2($$.c, &m);
2741 $$.c = abc_pushstring($$.c, $1.pattern);
2742 $$.c = abc_pushstring($$.c, $1.options);
2743 $$.c = abc_construct($$.c, 2);
2748 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2749 //MULTINAME(m, registry_getintclass());
2750 //$$.c = abc_coerce2($$.c, &m); // FIXME
2753 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2756 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2759 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2762 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2765 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
2768 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2771 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2772 $$.t = TYPE_BOOLEAN;
2774 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2775 $$.t = TYPE_BOOLEAN;
2777 CONSTANT : "null" {$$.c = abc_pushnull(0);
2781 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2782 $$.t = TYPE_BOOLEAN;
2784 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2785 $$.t = TYPE_BOOLEAN;
2787 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2788 $$.t = TYPE_BOOLEAN;
2790 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2791 $$.t = TYPE_BOOLEAN;
2793 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2794 $$.t = TYPE_BOOLEAN;
2796 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2797 $$.t = TYPE_BOOLEAN;
2799 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2800 $$.t = TYPE_BOOLEAN;
2802 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2803 $$.t = TYPE_BOOLEAN;
2806 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2808 $$.c = converttype($$.c, $1.t, $$.t);
2809 $$.c = abc_dup($$.c);
2810 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2811 $$.c = cut_last_push($$.c);
2812 $$.c = code_append($$.c,$3.c);
2813 $$.c = converttype($$.c, $3.t, $$.t);
2814 code_t*label = $$.c = abc_label($$.c);
2815 jmp->branch = label;
2818 $$.t = join_types($1.t, $3.t, 'A');
2819 /*printf("%08x:\n",$1.t);
2820 code_dump($1.c, 0, 0, "", stdout);
2821 printf("%08x:\n",$3.t);
2822 code_dump($3.c, 0, 0, "", stdout);
2823 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2825 $$.c = converttype($$.c, $1.t, $$.t);
2826 $$.c = abc_dup($$.c);
2827 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2828 $$.c = cut_last_push($$.c);
2829 $$.c = code_append($$.c,$3.c);
2830 $$.c = converttype($$.c, $3.t, $$.t);
2831 code_t*label = $$.c = abc_label($$.c);
2832 jmp->branch = label;
2835 E : '!' E {$$.c=$2.c;
2836 $$.c = abc_not($$.c);
2837 $$.t = TYPE_BOOLEAN;
2840 E : '~' E {$$.c=$2.c;
2841 $$.c = abc_bitnot($$.c);
2845 E : E '&' E {$$.c = code_append($1.c,$3.c);
2846 $$.c = abc_bitand($$.c);
2850 E : E '^' E {$$.c = code_append($1.c,$3.c);
2851 $$.c = abc_bitxor($$.c);
2855 E : E '|' E {$$.c = code_append($1.c,$3.c);
2856 $$.c = abc_bitor($$.c);
2860 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2861 $$.c = abc_rshift($$.c);
2864 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2865 $$.c = abc_urshift($$.c);
2868 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2869 $$.c = abc_lshift($$.c);
2873 E : E '/' E {$$.c = code_append($1.c,$3.c);
2874 $$.c = abc_divide($$.c);
2877 E : E '%' E {$$.c = code_append($1.c,$3.c);
2878 $$.c = abc_modulo($$.c);
2881 E : E '+' E {$$.c = code_append($1.c,$3.c);
2882 if(BOTH_INT($1.t, $3.t)) {
2883 $$.c = abc_add_i($$.c);
2886 $$.c = abc_add($$.c);
2887 $$.t = join_types($1.t,$3.t,'+');
2890 E : E '-' E {$$.c = code_append($1.c,$3.c);
2891 if(BOTH_INT($1.t,$3.t)) {
2892 $$.c = abc_subtract_i($$.c);
2895 $$.c = abc_subtract($$.c);
2899 E : E '*' E {$$.c = code_append($1.c,$3.c);
2900 if(BOTH_INT($1.t,$3.t)) {
2901 $$.c = abc_multiply_i($$.c);
2904 $$.c = abc_multiply($$.c);
2909 E : E "in" E {$$.c = code_append($1.c,$3.c);
2910 $$.c = abc_in($$.c);
2911 $$.t = TYPE_BOOLEAN;
2914 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2915 if(use_astype && TYPE_IS_CLASS($3.t) && $3.t->data) {
2916 MULTINAME(m, (classinfo_t*)($3.t->data));
2917 $$.c = abc_astype2($1.c, &m);
2920 $$.c = code_append($1.c, $3.c);
2921 $$.c = abc_astypelate($$.c);
2926 E : E "instanceof" E
2927 {$$.c = code_append($1.c, $3.c);
2928 $$.c = abc_instanceof($$.c);
2929 $$.t = TYPE_BOOLEAN;
2932 E : E "is" E {$$.c = code_append($1.c, $3.c);
2933 $$.c = abc_istypelate($$.c);
2934 $$.t = TYPE_BOOLEAN;
2937 E : "typeof" '(' E ')' {
2939 $$.c = abc_typeof($$.c);
2944 $$.c = cut_last_push($2.c);
2945 $$.c = abc_pushundefined($$.c);
2949 E : "void" { $$.c = abc_pushundefined(0);
2953 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2958 $$.c=abc_negate_i($$.c);
2961 $$.c=abc_negate($$.c);
2968 $$.c = code_append($$.c, $3.c);
2970 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2971 $$.c = abc_getproperty2($$.c, &m);
2972 $$.t = 0; // array elements have unknown type
2975 E : '[' MAYBE_EXPRESSION_LIST ']' {
2977 $$.c = code_append($$.c, $2.cc);
2978 $$.c = abc_newarray($$.c, $2.len);
2979 $$.t = registry_getarrayclass();
2982 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2983 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
2985 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2987 $$.cc = code_append($$.cc, $1.c);
2988 $$.cc = code_append($$.cc, $3.c);
2991 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2994 $$.cc = code_append($$.cc, $3.c);
2995 $$.cc = code_append($$.cc, $5.c);
3000 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
3002 $$.c = code_append($$.c, $2.cc);
3003 $$.c = abc_newobject($$.c, $2.len/2);
3004 $$.t = registry_getobjectclass();
3009 if(BOTH_INT($1.t,$3.t)) {
3010 c=abc_multiply_i(c);
3014 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
3015 $$.c = toreadwrite($1.c, c, 0, 0);
3020 code_t*c = abc_modulo($3.c);
3021 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
3022 $$.c = toreadwrite($1.c, c, 0, 0);
3026 code_t*c = abc_lshift($3.c);
3027 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
3028 $$.c = toreadwrite($1.c, c, 0, 0);
3032 code_t*c = abc_rshift($3.c);
3033 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
3034 $$.c = toreadwrite($1.c, c, 0, 0);
3038 code_t*c = abc_urshift($3.c);
3039 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
3040 $$.c = toreadwrite($1.c, c, 0, 0);
3044 code_t*c = abc_divide($3.c);
3045 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
3046 $$.c = toreadwrite($1.c, c, 0, 0);
3050 code_t*c = abc_bitor($3.c);
3051 c=converttype(c, TYPE_INT, $1.t);
3052 $$.c = toreadwrite($1.c, c, 0, 0);
3056 code_t*c = abc_bitxor($3.c);
3057 c=converttype(c, TYPE_INT, $1.t);
3058 $$.c = toreadwrite($1.c, c, 0, 0);
3064 if(TYPE_IS_INT($1.t)) {
3068 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
3071 $$.c = toreadwrite($1.c, c, 0, 0);
3074 E : E "-=" E { code_t*c = $3.c;
3075 if(TYPE_IS_INT($1.t)) {
3076 c=abc_subtract_i(c);
3079 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
3082 $$.c = toreadwrite($1.c, c, 0, 0);
3085 E : E '=' E { code_t*c = 0;
3086 c = code_append(c, $3.c);
3087 c = converttype(c, $3.t, $1.t);
3088 $$.c = toreadwrite($1.c, c, 1, 0);
3092 E : E '?' E ':' E %prec below_assignment {
3093 $$.t = join_types($3.t,$5.t,'?');
3095 code_t*j1 = $$.c = abc_iffalse($$.c, 0);
3096 $$.c = code_append($$.c, $3.c);
3097 $$.c = converttype($$.c, $3.t, $$.t);
3098 code_t*j2 = $$.c = abc_jump($$.c, 0);
3099 $$.c = j1->branch = abc_label($$.c);
3100 $$.c = code_append($$.c, $5.c);
3101 $$.c = converttype($$.c, $3.t, $$.t);
3102 $$.c = j2->branch = abc_label($$.c);
3105 E : E "++" { code_t*c = 0;
3106 classinfo_t*type = $1.t;
3107 if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
3108 int nr = getlocalnr($1.c);
3109 code_free($1.c);$1.c=0;
3110 if(TYPE_IS_INT($1.t)) {
3111 $$.c = abc_getlocal(0, nr);
3112 $$.c = abc_inclocal_i($$.c, nr);
3113 } else if(TYPE_IS_NUMBER($1.t)) {
3114 $$.c = abc_getlocal(0, nr);
3115 $$.c = abc_inclocal($$.c, nr);
3116 } else syntaxerror("internal error");
3118 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3119 c=abc_increment_i(c);
3125 c=converttype(c, type, $1.t);
3126 $$.c = toreadwrite($1.c, c, 0, 1);
3131 // TODO: use inclocal, like with ++
3132 E : E "--" { code_t*c = 0;
3133 classinfo_t*type = $1.t;
3134 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3135 c=abc_decrement_i(c);
3141 c=converttype(c, type, $1.t);
3142 $$.c = toreadwrite($1.c, c, 0, 1);
3146 E : "++" %prec plusplus_prefix E { code_t*c = 0;
3147 classinfo_t*type = $2.t;
3148 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3149 c=abc_increment_i(c);
3155 c=converttype(c, type, $2.t);
3156 $$.c = toreadwrite($2.c, c, 0, 0);
3160 E : "--" %prec minusminus_prefix E { code_t*c = 0;
3161 classinfo_t*type = $2.t;
3162 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3163 c=abc_decrement_i(c);
3169 c=converttype(c, type, $2.t);
3170 $$.c = toreadwrite($2.c, c, 0, 0);
3174 E : "super" '.' T_IDENTIFIER
3175 { if(!state->cls->info)
3176 syntaxerror("super keyword not allowed outside a class");
3177 classinfo_t*t = state->cls->info->superclass;
3178 if(!t) t = TYPE_OBJECT;
3180 memberinfo_t*f = registry_findmember(t, $3, 1);
3181 namespace_t ns = {f->access, ""};
3182 MEMBER_MULTINAME(m, f, $3);
3184 $$.c = abc_getlocal_0($$.c);
3185 $$.c = abc_getsuper2($$.c, &m);
3186 $$.t = slotinfo_gettype((slotinfo_t*)f);
3189 E : '@' T_IDENTIFIER {
3191 $$.c = abc_pushundefined(0);
3193 as3_warning("ignored @ operator");
3196 E : E '.' '@' T_IDENTIFIER {
3197 // child attribute TODO
3198 $$.c = abc_pushundefined(0);
3200 as3_warning("ignored .@ operator");
3203 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3204 // namespace declaration TODO
3205 $$.c = abc_pushundefined(0);
3207 as3_warning("ignored :: operator");
3210 E : E ".." T_IDENTIFIER {
3212 $$.c = abc_pushundefined(0);
3214 as3_warning("ignored .. operator");
3217 E : E '.' '(' E ')' {
3219 $$.c = abc_pushundefined(0);
3221 as3_warning("ignored .() operator");
3224 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
3228 E : E '.' T_IDENTIFIER
3230 classinfo_t*t = $1.t;
3232 if(TYPE_IS_CLASS(t) && t->data) {
3237 memberinfo_t*f = registry_findmember(t, $3, 1);
3239 if(f && !is_static != !(f->flags&FLAG_STATIC))
3241 if(f && f->slot && !noslot) {
3242 $$.c = abc_getslot($$.c, f->slot);
3244 MEMBER_MULTINAME(m, f, $3);
3245 $$.c = abc_getproperty2($$.c, &m);
3247 /* determine type */
3248 $$.t = slotinfo_gettype((slotinfo_t*)f);
3250 $$.c = abc_coerce_a($$.c);
3252 /* when resolving a property on an unknown type, we do know the
3253 name of the property (and don't seem to need the package), but
3254 we need to make avm2 try out all access modes */
3255 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3256 $$.c = abc_getproperty2($$.c, &m);
3257 $$.c = abc_coerce_a($$.c);
3258 $$.t = registry_getanytype();
3262 VAR_READ : T_IDENTIFIER {
3269 /* look at variables */
3270 if((v = find_variable($1))) {
3271 // $1 is a local variable
3272 $$.c = abc_getlocal($$.c, v->index);
3277 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3279 /* look at current class' members */
3280 if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
3281 (f->flags&FLAG_STATIC) >= i_am_static) {
3282 // $1 is a function in this class
3283 int var_is_static = (f->flags&FLAG_STATIC);
3285 if(f->kind == INFOTYPE_METHOD) {
3286 $$.t = TYPE_FUNCTION(f);
3290 if(var_is_static && !i_am_static) {
3291 /* access to a static member from a non-static location.
3292 do this via findpropstrict:
3293 there doesn't seem to be any non-lookup way to access
3294 static properties of a class */
3295 state->method->late_binding = 1;
3297 namespace_t ns = {f->access, ""};
3298 multiname_t m = {QNAME, &ns, 0, $1};
3299 $$.c = abc_findpropstrict2($$.c, &m);
3300 $$.c = abc_getproperty2($$.c, &m);
3302 } else if(f->slot>0) {
3303 $$.c = abc_getlocal_0($$.c);
3304 $$.c = abc_getslot($$.c, f->slot);
3307 namespace_t ns = {f->access, ""};
3308 multiname_t m = {QNAME, &ns, 0, $1};
3309 $$.c = abc_getlocal_0($$.c);
3310 $$.c = abc_getproperty2($$.c, &m);
3315 /* look at actual classes, in the current package and imported */
3316 if((a = find_class($1))) {
3317 if(a->access == ACCESS_PACKAGEINTERNAL &&
3318 strcmp(a->package, state->package) &&
3319 strcmp(a->package, internal_filename_package)
3321 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
3322 infotypename(a),$1, a->package, state->package);
3324 if(a->kind != INFOTYPE_CLASS) {
3326 $$.c = abc_findpropstrict2($$.c, &m);
3327 $$.c = abc_getproperty2($$.c, &m);
3328 if(a->kind == INFOTYPE_METHOD) {
3329 methodinfo_t*f = (methodinfo_t*)a;
3330 $$.t = TYPE_FUNCTION(f);
3332 varinfo_t*v = (varinfo_t*)a;
3336 classinfo_t*c = (classinfo_t*)a;
3338 $$.c = abc_getglobalscope($$.c);
3339 $$.c = abc_getslot($$.c, c->slot);
3342 $$.c = abc_getlex2($$.c, &m);
3344 $$.t = TYPE_CLASS(c);
3349 /* unknown object, let the avm2 resolve it */
3351 as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3352 state->method->late_binding = 1;
3354 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3357 $$.c = abc_findpropstrict2($$.c, &m);
3358 $$.c = abc_getproperty2($$.c, &m);
3362 // ----------------- namespaces -------------------------------------------------
3364 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
3365 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
3366 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
3368 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {
3370 tokenizer_register_namespace($3);