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 */
31 #include "tokenizer.h"
48 enum yytokentype token;
50 classinfo_t*classinfo;
51 classinfo_list_t*classinfo_list;
53 slotinfo_list_t*slotinfo_list;
56 unsigned int number_uint;
60 //typedcode_list_t*value_list;
61 codeandnumber_t value_list;
67 for_start_t for_start;
68 abc_exception_t *exception;
71 namespace_decl_t* namespace_decl;
74 abc_exception_list_t *l;
80 %token<id> T_IDENTIFIER T_NAMESPACE
82 %token<regexp> T_REGEXP
84 %token<number_int> T_INT
85 %token<number_uint> T_UINT
86 %token<number_float> T_FLOAT
88 %token<id> T_FOR "for"
89 %token<id> T_WHILE "while"
91 %token<id> T_SWITCH "switch"
93 %token<token> KW_IMPLEMENTS "implements"
94 %token<token> KW_NAMESPACE "namespace"
95 %token<token> KW_PACKAGE "package"
96 %token<token> KW_PROTECTED "protected"
97 %token<token> KW_ARGUMENTS "arguments"
98 %token<token> KW_PUBLIC "public"
99 %token<token> KW_PRIVATE "private"
100 %token<token> KW_USE "use"
101 %token<token> KW_INTERNAL "internal"
102 %token<token> KW_NEW "new"
103 %token<token> KW_NATIVE "native"
104 %token<token> KW_FUNCTION "function"
105 %token<token> KW_FINALLY "finally"
106 %token<token> KW_UNDEFINED "undefined"
107 %token<token> KW_NAN "NaN"
108 %token<token> KW_CONTINUE "continue"
109 %token<token> KW_CLASS "class"
110 %token<token> KW_CONST "const"
111 %token<token> KW_CATCH "catch"
112 %token<token> KW_CASE "case"
113 %token<token> KW_SET "set"
114 %token<token> KW_VOID "void"
115 %token<token> KW_THROW "throw"
116 %token<token> KW_STATIC "static"
117 %token<token> KW_WITH "with"
118 %token<token> KW_INSTANCEOF "instanceof"
119 %token<token> KW_IMPORT "import"
120 %token<token> KW_RETURN "return"
121 %token<token> KW_TYPEOF "typeof"
122 %token<token> KW_INTERFACE "interface"
123 %token<token> KW_NULL "null"
124 %token<token> KW_VAR "var"
125 %token<token> KW_DYNAMIC "dynamic"
126 %token<token> KW_OVERRIDE "override"
127 %token<token> KW_FINAL "final"
128 %token<token> KW_EACH "each"
129 %token<token> KW_GET "get"
130 %token<token> KW_TRY "try"
131 %token<token> KW_SUPER "super"
132 %token<token> KW_EXTENDS "extends"
133 %token<token> KW_FALSE "false"
134 %token<token> KW_TRUE "true"
135 %token<token> KW_BOOLEAN "Boolean"
136 %token<token> KW_UINT "uint"
137 %token<token> KW_INT "int"
138 %token<token> KW_NUMBER "Number"
139 %token<token> KW_STRING "String"
140 %token<token> KW_DEFAULT "default"
141 %token<token> KW_DELETE "delete"
142 %token<token> KW_IF "if"
143 %token<token> KW_ELSE "else"
144 %token<token> KW_BREAK "break"
145 %token<token> KW_IS "is"
146 %token<token> KW_IN "in"
147 %token<token> KW_AS "as"
149 %token<token> T_DICTSTART "{ (dictionary)"
150 %token<token> T_EQEQ "=="
151 %token<token> T_EQEQEQ "==="
152 %token<token> T_NE "!="
153 %token<token> T_NEE "!=="
154 %token<token> T_LE "<="
155 %token<token> T_GE ">="
156 %token<token> T_ORBY "|="
157 %token<token> T_DIVBY "/="
158 %token<token> T_MODBY "%="
159 %token<token> T_MULBY "*="
160 %token<token> T_ANDBY "&="
161 %token<token> T_PLUSBY "+="
162 %token<token> T_MINUSBY "-="
163 %token<token> T_XORBY "^="
164 %token<token> T_SHRBY ">>="
165 %token<token> T_SHLBY "<<="
166 %token<token> T_USHRBY ">>>="
167 %token<token> T_OROR "||"
168 %token<token> T_ANDAND "&&"
169 %token<token> T_COLONCOLON "::"
170 %token<token> T_MINUSMINUS "--"
171 %token<token> T_PLUSPLUS "++"
172 %token<token> T_DOTDOT ".."
173 %token<token> T_DOTDOTDOT "..."
174 %token<token> T_SHL "<<"
175 %token<token> T_USHR ">>>"
176 %token<token> T_SHR ">>"
178 %type <number_int> CONDITIONAL_COMPILATION
179 %type <for_start> FOR_START
180 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER ID_OR_NS SUBNODE
181 %type <namespace_decl> NAMESPACE_ID
182 %type <token> VARCONST
184 %type <code> CODEPIECE CODE_STATEMENT
185 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
186 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
187 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
188 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
189 %type <exception> CATCH FINALLY
190 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
191 %type <code> CLASS_DECLARATION
192 %type <code> NAMESPACE_DECLARATION
193 %type <code> INTERFACE_DECLARATION
194 %type <code> VOIDEXPRESSION
195 %type <value> EXPRESSION NONCOMMAEXPRESSION
196 %type <node> MAYBEEXPRESSION
198 %type <node> E COMMA_EXPRESSION
199 %type <node> VAR_READ
200 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
201 %type <value> INNERFUNCTION
202 %type <code> USE_NAMESPACE
203 %type <code> FOR_INIT
205 %type <classinfo> MAYBETYPE
208 %type <params> PARAM_LIST
209 %type <params> MAYBE_PARAM_LIST
210 %type <flags> MAYBE_MODIFIERS
211 %type <flags> MODIFIER_LIST
212 %type <flags> MODIFIER
213 %type <constant> CONSTANT MAYBECONSTANT
214 %type <classinfo_list> IMPLEMENTS_LIST
215 %type <classinfo> EXTENDS CLASS_SPEC
216 %type <classinfo_list> EXTENDS_LIST
217 %type <classinfo> CLASS PACKAGEANDCLASS
218 %type <classinfo_list> CLASS_SPEC_LIST
219 %type <id> XML XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT XML_ID_OR_EXPR XMLEXPR1 XMLEXPR2
220 %type <classinfo> TYPE
221 //%type <token> VARIABLE
224 //%type <token> T_IDENTIFIER
225 %type <value> FUNCTIONCALL
226 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES
227 %type <value_list> MAYBE_DICT_EXPRPAIR_LIST DICT_EXPRPAIR_LIST WITH_HEAD
230 // precedence: from low to high
234 %left below_semicolon
237 %nonassoc below_assignment // for ?:, contrary to spec
238 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
245 %nonassoc "==" "!=" "===" "!=="
246 %nonassoc "is" "as" "in"
248 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
249 %left "<<" ">>" ">>>"
253 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
255 %nonassoc below_curly
259 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
261 %left T_IDENTIFIER "arguments"
262 %left above_identifier
266 // needed for "return" precedence:
267 %nonassoc T_STRING T_REGEXP
268 %nonassoc T_INT T_UINT T_FLOAT KW_NAN
269 %nonassoc "false" "true" "null" "undefined" "super" "function"
276 static int a3_error(char*s)
278 syntaxerror("%s", s);
279 return 0; //make gcc happy
282 static void parsererror(const char*file, int line, const char*f)
284 syntaxerror("internal error in %s, %s:%d", f, file, line);
287 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
290 static char* concat2(const char* t1, const char* t2)
294 char*text = malloc(l1+l2+1);
295 memcpy(text , t1, l1);
296 memcpy(text+l1, t2, l2);
300 static char* concat3(const char* t1, const char* t2, const char* t3)
305 char*text = malloc(l1+l2+l3+1);
306 memcpy(text , t1, l1);
307 memcpy(text+l1, t2, l2);
308 memcpy(text+l1+l2, t3, l3);
313 typedef struct _import {
316 DECLARE_LIST(import);
318 DECLARE(methodstate);
319 DECLARE_LIST(methodstate);
321 typedef struct _classstate {
327 methodstate_t*static_init;
329 //code_t*static_init;
331 char has_constructor;
334 struct _methodstate {
345 dict_t*unresolved_variables;
348 char uses_parent_function;
356 int var_index; // for inner methods
357 int slot_index; // for inner methods
358 char is_a_slot; // for inner methods
363 abc_exception_list_t*exceptions;
365 methodstate_list_t*innerfunctions;
368 typedef struct _state {
373 import_list_t*wildcard_imports;
374 dict_t*import_toplevel_packages;
377 namespace_list_t*active_namespace_urls;
379 char has_own_imports;
380 char new_vars; // e.g. transition between two functions
381 char xmlfilter; // are we inside a xmlobj..() filter?
384 methodstate_t*method;
391 dict_t*allvars; // also contains variables from sublevels
394 typedef struct _global {
397 parsedclass_list_t*classes;
398 abc_script_t*classinit;
400 abc_script_t*init; //package-level code
403 dict_t*file2token2info;
406 static global_t*global = 0;
407 static state_t* state = 0;
411 /* protected handling here is a big hack: we just assume the protectedns
412 is package:class. the correct approach would be to add the proper
413 namespace to all protected members in the registry, even though that
414 would slow down searching */
415 #define MEMBER_MULTINAME(m,f,n) \
419 m##_ns.access = ((slotinfo_t*)(f))->access; \
420 if(m##_ns.access == ACCESS_NAMESPACE) \
421 m##_ns.name = ((slotinfo_t*)(f))->package; \
422 else if(m##_ns.access == ACCESS_PROTECTED && (f)->parent) \
423 m##_ns.name = concat3((f)->parent->package,":",(f)->parent->name); \
428 m.namespace_set = 0; \
429 m.name = ((slotinfo_t*)(f))->name; \
431 m.type = MULTINAME; \
433 m.namespace_set = &nopackage_namespace_set; \
437 /* warning: list length of namespace set is undefined */
438 #define MULTINAME_LATE(m, access, package) \
439 namespace_t m##_ns = {access, package}; \
440 namespace_set_t m##_nsset; \
441 namespace_list_t m##_l;m##_l.next = 0; \
442 m##_nsset.namespaces = &m##_l; \
443 m##_nsset = m##_nsset; \
444 m##_l.namespace = &m##_ns; \
445 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
447 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
448 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
449 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
450 static namespace_t stdns = {ACCESS_PACKAGE, ""};
451 static namespace_list_t nl4 = {&stdns,0};
452 static namespace_list_t nl3 = {&ns3,&nl4};
453 static namespace_list_t nl2 = {&ns2,&nl3};
454 static namespace_list_t nl1 = {&ns1,&nl2};
455 static namespace_set_t nopackage_namespace_set = {&nl1};
457 static dict_t*definitions=0;
458 void as3_set_define(const char*c)
461 definitions = dict_new();
462 if(!dict_contains(definitions,c))
463 dict_put(definitions,c,0);
466 static void new_state()
469 state_t*oldstate = state;
471 memcpy(s, state, sizeof(state_t)); //shallow copy
473 s->imports = dict_new();
475 if(!s->import_toplevel_packages) {
476 s->import_toplevel_packages = dict_new();
480 state->has_own_imports = 0;
481 state->vars = dict_new();
482 state->old = oldstate;
485 trie_remember(active_namespaces);
488 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
491 static void state_destroy(state_t*state)
493 if(state->has_own_imports) {
494 list_free(state->wildcard_imports);
495 dict_destroy(state->imports);state->imports=0;
497 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
498 dict_destroy(state->imports);state->imports=0;
501 dict_destroy(state->vars);state->vars=0;
503 if(state->new_vars && state->allvars) {
504 parserassert(!state->old || state->old->allvars != state->allvars);
505 DICT_ITERATE_DATA(state->allvars, void*, data) {
508 dict_destroy(state->allvars);
511 list_free(state->active_namespace_urls)
512 state->active_namespace_urls = 0;
517 static void old_state()
519 trie_rollback(active_namespaces);
521 if(!state || !state->old)
522 syntaxerror("invalid nesting");
523 state_t*leaving = state;
527 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
528 free(leaving->method);
531 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
536 state_destroy(leaving);
539 static code_t* method_header(methodstate_t*m);
540 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
541 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0);
544 static char* internal_filename_package = 0;
545 void initialize_file(char*filename)
548 syntaxerror("invalid call to initialize_file during parsing of another file");
551 active_namespaces = trie_new();
554 state->package = internal_filename_package = strdup(filename);
555 state->allvars = dict_new();
557 global->token2info = dict_lookup(global->file2token2info,
558 current_filename // use long version
560 if(!global->token2info) {
561 global->token2info = dict_new2(&ptr_type);
562 dict_put(global->file2token2info, current_filename, global->token2info);
566 state->method = rfx_calloc(sizeof(methodstate_t));
567 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
568 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
570 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
572 syntaxerror("internal error: skewed tokencount");
573 function_initvars(state->method, 0, 0, 0, 1);
574 global->init = abc_initscript(global->file);
580 if(!state || state->level!=1) {
581 syntaxerror("unexpected end of file in pass %d", as3_pass);
585 dict_del(global->file2token2info, current_filename);
586 code_t*header = method_header(state->method);
587 code_t*c = wrap_function(header, 0, global->init->method->body->code);
588 global->init->method->body->code = abc_returnvoid(c);
589 free(state->method);state->method=0;
592 //free(state->package);state->package=0; // used in registry
593 state_destroy(state);state=0;
596 void initialize_parser()
598 global = rfx_calloc(sizeof(global_t));
599 global->file = abc_file_new();
600 global->file->flags &= ~ABCFILE_LAZY;
601 global->file2token2info = dict_new();
602 global->token2info = 0;
603 global->classinit = abc_initscript(global->file);
606 void* finish_parser()
608 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
609 global->token2info=0;
611 initcode_add_classlist(global->classinit, global->classes);
616 typedef struct _variable {
621 methodstate_t*is_inner_method;
624 static variable_t* find_variable(state_t*s, char*name)
629 v = dict_lookup(s->vars, name);
631 if(s->new_vars) break;
634 return dict_lookup(top->allvars, name);
636 static variable_t* find_slot(state_t*s, const char*name)
638 if(s->method && s->method->slots)
639 return dict_lookup(s->method->slots, name);
643 static variable_t* find_variable_safe(state_t*s, char*name)
645 variable_t* v = find_variable(s, name);
647 syntaxerror("undefined variable: %s", name);
651 static char variable_exists(char*name)
653 return dict_contains(state->vars, name);
656 static code_t*defaultvalue(code_t*c, classinfo_t*type)
658 if(TYPE_IS_INT(type)) {
659 c = abc_pushbyte(c, 0);
660 } else if(TYPE_IS_UINT(type)) {
661 c = abc_pushuint(c, 0);
662 } else if(TYPE_IS_FLOAT(type)) {
664 } else if(TYPE_IS_BOOLEAN(type)) {
665 c = abc_pushfalse(c);
667 //c = abc_pushundefined(c);
668 syntaxerror("internal error: can't generate default value for * type");
672 c = abc_coerce2(c, &m);
677 static int alloc_local()
679 return state->method->variable_count++;
682 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
685 variable_t*v = find_slot(state, name);
691 v->index = alloc_local();
696 dict_put(state->vars, name, v);
697 dict_put(state->allvars, name, v);
702 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
704 return new_variable2(name, type, init, maybeslot)->index;
707 #define TEMPVARNAME "__as3_temp__"
710 variable_t*v = find_variable(state, TEMPVARNAME);
715 i = new_variable(TEMPVARNAME, 0, 0, 0);
720 static code_t* var_block(code_t*body)
726 for(t=0;t<state->vars->hashsize;t++) {
727 dictentry_t*e = state->vars->slots[t];
729 variable_t*v = (variable_t*)e->data;
730 if(v->type && v->init) {
731 c = defaultvalue(c, v->type);
732 c = abc_setlocal(c, v->index);
733 k = abc_kill(k, v->index);
743 if(x->opcode== OPCODE___BREAK__ ||
744 x->opcode== OPCODE___CONTINUE__) {
745 /* link kill code before break/continue */
746 code_t*e = code_dup(k);
747 code_t*s = code_start(e);
759 c = code_append(c, body);
760 c = code_append(c, k);
764 static void unknown_variable(char*name)
766 if(!state->method->unresolved_variables)
767 state->method->unresolved_variables = dict_new();
768 if(!dict_contains(state->method->unresolved_variables, name))
769 dict_put(state->method->unresolved_variables, name, 0);
772 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
774 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
775 c = abc_getlocal_0(c);
776 c = abc_pushscope(c);
779 /* FIXME: this alloc_local() causes variable indexes to be
780 different in pass2 than in pass1 */
781 if(!m->activation_var) {
782 m->activation_var = alloc_local();
785 c = abc_newactivation(c);
787 c = abc_pushscope(c);
788 c = abc_setlocal(c, m->activation_var);
790 c = abc_getlocal(c, m->activation_var);
791 c = abc_pushscope(c);
797 static code_t* method_header(methodstate_t*m)
801 c = add_scope_code(c, m, 1);
803 methodstate_list_t*l = m->innerfunctions;
805 parserassert(l->methodstate->abc);
806 if(m->uses_slots && l->methodstate->is_a_slot) {
807 c = abc_getscopeobject(c, 1);
808 c = abc_newfunction(c, l->methodstate->abc);
810 c = abc_setlocal(c, l->methodstate->var_index);
811 c = abc_setslot(c, l->methodstate->slot_index);
813 c = abc_newfunction(c, l->methodstate->abc);
814 c = abc_setlocal(c, l->methodstate->var_index);
816 free(l->methodstate);l->methodstate=0;
820 c = code_append(c, m->header);
823 if(m->is_constructor && !m->has_super) {
824 // call default constructor
825 c = abc_getlocal_0(c);
826 c = abc_constructsuper(c, 0);
830 /* all parameters that are used by inner functions
831 need to be copied from local to slot */
832 parserassert(m->activation_var);
833 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
834 if(v->is_parameter) {
835 c = abc_getlocal(c, m->activation_var);
836 c = abc_getlocal(c, v->index);
837 c = abc_setslot(c, v->index);
841 list_free(m->innerfunctions);
842 m->innerfunctions = 0;
847 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
849 c = code_append(c, header);
850 c = code_append(c, var_block(body));
851 /* append return if necessary */
852 if(!c || (c->opcode != OPCODE_RETURNVOID &&
853 c->opcode != OPCODE_RETURNVALUE)) {
854 c = abc_returnvoid(c);
859 static void startpackage(char*name)
862 state->package = strdup(name);
864 static void endpackage()
866 //used e.g. in classinfo_register:
867 //free(state->package);state->package=0;
871 #define FLAG_PUBLIC 256
872 #define FLAG_PROTECTED 512
873 #define FLAG_PRIVATE 1024
874 #define FLAG_PACKAGEINTERNAL 2048
875 #define FLAG_NAMESPACE 4096
877 static namespace_t modifiers2access(modifiers_t*mod)
882 if(mod->flags&FLAG_NAMESPACE) {
883 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
884 syntaxerror("invalid combination of access levels and namespaces");
885 ns.access = ACCESS_NAMESPACE;
887 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
889 /* shouldn't happen- the tokenizer only reports something as a namespace
890 if it was already registered */
891 trie_dump(active_namespaces);
892 syntaxerror("unknown namespace: %s", mod->ns);
895 } else if(mod->flags&FLAG_PUBLIC) {
896 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
897 syntaxerror("invalid combination of access levels");
898 ns.access = ACCESS_PACKAGE;
899 } else if(mod->flags&FLAG_PRIVATE) {
900 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
901 syntaxerror("invalid combination of access levels");
902 ns.access = ACCESS_PRIVATE;
903 } else if(mod->flags&FLAG_PROTECTED) {
904 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
905 syntaxerror("invalid combination of access levels");
906 ns.access = ACCESS_PROTECTED;
908 ns.access = ACCESS_PACKAGEINTERNAL;
912 static slotinfo_t* find_class(const char*name);
914 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
916 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
919 static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
924 index = new_variable("this", 0, 0, 0);
925 else if(!m->is_global)
926 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
928 index = new_variable("globalscope", 0, 0, 0);
929 parserassert(!index);
934 for(p=params->list;p;p=p->next) {
935 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
938 variable_t*v = new_variable2("arguments", TYPE_ARRAY, 0, 0);
939 if(as3_pass==2 && m->need_arguments) {
940 m->need_arguments = v->index;
945 /* as variables and slots share the same number, make sure
946 that those variable indices are reserved. It's up to the
947 optimizer to later shuffle the variables down to lower
949 m->variable_count = m->uses_slots;
953 methodstate_list_t*l = m->innerfunctions;
955 methodstate_t*m = l->methodstate;
957 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
958 m->var_index = v->index;
959 m->slot_index = v->index;
960 v->is_inner_method = m;
966 m->scope_code = add_scope_code(m->scope_code, m, 0);
969 if(as3_pass==2 && m->slots) {
970 /* exchange unresolved identifiers with the actual objects */
971 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
972 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
973 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
974 if(!type || type->kind != INFOTYPE_CLASS) {
975 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
984 char*as3_globalclass=0;
985 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
988 syntaxerror("inner classes now allowed");
993 classinfo_list_t*mlist=0;
995 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
996 syntaxerror("invalid modifier(s)");
998 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
999 syntaxerror("public and internal not supported at the same time.");
1001 if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
1002 syntaxerror("protected and static not supported at the same time.");
1004 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1005 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
1006 // all classes extend object
1007 extends = registry_getobjectclass();
1010 /* create the class name, together with the proper attributes */
1014 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
1015 access = ACCESS_PRIVATE; package = internal_filename_package;
1016 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
1017 access = ACCESS_PACKAGEINTERNAL; package = state->package;
1018 } else if(state->package!=internal_filename_package) {
1019 access = ACCESS_PACKAGE; package = state->package;
1021 syntaxerror("public classes only allowed inside a package");
1025 state->cls = rfx_calloc(sizeof(classstate_t));
1026 state->cls->init = rfx_calloc(sizeof(methodstate_t));
1027 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
1028 state->cls->static_init->is_static=FLAG_STATIC;
1029 state->cls->static_init->variable_count=1;
1030 /* notice: we make no effort to initialize the top variable (local0) here,
1031 even though it has special meaning. We just rely on the fact
1032 that pass 1 won't do anything with variables */
1034 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1036 /* set current method to constructor- all code within the class-level (except
1037 static variable initializations) will be executed during construction time */
1038 state->method = state->cls->init;
1040 if(registry_find(package, classname)) {
1041 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1043 /* build info struct */
1044 int num_interfaces = (list_length(implements));
1045 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1046 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1047 state->cls->info->superclass = extends;
1050 classinfo_list_t*l = implements;
1051 for(l=implements;l;l=l->next) {
1052 state->cls->info->interfaces[pos++] = l->classinfo;
1057 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1059 state->method = state->cls->init;
1060 parserassert(state->cls && state->cls->info);
1062 function_initvars(state->cls->init, 0, 0, 0, 1);
1063 function_initvars(state->cls->static_init, 0, 0, 0, 0);
1065 if(extends && (extends->flags & FLAG_FINAL))
1066 syntaxerror("Can't extend final class '%s'", extends->name);
1069 while(state->cls->info->interfaces[pos]) {
1070 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1071 syntaxerror("'%s' is not an interface",
1072 state->cls->info->interfaces[pos]->name);
1076 /* generate the abc code for this class */
1077 MULTINAME(classname2,state->cls->info);
1078 multiname_t*extends2 = sig2mname(extends);
1080 /* don't add the class to the class index just yet- that will be done later
1082 state->cls->abc = abc_class_new(0, &classname2, extends2);
1083 state->cls->abc->file = global->file;
1085 multiname_destroy(extends2);
1086 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1087 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1088 if(state->cls->info->flags&FLAG_INTERFACE) {
1089 abc_class_interface(state->cls->abc);
1092 for(mlist=implements;mlist;mlist=mlist->next) {
1093 MULTINAME(m, mlist->classinfo);
1094 abc_class_add_interface(state->cls->abc, &m);
1097 NEW(parsedclass_t,p);
1098 p->cls = state->cls->info;
1099 p->abc = state->cls->abc;
1100 list_append(global->classes, p);
1102 /* flash.display.MovieClip handling */
1103 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1104 if(state->package && state->package[0]) {
1105 as3_globalclass = concat3(state->package, ".", classname);
1107 as3_globalclass = strdup(classname);
1113 static void endclass()
1116 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1118 c = abc_getlocal_0(c);
1119 c = abc_constructsuper(c, 0);
1120 state->cls->init->header = code_append(state->cls->init->header, c);
1121 state->cls->has_constructor=1;
1123 if(state->cls->init) {
1124 if(state->cls->info->flags&FLAG_INTERFACE) {
1125 if(state->cls->init->header)
1126 syntaxerror("interface can not have class-level code");
1128 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1129 code_t*c = method_header(state->cls->init);
1130 m->body->code = wrap_function(c, 0, m->body->code);
1133 if(state->cls->static_init) {
1134 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1135 code_t*c = method_header(state->cls->static_init);
1136 m->body->code = wrap_function(c, 0, m->body->code);
1139 trait_list_t*trait = state->cls->abc->traits;
1140 /* switch all protected members to the protected ns of this class */
1142 trait_t*t = trait->trait;
1143 if(t->name->ns->access == ACCESS_PROTECTED) {
1144 if(!state->cls->abc->protectedNS) {
1145 char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
1146 state->cls->abc->protectedNS = namespace_new_protected(n);
1147 state->cls->abc->flags |= CLASS_PROTECTED_NS;
1149 t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
1151 trait = trait->next;
1158 void check_code_for_break(code_t*c)
1161 if(c->opcode == OPCODE___BREAK__) {
1162 char*name = string_cstr(c->data[0]);
1163 syntaxerror("Unresolved \"break %s\"", name);
1165 if(c->opcode == OPCODE___CONTINUE__) {
1166 char*name = string_cstr(c->data[0]);
1167 syntaxerror("Unresolved \"continue %s\"", name);
1169 if(c->opcode == OPCODE___RETHROW__) {
1170 syntaxerror("Unresolved \"rethrow\"");
1172 if(c->opcode == OPCODE___FALLTHROUGH__) {
1173 syntaxerror("Unresolved \"fallthrough\"");
1175 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1176 char*name = string_cstr(c->data[0]);
1177 syntaxerror("Can't reference a package (%s) as such", name);
1183 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1185 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1186 if(TYPE_IS_NUMBER(t)) {
1187 xassert(c->type == CONSTANT_FLOAT
1188 || c->type == CONSTANT_INT
1189 || c->type == CONSTANT_UINT);
1190 } else if(TYPE_IS_UINT(t)) {
1191 xassert(c->type == CONSTANT_UINT ||
1192 (c->type == CONSTANT_INT && c->i>=0));
1193 } else if(TYPE_IS_INT(t)) {
1194 xassert(c->type == CONSTANT_INT);
1195 } else if(TYPE_IS_BOOLEAN(t)) {
1196 xassert(c->type == CONSTANT_TRUE
1197 || c->type == CONSTANT_FALSE);
1201 static void check_override(memberinfo_t*m, int flags)
1205 if(m->parent == state->cls->info)
1206 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1208 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1209 if(m->access==ACCESS_PRIVATE)
1211 if(m->flags & FLAG_FINAL)
1212 syntaxerror("can't override final member %s", m->name);
1214 /* allow this. it's no issue.
1215 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1216 syntaxerror("can't override static member %s", m->name);*/
1218 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1219 syntaxerror("can't override non-static member %s with static declaration", m->name);
1221 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1222 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1223 if(m->kind == INFOTYPE_METHOD)
1224 syntaxerror("can't override without explicit 'override' declaration");
1226 syntaxerror("can't override '%s'", m->name);
1231 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1233 methodinfo_t*minfo = 0;
1234 namespace_t ns = modifiers2access(mod);
1237 minfo = methodinfo_register_global(ns.access, state->package, name);
1238 minfo->return_type = return_type;
1239 } else if(getset != KW_GET && getset != KW_SET) {
1241 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1243 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1245 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1246 minfo->return_type = return_type;
1247 // getslot on a member slot only returns "undefined", so no need
1248 // to actually store these
1249 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1251 //class getter/setter
1252 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1254 if(getset == KW_GET) {
1256 } else if(params->list && params->list->param && !params->list->next) {
1257 type = params->list->param->type;
1259 syntaxerror("setter function needs to take exactly one argument");
1260 // not sure wether to look into superclasses here, too
1261 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1263 if(minfo->kind!=INFOTYPE_VAR)
1264 syntaxerror("class already contains a method called '%s'", name);
1265 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1266 syntaxerror("class already contains a field called '%s'", name);
1267 if(minfo->subtype & gs)
1268 syntaxerror("getter/setter for '%s' already defined", name);
1269 /* make a setter or getter into a getset */
1270 minfo->subtype |= gs;
1273 FIXME: this check needs to be done in pass 2
1275 if((!minfo->return_type != !type) ||
1276 (minfo->return_type && type &&
1277 !strcmp(minfo->return_type->name, type->name))) {
1278 syntaxerror("different type in getter and setter: %s and %s",
1279 minfo->return_type?minfo->return_type->name:"*",
1280 type?type->name:"*");
1283 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1284 minfo->kind = INFOTYPE_VAR; //hack
1285 minfo->subtype = gs;
1286 minfo->return_type = type;
1289 /* can't assign a slot as getter and setter might have different slots */
1290 //minfo->slot = slot;
1292 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1293 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1294 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1299 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1301 //parserassert(state->method && state->method->info);
1303 methodstate_t*parent_method = state->method;
1306 return_type = 0; // not valid in pass 1
1310 state->new_vars = 1;
1311 state->allvars = dict_new();
1314 state->method = rfx_calloc(sizeof(methodstate_t));
1315 state->method->inner = 1;
1316 state->method->variable_count = 0;
1317 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1319 NEW(methodinfo_t,minfo);
1320 minfo->kind = INFOTYPE_METHOD;
1321 minfo->access = ACCESS_PACKAGEINTERNAL;
1323 state->method->info = minfo;
1326 list_append(parent_method->innerfunctions, state->method);
1328 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1330 function_initvars(state->method, 1, params, 0, 1);
1334 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1335 state->method->variable_count = 0;
1336 parserassert(state->method);
1338 state->method->info->return_type = return_type;
1339 function_initvars(state->method, 1, params, 0, 1);
1343 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1344 params_t*params, classinfo_t*return_type)
1346 if(state->method && state->method->info) {
1347 syntaxerror("not able to start another method scope");
1350 state->new_vars = 1;
1351 state->allvars = dict_new();
1354 state->method = rfx_calloc(sizeof(methodstate_t));
1355 state->method->has_super = 0;
1356 state->method->is_static = mod->flags&FLAG_STATIC;
1359 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1361 state->method->is_global = 1;
1362 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1364 if(state->method->is_constructor)
1365 name = "__as3_constructor__";
1367 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1369 function_initvars(state->method, 1, params, mod->flags, 1);
1371 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1375 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1376 state->method->variable_count = 0;
1377 parserassert(state->method);
1380 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1381 check_override(m, mod->flags);
1385 state->cls->has_constructor |= state->method->is_constructor;
1388 function_initvars(state->method, 1, params, mod->flags, 1);
1392 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1393 params_t*params, classinfo_t*return_type, code_t*body)
1396 // store inner methods in variables
1397 function_initvars(state->method, 0, 0, 0, 0);
1399 methodstate_list_t*ml = state->method->innerfunctions;
1401 dict_t*xvars = dict_new();
1404 methodstate_t*m = ml->methodstate;
1405 parserassert(m->inner);
1406 if(m->unresolved_variables) {
1407 dict_t*d = m->unresolved_variables;
1409 for(t=0;t<d->hashsize;t++) {
1410 dictentry_t*l = d->slots[t];
1412 /* check parent method's variables */
1414 if((v=find_variable(state, l->key))) {
1415 m->uses_parent_function = 1;
1416 state->method->uses_slots = 1;
1417 dict_put(xvars, l->key, 0);
1424 dict_destroy(m->unresolved_variables);
1425 m->unresolved_variables = 0;
1430 if(state->method->uses_slots) {
1431 state->method->slots = dict_new();
1433 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1434 if(!name) syntaxerror("internal error");
1435 if(v->index && dict_contains(xvars, name)) {
1438 if(v->is_inner_method) {
1439 v->is_inner_method->is_a_slot = 1;
1442 dict_put(state->method->slots, name, v);
1445 state->method->uses_slots = i;
1446 dict_destroy(state->vars);state->vars = 0;
1447 parserassert(state->new_vars);
1448 dict_destroy(state->allvars);state->allvars = 0;
1455 /*if(state->method->uses_parent_function){
1456 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1461 multiname_t*type2 = sig2mname(return_type);
1463 if(state->method->inner) {
1464 f = state->method->abc;
1465 abc_method_init(f, global->file, type2, 1);
1466 } else if(state->method->is_constructor) {
1467 f = abc_class_getconstructor(state->cls->abc, type2);
1468 } else if(!state->method->is_global) {
1469 namespace_t ns = modifiers2access(mod);
1470 multiname_t mname = {QNAME, &ns, 0, name};
1471 if(mod->flags&FLAG_STATIC)
1472 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1474 f = abc_class_method(state->cls->abc, type2, &mname);
1475 slot = f->trait->slot_id;
1477 namespace_t mname_ns = {state->method->info->access, state->package};
1478 multiname_t mname = {QNAME, &mname_ns, 0, name};
1480 f = abc_method_new(global->file, type2, 1);
1481 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1482 //abc_code_t*c = global->init->method->body->code;
1484 //flash doesn't seem to allow us to access function slots
1485 //state->method->info->slot = slot;
1487 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1488 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1489 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1490 if(params->varargs) f->flags |= METHOD_NEED_REST;
1491 if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
1495 for(p=params->list;p;p=p->next) {
1496 if(params->varargs && !p->next) {
1497 break; //varargs: omit last parameter in function signature
1499 multiname_t*m = sig2mname(p->param->type);
1500 list_append(f->parameters, m);
1501 if(p->param->value) {
1502 check_constant_against_type(p->param->type, p->param->value);
1503 opt=1;list_append(f->optional_parameters, p->param->value);
1505 syntaxerror("non-optional parameter not allowed after optional parameters");
1508 if(state->method->slots) {
1509 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1511 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1512 multiname_t*type = sig2mname(v->type);
1513 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1514 t->slot_id = v->index;
1519 check_code_for_break(body);
1521 /* Seems this works now.
1522 if(state->method->exceptions && state->method->uses_slots) {
1523 as3_warning("try/catch and activation not supported yet within the same method");
1527 f->body->code = body;
1528 f->body->exceptions = state->method->exceptions;
1529 } else { //interface
1531 syntaxerror("interface methods can't have a method body");
1541 void breakjumpsto(code_t*c, char*name, code_t*jump)
1544 if(c->opcode == OPCODE___BREAK__) {
1545 string_t*name2 = c->data[0];
1546 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1547 c->opcode = OPCODE_JUMP;
1554 void continuejumpsto(code_t*c, char*name, code_t*jump)
1557 if(c->opcode == OPCODE___CONTINUE__) {
1558 string_t*name2 = c->data[0];
1559 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1560 c->opcode = OPCODE_JUMP;
1568 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1573 return abc_coerce_a(c);
1577 // cast an "any" type to a specific type. subject to
1578 // runtime exceptions
1579 return abc_coerce2(c, &m);
1582 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1583 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1584 // allow conversion between number types
1585 if(TYPE_IS_UINT(to))
1586 return abc_convert_u(c);
1587 else if(TYPE_IS_INT(to))
1588 return abc_convert_i(c);
1589 else if(TYPE_IS_NUMBER(to))
1590 return abc_convert_d(c);
1591 return abc_coerce2(c, &m);
1594 if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
1597 if(TYPE_IS_BOOLEAN(to))
1598 return abc_convert_b(c);
1599 if(TYPE_IS_STRING(to))
1600 return abc_convert_s(c);
1601 if(TYPE_IS_OBJECT(to))
1602 return abc_convert_o(c);
1604 classinfo_t*supertype = from;
1606 if(supertype == to) {
1607 // target type is one of from's superclasses
1608 return abc_coerce2(c, &m);
1611 while(supertype->interfaces[t]) {
1612 if(supertype->interfaces[t]==to) {
1613 // target type is one of from's interfaces
1614 return abc_coerce2(c, &m);
1618 supertype = supertype->superclass;
1620 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1622 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1624 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1627 as3_error("can't convert type %s%s%s to %s%s%s",
1628 from->package, from->package[0]?".":"", from->name,
1629 to->package, to->package[0]?".":"", to->name);
1633 /* move to ast.c todo end */
1635 char is_pushundefined(code_t*c)
1637 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1640 static const char* get_package_from_name(const char*name)
1642 /* try explicit imports */
1643 dictentry_t* e = dict_get_slot(state->imports, name);
1645 if(!strcmp(e->key, name)) {
1646 slotinfo_t*c = (slotinfo_t*)e->data;
1647 if(c) return c->package;
1653 static namespace_list_t*get_current_imports()
1655 namespace_list_t*searchlist = 0;
1657 list_append(searchlist, namespace_new_package(state->package));
1659 import_list_t*l = state->wildcard_imports;
1661 namespace_t*ns = namespace_new_package(l->import->package);
1662 list_append(searchlist, ns);
1665 list_append(searchlist, namespace_new_package(""));
1666 list_append(searchlist, namespace_new_package(internal_filename_package));
1670 static slotinfo_t* find_class(const char*name)
1674 c = registry_find(state->package, name);
1677 /* try explicit imports */
1678 dictentry_t* e = dict_get_slot(state->imports, name);
1681 if(!strcmp(e->key, name)) {
1682 c = (slotinfo_t*)e->data;
1688 /* try package.* imports */
1689 import_list_t*l = state->wildcard_imports;
1691 //printf("does package %s contain a class %s?\n", l->import->package, name);
1692 c = registry_find(l->import->package, name);
1697 /* try global package */
1698 c = registry_find("", name);
1701 /* try local "filename" package */
1702 c = registry_find(internal_filename_package, name);
1707 typedcode_t push_class(slotinfo_t*a)
1712 if(a->access == ACCESS_PACKAGEINTERNAL &&
1713 strcmp(a->package, state->package) &&
1714 strcmp(a->package, internal_filename_package)
1716 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1717 infotypename(a), a->name, a->package, state->package);
1720 if(a->kind != INFOTYPE_CLASS) {
1722 x.c = abc_findpropstrict2(x.c, &m);
1723 x.c = abc_getproperty2(x.c, &m);
1724 if(a->kind == INFOTYPE_METHOD) {
1725 methodinfo_t*f = (methodinfo_t*)a;
1726 x.t = TYPE_FUNCTION(f);
1728 varinfo_t*v = (varinfo_t*)a;
1732 classinfo_t*c = (classinfo_t*)a;
1734 if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
1735 x.c = abc_getglobalscope(x.c);
1736 x.c = abc_getslot(x.c, c->slot);
1739 x.c = abc_getlex2(x.c, &m);
1741 x.t = TYPE_CLASS(c);
1747 char is_break_or_jump(code_t*c)
1751 if(c->opcode == OPCODE_JUMP ||
1752 c->opcode == OPCODE___BREAK__ ||
1753 c->opcode == OPCODE___CONTINUE__ ||
1754 c->opcode == OPCODE_THROW ||
1755 c->opcode == OPCODE_RETURNVOID ||
1756 c->opcode == OPCODE_RETURNVALUE) {
1762 #define IS_FINALLY_TARGET(op) \
1763 ((op) == OPCODE___CONTINUE__ || \
1764 (op) == OPCODE___BREAK__ || \
1765 (op) == OPCODE_RETURNVOID || \
1766 (op) == OPCODE_RETURNVALUE || \
1767 (op) == OPCODE___RETHROW__)
1769 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1771 #define NEED_EXTRA_STACK_ARG
1772 code_t*finally_label = abc_nop(0);
1773 NEW(lookupswitch_t, l);
1779 code_t*prev = i->prev;
1780 if(IS_FINALLY_TARGET(i->opcode)) {
1783 if(i->opcode == OPCODE___RETHROW__ ||
1784 i->opcode == OPCODE_RETURNVALUE) {
1785 if(i->opcode == OPCODE___RETHROW__)
1786 i->opcode = OPCODE_THROW;
1788 p = abc_coerce_a(p);
1789 p = abc_setlocal(p, tempvar);
1791 p = abc_pushbyte(p, count++);
1792 p = abc_jump(p, finally_label);
1793 code_t*target = p = abc_label(p);
1794 #ifdef NEED_EXTRA_STACK_ARG
1798 p = abc_getlocal(p, tempvar);
1801 p->next = i;i->prev = p;
1802 list_append(l->targets, target);
1808 c = abc_pushbyte(c, -1);
1809 c = code_append(c, finally_label);
1810 c = code_append(c, finally);
1812 #ifdef NEED_EXTRA_STACK_ARG
1815 c = abc_lookupswitch(c, l);
1816 c = l->def = abc_label(c);
1817 #ifdef NEED_EXTRA_STACK_ARG
1824 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1828 code_t*prev = i->prev;
1829 if(IS_FINALLY_TARGET(i->opcode)) {
1830 if(i->opcode == OPCODE___RETHROW__)
1831 i->opcode = OPCODE_THROW;
1832 code_t*end = code_dup(finally);
1833 code_t*start = code_start(end);
1834 if(prev) prev->next = start;
1841 return code_append(c, finally);
1844 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1850 int num_insertion_points=0;
1852 if(IS_FINALLY_TARGET(i->opcode))
1853 num_insertion_points++;
1860 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1865 int simple_version_cost = (1+num_insertion_points)*code_size;
1866 int lookup_version_cost = 4*num_insertion_points + 5;
1868 if(cantdup || simple_version_cost > lookup_version_cost) {
1869 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1870 return insert_finally_lookup(c, finally, tempvar);
1872 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1873 return insert_finally_simple(c, finally, tempvar);
1877 #define PASS1 }} if(as3_pass == 1) {{
1878 #define PASS1END }} if(as3_pass == 2) {{
1879 #define PASS2 }} if(as3_pass == 2) {{
1880 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1881 #define PASS12END }} if(as3_pass == 2) {{
1882 #define PASS_ALWAYS }} {{
1888 /* ------------ code blocks / statements ---------------- */
1890 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1892 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1893 PROGRAM_CODE_LIST: PROGRAM_CODE
1894 | PROGRAM_CODE_LIST PROGRAM_CODE
1896 PROGRAM_CODE: PACKAGE_DECLARATION
1897 | INTERFACE_DECLARATION
1899 | FUNCTION_DECLARATION
1902 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1905 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1906 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1907 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1909 INPACKAGE_CODE: INTERFACE_DECLARATION
1911 | FUNCTION_DECLARATION
1914 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1917 MAYBECODE: CODE {$$=$1;}
1918 MAYBECODE: {$$=code_new();}
1920 CODE: CODE CODEPIECE {
1921 $$=code_append($1,$2);
1923 CODE: CODEPIECE {$$=$1;}
1925 // code which may appear outside of methods
1926 CODE_STATEMENT: IMPORT
1928 CODE_STATEMENT: FOR_IN
1929 CODE_STATEMENT: WHILE
1930 CODE_STATEMENT: DO_WHILE
1931 CODE_STATEMENT: SWITCH
1933 CODE_STATEMENT: WITH
1935 CODE_STATEMENT: VOIDEXPRESSION
1936 CODE_STATEMENT: USE_NAMESPACE
1937 CODE_STATEMENT: NAMESPACE_DECLARATION
1938 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1939 CODE_STATEMENT: '{' '}' {$$=0;}
1941 // code which may appear in methods
1942 CODEPIECE: ';' {$$=0;}
1943 CODEPIECE: CODE_STATEMENT
1944 CODEPIECE: VARIABLE_DECLARATION
1949 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
1959 //CODEBLOCK : '{' CODE '}' {$$=$2;}
1960 //CODEBLOCK : '{' '}' {$$=0;}
1961 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1962 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1964 /* ------------ package init code ------------------- */
1966 PACKAGE_INITCODE: CODE_STATEMENT {
1967 code_t**cc = &global->init->method->body->code;
1968 *cc = code_append(*cc, $1);
1971 /* ------------ conditional compilation ------------- */
1973 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
1976 char*key = concat3($1,"::",$3);
1977 if(!definitions || !dict_contains(definitions, key)) {
1983 /* ------------ variables --------------------------- */
1986 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1992 MAYBEEXPRESSION : '=' E {$$=$2;}
1993 | {$$=mkdummynode();}
1995 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1996 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1998 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1999 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
2001 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2004 if(variable_exists($1))
2005 syntaxerror("Variable %s already defined", $1);
2007 new_variable($1, 0, 1, 0);
2012 if(state->method->uses_slots) {
2013 variable_t* v = find_slot(state, $1);
2015 // this variable is stored in a slot
2023 index = new_variable($1, $2, 1, 0);
2026 $$ = slot?abc_getscopeobject(0, 1):0;
2028 typedcode_t v = node_read($3);
2029 if(!is_subtype_of(v.t, $2)) {
2030 syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
2033 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2034 $$ = code_append($$, v.c);
2035 $$ = converttype($$, v.t, $2);
2038 $$ = defaultvalue($$, $2);
2041 if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
2042 $$ = code_append($$, v.c);
2043 $$ = abc_coerce_a($$);
2045 // don't do anything
2053 $$ = abc_setslot($$, index);
2055 $$ = abc_setlocal($$, index);
2059 /* ------------ control flow ------------------------- */
2061 MAYBEELSE: %prec below_else {$$ = code_new();}
2062 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2063 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2065 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2068 $$ = code_append($$, $4.c);
2069 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2071 $$ = code_append($$, $6);
2073 myjmp = $$ = abc_jump($$, 0);
2075 myif->branch = $$ = abc_nop($$);
2077 $$ = code_append($$, $7);
2078 myjmp->branch = $$ = abc_nop($$);
2084 FOR_INIT : {$$=code_new();}
2085 FOR_INIT : VARIABLE_DECLARATION
2086 FOR_INIT : VOIDEXPRESSION
2088 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2089 // (I don't see any easy way to revolve this conflict otherwise, as we
2090 // can't touch VAR_READ without upsetting the precedence about "return")
2091 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2092 PASS1 $$=$2;new_variable($2,0,1,0);
2093 PASS2 $$=$2;new_variable($2,$3,1,0);
2095 FOR_IN_INIT : T_IDENTIFIER {
2100 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2101 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2103 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2104 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2106 $$ = code_append($$, $2);
2107 code_t*loopstart = $$ = abc_label($$);
2108 $$ = code_append($$, $4.c);
2109 code_t*myif = $$ = abc_iffalse($$, 0);
2110 $$ = code_append($$, $8);
2111 code_t*cont = $$ = abc_nop($$);
2112 $$ = code_append($$, $6);
2113 $$ = abc_jump($$, loopstart);
2114 code_t*out = $$ = abc_nop($$);
2115 breakjumpsto($$, $1.name, out);
2116 continuejumpsto($$, $1.name, cont);
2123 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2124 variable_t*var = find_variable(state, $2);
2126 syntaxerror("variable %s not known in this scope", $2);
2129 char*tmp1name = concat2($2, "__tmp1__");
2130 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2131 char*tmp2name = concat2($2, "__array__");
2132 int array = new_variable(tmp1name, 0, 0, 0);
2135 $$ = code_append($$, $4.c);
2136 $$ = abc_coerce_a($$);
2137 $$ = abc_setlocal($$, array);
2138 $$ = abc_pushbyte($$, 0);
2139 $$ = abc_setlocal($$, it);
2141 code_t*loopstart = $$ = abc_label($$);
2143 $$ = abc_hasnext2($$, array, it);
2144 code_t*myif = $$ = abc_iffalse($$, 0);
2145 $$ = abc_getlocal($$, array);
2146 $$ = abc_getlocal($$, it);
2148 $$ = abc_nextname($$);
2150 $$ = abc_nextvalue($$);
2151 $$ = converttype($$, 0, var->type);
2152 $$ = abc_setlocal($$, var->index);
2154 $$ = code_append($$, $6);
2155 $$ = abc_jump($$, loopstart);
2157 code_t*out = $$ = abc_nop($$);
2158 breakjumpsto($$, $1.name, out);
2159 continuejumpsto($$, $1.name, loopstart);
2171 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2175 code_t*myjmp = $$ = abc_jump($$, 0);
2176 code_t*loopstart = $$ = abc_label($$);
2177 $$ = code_append($$, $6);
2178 code_t*cont = $$ = abc_nop($$);
2179 myjmp->branch = cont;
2180 $$ = code_append($$, $4.c);
2181 $$ = abc_iftrue($$, loopstart);
2182 code_t*out = $$ = abc_nop($$);
2183 breakjumpsto($$, $1, out);
2184 continuejumpsto($$, $1, cont);
2190 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2192 code_t*loopstart = $$ = abc_label($$);
2193 $$ = code_append($$, $3);
2194 code_t*cont = $$ = abc_nop($$);
2195 $$ = code_append($$, $6.c);
2196 $$ = abc_iftrue($$, loopstart);
2197 code_t*out = $$ = abc_nop($$);
2198 breakjumpsto($$, $1, out);
2199 continuejumpsto($$, $1, cont);
2205 BREAK : "break" %prec prec_none {
2206 $$ = abc___break__(0, "");
2208 BREAK : "break" T_IDENTIFIER {
2209 $$ = abc___break__(0, $2);
2211 CONTINUE : "continue" %prec prec_none {
2212 $$ = abc___continue__(0, "");
2214 CONTINUE : "continue" T_IDENTIFIER {
2215 $$ = abc___continue__(0, $2);
2218 MAYBE_CASE_LIST : {$$=0;}
2219 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2220 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2221 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2222 CASE_LIST: CASE {$$=$1;}
2223 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2225 CASE: "case" E ':' MAYBECODE {
2226 $$ = abc_getlocal(0, state->switch_var);
2227 $$ = code_append($$, node_read($2).c);
2228 code_t*j = $$ = abc_ifne($$, 0);
2229 $$ = code_append($$, $4);
2230 if($$->opcode != OPCODE___BREAK__) {
2231 $$ = abc___fallthrough__($$, "");
2233 code_t*e = $$ = abc_nop($$);
2236 DEFAULT: "default" ':' MAYBECODE {
2239 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2240 $$ = node_read($4).c;
2241 $$ = abc_setlocal($$, state->switch_var);
2242 $$ = code_append($$, $7);
2244 code_t*out = $$ = abc_kill($$, state->switch_var);
2245 breakjumpsto($$, $1, out);
2247 code_t*c = $$,*lastblock=0;
2249 if(c->opcode == OPCODE_IFNE) {
2250 if(!c->next) syntaxerror("internal error in fallthrough handling");
2252 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2254 c->opcode = OPCODE_JUMP;
2255 c->branch = lastblock;
2257 /* fall through end of switch */
2258 c->opcode = OPCODE_NOP;
2268 /* ------------ try / catch /finally ---------------- */
2270 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2271 state->exception_name=$3;
2272 PASS1 new_variable($3, 0, 0, 0);
2273 PASS2 new_variable($3, $4, 0, 0);
2276 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2277 multiname_t name = {QNAME, &name_ns, 0, $3};
2279 NEW(abc_exception_t, e)
2280 e->exc_type = sig2mname($4);
2281 e->var_name = multiname_clone(&name);
2285 int i = find_variable_safe(state, $3)->index;
2286 e->target = c = abc_nop(0);
2287 c = abc_setlocal(c, i);
2288 c = code_append(c, code_dup(state->method->scope_code));
2289 c = code_append(c, $8);
2295 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2300 NEW(abc_exception_t, e)
2301 e->exc_type = 0; //all exceptions
2302 e->var_name = 0; //no name
2305 e->to = code_append(e->to, $4);
2311 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2312 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2313 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2314 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2318 list_append($$.l,$2);
2319 $$.finally = $2->to;$2->to=0;
2322 CATCH_FINALLY_LIST: FINALLY {
2326 list_append($$.l,$1);
2327 $$.finally = $1->to;$1->to=0;
2331 TRY : "try" '{' {PASS12 new_state();
2332 state->method->has_exceptions=1;
2333 state->method->late_binding=1;//for invariant scope_code
2334 } MAYBECODE '}' CATCH_FINALLY_LIST {
2335 code_t*out = abc_nop(0);
2337 code_t*start = abc_nop(0);
2338 $$ = code_append(start, $4);
2339 if(!is_break_or_jump($4)) {
2340 $$ = abc_jump($$, out);
2342 code_t*end = $$ = abc_nop($$);
2346 tmp = new_variable("__finally__", 0, 0, 0);
2348 abc_exception_list_t*l = $6.l;
2351 abc_exception_t*e = l->abc_exception;
2353 $$ = code_append($$, e->target);
2354 $$ = abc_jump($$, out);
2356 parserassert((ptroff_t)$6.finally);
2358 e->target = $$ = abc_nop($$);
2359 $$ = code_append($$, code_dup(state->method->scope_code));
2360 $$ = abc___rethrow__($$);
2368 $$ = code_append($$, out);
2370 $$ = insert_finally($$, $6.finally, tmp);
2372 list_concat(state->method->exceptions, $6.l);
2378 /* ------------ throw ------------------------------- */
2380 THROW : "throw" EXPRESSION {
2384 THROW : "throw" %prec prec_none {
2385 if(!state->exception_name)
2386 syntaxerror("re-throw only possible within a catch block");
2387 variable_t*v = find_variable(state, state->exception_name);
2389 $$=abc_getlocal($$, v->index);
2393 /* ------------ with -------------------------------- */
2395 WITH_HEAD : "with" '(' EXPRESSION ')' {
2397 if(state->method->has_exceptions) {
2398 int v = alloc_local();
2399 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2400 state->method->scope_code = abc_pushwith(state->method->scope_code);
2405 WITH : WITH_HEAD CODEBLOCK {
2406 /* remove getlocal;pushwith from scope code again */
2407 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2410 if(state->method->has_exceptions) {
2412 $$ = abc_setlocal($$, $1.number);
2414 $$ = abc_pushwith($$);
2415 $$ = code_append($$, $2);
2416 $$ = abc_popscope($$);
2420 /* ------------ packages and imports ---------------- */
2422 X_IDENTIFIER: T_IDENTIFIER
2423 | "package" {PASS12 $$="package";}
2424 | T_NAMESPACE {PASS12 $$=$1;}
2426 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2427 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2429 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2430 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2431 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2432 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2435 static void state_has_imports()
2437 state->wildcard_imports = list_clone(state->wildcard_imports);
2438 state->imports = dict_clone(state->imports);
2439 state->has_own_imports = 1;
2441 static void import_toplevel(const char*package)
2443 char* s = strdup(package);
2445 dict_put(state->import_toplevel_packages, s, 0);
2446 char*x = strrchr(s, '.');
2454 IMPORT : "import" PACKAGEANDCLASS {
2456 slotinfo_t*s = registry_find($2->package, $2->name);
2457 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2458 as3_schedule_class($2->package, $2->name);
2462 syntaxerror("Couldn't import class\n");
2463 state_has_imports();
2464 dict_put(state->imports, c->name, c);
2465 import_toplevel(c->package);
2468 IMPORT : "import" PACKAGE '.' '*' {
2470 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2471 as3_schedule_package($2);
2476 state_has_imports();
2477 list_append(state->wildcard_imports, i);
2478 import_toplevel(i->package);
2482 /* ------------ classes and interfaces (header) -------------- */
2484 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2485 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2486 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2487 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2489 $$.flags=$1.flags|$2.flags;
2490 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2491 $$.ns=$1.ns?$1.ns:$2.ns;
2494 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2495 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2496 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2497 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2498 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2499 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2500 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2501 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2502 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2503 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2507 EXTENDS : {PASS12 $$=0;}
2508 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2510 EXTENDS_LIST : {PASS12 $$=list_new();}
2511 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2513 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2514 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2516 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2517 EXTENDS IMPLEMENTS_LIST
2518 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2520 '}' {PASS12 endclass();$$=0;}
2522 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2524 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2525 startclass(&$1,$3,0,$4);}
2526 MAYBE_INTERFACE_BODY
2527 '}' {PASS12 endclass();$$=0;}
2529 /* ------------ classes and interfaces (body) -------------- */
2532 MAYBE_CLASS_BODY : CLASS_BODY
2533 CLASS_BODY : CLASS_BODY_ITEM
2534 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2535 CLASS_BODY_ITEM : ';'
2536 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2537 CLASS_BODY_ITEM : SLOT_DECLARATION
2538 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2540 CLASS_BODY_ITEM : CODE_STATEMENT {
2541 code_t*c = state->cls->static_init->header;
2542 c = code_append(c, $1);
2543 state->cls->static_init->header = c;
2546 MAYBE_INTERFACE_BODY :
2547 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2548 INTERFACE_BODY : IDECLARATION
2549 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2551 IDECLARATION : "var" T_IDENTIFIER {
2552 syntaxerror("variable declarations not allowed in interfaces");
2554 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2556 $1.flags |= FLAG_PUBLIC;
2557 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2558 syntaxerror("invalid method modifiers: interface methods always need to be public");
2560 startfunction(&$1,$3,$4,&$6,$8);
2561 endfunction(&$1,$3,$4,&$6,$8, 0);
2562 list_deep_free($6.list);
2565 /* ------------ classes and interfaces (body, slots ) ------- */
2568 static int slotstate_varconst = 0;
2569 static modifiers_t*slotstate_flags = 0;
2570 static void setslotstate(modifiers_t* flags, int varconst)
2572 slotstate_varconst = varconst;
2573 slotstate_flags = flags;
2576 if(flags->flags&FLAG_STATIC) {
2577 state->method = state->cls->static_init;
2579 state->method = state->cls->init;
2582 // reset to "default" state (all in class code is static by default) */
2583 state->method = state->cls->static_init;
2586 parserassert(state->method);
2589 static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
2591 int flags = modifiers->flags;
2592 namespace_t ns = modifiers2access(modifiers);
2595 multiname_t mname = {QNAME, &ns, 0, name};
2597 trait_list_t**traits;
2601 ns.name = state->package;
2602 traits = &global->init->traits;
2603 code = &global->init->method->body->code;
2604 } else if(flags&FLAG_STATIC) {
2606 traits = &state->cls->abc->static_traits;
2607 code = &state->cls->static_init->header;
2609 // instance variable
2610 traits = &state->cls->abc->traits;
2611 code = &state->cls->init->header;
2616 *m = *multiname_clone(&mname);
2618 return trait_new_member(traits, 0, multiname_clone(&mname), 0);
2622 VARCONST: "var" | "const"
2624 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2626 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2627 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2629 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2632 int flags = slotstate_flags->flags;
2633 namespace_t ns = modifiers2access(slotstate_flags);
2637 varinfo_t* info = 0;
2639 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2641 check_override(i, flags);
2643 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2645 slotinfo_t*i = registry_find(state->package, $1);
2647 syntaxerror("package %s already contains '%s'", state->package, $1);
2649 if(ns.name && ns.name[0]) {
2650 syntaxerror("namespaces not allowed on package-level variables");
2652 info = varinfo_register_global(ns.access, state->package, $1);
2656 info->flags = flags;
2658 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2662 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2666 trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
2670 t->type_name = multiname_clone(&m);
2672 info->slot = t->slot_id;
2674 /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1"
2675 FIXME: is there a way to use slots and still don't have conflicting overrides?
2677 info->slot = t->slot_id = 0;
2679 constant_t cval = $3->type->eval($3);
2680 if(cval.type!=CONSTANT_UNKNOWN) {
2681 /* compile time constant */
2682 t->value = malloc(sizeof(constant_t));
2683 memcpy(t->value, &cval, sizeof(constant_t));
2684 info->value = constant_clone(t->value);
2686 typedcode_t v = node_read($3);
2687 /* initalization code (if needed) */
2689 if(v.c && !is_pushundefined(v.c)) {
2690 c = abc_getlocal_0(c);
2691 c = code_append(c, v.c);
2692 c = converttype(c, v.t, $2);
2694 c = abc_initproperty2(c, &mname);
2696 c = abc_setslot(c, t->slot_id);
2699 *code = code_append(*code, c);
2702 if(slotstate_varconst==KW_CONST) {
2703 t->kind= TRAIT_CONST;
2704 info->flags |= FLAG_CONST;
2711 /* ------------ constants -------------------------------------- */
2713 MAYBECONSTANT: {$$=0;}
2714 MAYBECONSTANT: '=' E {
2715 $$ = malloc(sizeof(constant_t));
2716 *$$ = node_eval($2);
2717 if($$->type == CONSTANT_UNKNOWN) {
2718 syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
2722 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2723 CONSTANT : T_INT {$$ = constant_new_int($1);}
2725 $$ = constant_new_uint($1);
2727 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2728 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2729 CONSTANT : "true" {$$ = constant_new_true($1);}
2730 CONSTANT : "false" {$$ = constant_new_false($1);}
2731 CONSTANT : "null" {$$ = constant_new_null($1);}
2732 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2733 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2736 CONSTANT : T_IDENTIFIER {
2737 if(!strcmp($1, "NaN")) {
2738 $$ = constant_new_float(__builtin_nan(""));
2740 as3_warning("Couldn't evaluate constant value of %s", $1);
2741 $$ = constant_new_null($1);
2745 /* ---------------------------xml ------------------------------ */
2748 static int xml_level = 0;
2753 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
2754 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
2755 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
2757 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
2759 as3_warning("xml string substitution not yet supported");
2761 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
2763 as3_warning("xml string substitution not yet supported");
2766 XMLTEXT : XMLTEXT XMLEXPR1 {
2767 $$ = concat2($1, "{...}");
2769 XMLTEXT : XMLTEXT T_STRING {$$=concat2($1, string_cstr(&$2));}
2770 XMLTEXT : XMLTEXT '>' {$$=concat2($1, ">");}
2772 XML2 : XMLNODE XMLTEXT {$$=concat2($1,$2);}
2773 XML2 : XML2 XMLNODE XMLTEXT {$$=concat3($1,$2,$3);free($1);free($2);free($3);}
2775 XML_ID_OR_EXPR: T_IDENTIFIER {$$=$1;}
2776 XML_ID_OR_EXPR: XMLEXPR2 {$$=$1;}
2778 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2779 $$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
2780 free($2);free($3);free($5);free($8);
2782 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
2783 $$ = allocprintf("<%s%s/>", $2, $3);
2785 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
2786 $$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
2787 free($2);free($3);free($5);free($6);free($9);
2790 MAYBE_XMLATTRIBUTES: {$$=strdup("");}
2791 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {$$=concat2(" ",$1);}
2792 XMLATTRIBUTES: XMLATTRIBUTE {$$=$1;}
2793 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {$$=concat3($1," ",$2);free($1);free($2);}
2795 XMLATTRIBUTE: XMLEXPR2 {
2796 $$ = strdup("{...}");
2798 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
2799 char* str = string_cstr(&$3);
2800 $$ = concat2("{...}=",str);
2802 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
2803 $$ = strdup("{...}={...}");
2805 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
2806 $$ = concat2($1,"={...}");
2808 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
2809 char* str = string_cstr(&$3);
2810 $$=allocprintf("%s=\"%s\"", $1,str);
2812 free($1);free((char*)$3.str);
2815 /* ------------ classes and interfaces (body, functions) ------- */
2817 // non-vararg version
2820 memset(&$$,0,sizeof($$));
2822 MAYBE_PARAM_LIST: PARAM_LIST {
2828 MAYBE_PARAM_LIST: "..." PARAM {
2830 memset(&$$,0,sizeof($$));
2832 list_append($$.list, $2);
2834 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2838 list_append($$.list, $4);
2842 PARAM_LIST: PARAM_LIST ',' PARAM {
2845 list_append($$.list, $3);
2849 memset(&$$,0,sizeof($$));
2850 list_append($$.list, $1);
2853 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2855 $$ = rfx_calloc(sizeof(param_t));
2861 PARAM: T_IDENTIFIER MAYBECONSTANT {
2863 $$ = rfx_calloc(sizeof(param_t));
2865 $$->type = TYPE_ANY;
2873 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2874 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2877 endfunction(&$1,$3,$4,&$6,0,0);
2879 if(!state->method->info) syntaxerror("internal error");
2881 code_t*c = method_header(state->method);
2882 c = wrap_function(c, 0, $11);
2884 endfunction(&$1,$3,$4,&$6,$8,c);
2886 list_deep_free($6.list);
2890 MAYBE_IDENTIFIER: T_IDENTIFIER
2891 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2892 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2893 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2896 endfunction(0,0,$2,&$4,0,0);
2898 methodinfo_t*f = state->method->info;
2899 if(!f || !f->kind) syntaxerror("internal error");
2901 code_t*c = method_header(state->method);
2902 c = wrap_function(c, 0, $9);
2904 int index = state->method->var_index;
2905 endfunction(0,0,$2,&$4,$6,c);
2907 $$.c = abc_getlocal(0, index);
2908 $$.t = TYPE_FUNCTION(f);
2910 PASS12 list_deep_free($4.list);
2914 /* ------------- package + class ids --------------- */
2916 CLASS: X_IDENTIFIER {
2917 PASS1 NEW(unresolvedinfo_t,c);
2918 memset(c, 0, sizeof(*c));
2919 c->kind = INFOTYPE_UNRESOLVED;
2921 c->package = get_package_from_name($1);
2923 c->nsset = get_current_imports();
2924 /* make the compiler look for this class in the current directory,
2926 as3_schedule_class_noerror(state->package, $1);
2928 $$ = (classinfo_t*)c;
2930 slotinfo_t*s = find_class($1);
2931 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2932 $$ = (classinfo_t*)s;
2935 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2936 PASS1 NEW(unresolvedinfo_t,c);
2937 memset(c, 0, sizeof(*c));
2938 c->kind = INFOTYPE_UNRESOLVED;
2941 $$ = (classinfo_t*)c;
2943 slotinfo_t*s = registry_find($1, $3);
2944 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2946 $$ = (classinfo_t*)s;
2949 CLASS_SPEC: PACKAGEANDCLASS
2952 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2953 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2955 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2956 | '*' {PASS12 $$=TYPE_ANY;}
2957 | "void" {PASS12 $$=TYPE_VOID;}
2959 | "String" {$$=registry_getstringclass();}
2960 | "int" {$$=registry_getintclass();}
2961 | "uint" {$$=registry_getuintclass();}
2962 | "Boolean" {$$=registry_getbooleanclass();}
2963 | "Number" {$$=registry_getnumberclass();}
2966 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2967 MAYBETYPE: {PASS12 $$=0;}
2969 /* ----------function calls, delete, constructor calls ------ */
2971 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
2972 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2974 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
2975 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2976 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2978 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
2982 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
2983 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
2984 $$.number= $1.number+1;
2985 $$.cc = code_append($1.cc, $2.c);
2989 NEW : "new" E XX MAYBE_PARAM_VALUES {
2990 typedcode_t v = node_read($2);
2992 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2994 code_t*paramcode = $4.cc;
2995 if($$.c->opcode == OPCODE_GETPROPERTY) {
2996 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2997 $$.c = code_cutlast($$.c);
2998 $$.c = code_append($$.c, paramcode);
2999 $$.c = abc_constructprop2($$.c, name, $4.number);
3000 multiname_destroy(name);
3001 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3003 classinfo_t*c = v.t->data;
3005 $$.c = abc_findpropstrict2(0, &m);
3006 $$.c = code_append($$.c, paramcode);
3007 $$.c = abc_constructprop2($$.c, &m, $4.number);
3008 /*} else if($$.c->opcode == OPCODE_GETSLOT) {
3009 int slot = (int)(ptroff_t)$$.c->data[0];
3010 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
3011 multiname_t*name = t->name;
3012 $$.c = code_cutlast($$.c);
3013 $$.c = code_append($$.c, paramcode);
3014 $$.c = abc_constructprop2($$.c, name, $4.number);*/
3016 $$.c = code_append($$.c, paramcode);
3017 $$.c = abc_construct($$.c, $4.number);
3021 if(TYPE_IS_CLASS(v.t) && v.t->data) {
3024 $$.c = abc_coerce_a($$.c);
3029 /* TODO: use abc_call (for calling local variables),
3030 abc_callstatic (for calling own methods)
3033 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
3035 typedcode_t v = node_read($1);
3037 if($$.c->opcode == OPCODE_COERCE_A) {
3038 $$.c = code_cutlast($$.c);
3040 code_t*paramcode = $3.cc;
3043 if($$.c->opcode == OPCODE_GETPROPERTY) {
3044 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3045 $$.c = code_cutlast($$.c);
3046 $$.c = code_append($$.c, paramcode);
3047 $$.c = abc_callproperty2($$.c, name, $3.number);
3048 multiname_destroy(name);
3049 /* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
3050 int slot = (int)(ptroff_t)$$.c->data[0];
3051 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
3052 if(t->kind!=TRAIT_METHOD) {
3053 //ok: flash allows to assign closures to members.
3055 multiname_t*name = t->name;
3056 $$.c = code_cutlast($$.c);
3057 $$.c = code_append($$.c, paramcode);
3058 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
3059 $$.c = abc_callproperty2($$.c, name, $3.number);*/
3060 } else if($$.c->opcode == OPCODE_GETSUPER) {
3061 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
3062 $$.c = code_cutlast($$.c);
3063 $$.c = code_append($$.c, paramcode);
3064 $$.c = abc_callsuper2($$.c, name, $3.number);
3065 multiname_destroy(name);
3067 $$.c = abc_getglobalscope($$.c);
3068 $$.c = code_append($$.c, paramcode);
3069 $$.c = abc_call($$.c, $3.number);
3072 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
3073 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
3074 } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
3075 // calling a class is like a typecast
3076 $$.t = (classinfo_t*)v.t->data;
3078 $$.c = abc_coerce_a($$.c);
3083 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
3084 if(!state->cls) syntaxerror("super() not allowed outside of a class");
3085 if(!state->method) syntaxerror("super() not allowed outside of a function");
3086 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
3089 $$.c = abc_getlocal_0($$.c);
3091 $$.c = code_append($$.c, $3.cc);
3093 this is dependent on the control path, check this somewhere else
3094 if(state->method->has_super)
3095 syntaxerror("constructor may call super() only once");
3097 state->method->has_super = 1;
3099 $$.c = abc_constructsuper($$.c, $3.number);
3100 $$.c = abc_pushundefined($$.c);
3104 DELETE: "delete" E {
3105 typedcode_t v = node_read($2);
3107 if($$.c->opcode == OPCODE_COERCE_A) {
3108 $$.c = code_cutlast($$.c);
3110 multiname_t*name = 0;
3111 if($$.c->opcode == OPCODE_GETPROPERTY) {
3112 $$.c->opcode = OPCODE_DELETEPROPERTY;
3113 } else if($$.c->opcode == OPCODE_GETSLOT) {
3114 int slot = (int)(ptroff_t)$$.c->data[0];
3115 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
3116 $$.c = code_cutlast($$.c);
3117 $$.c = abc_deleteproperty2($$.c, name);
3119 $$.c = abc_getlocal_0($$.c);
3120 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
3121 $$.c = abc_deleteproperty2($$.c, &m);
3123 $$.t = TYPE_BOOLEAN;
3126 RETURN: "return" %prec prec_none {
3127 $$ = abc_returnvoid(0);
3129 RETURN: "return" EXPRESSION {
3131 $$ = abc_returnvalue($$);
3134 // ----------------------- expression types -------------------------------------
3136 NONCOMMAEXPRESSION : E %prec below_lt {
3139 EXPRESSION : COMMA_EXPRESSION {
3142 COMMA_EXPRESSION : E %prec below_lt {
3143 $$ = mkmultinode(&node_comma, $1);
3145 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
3146 $$ = multinode_extend($1, $3);
3148 VOIDEXPRESSION : E %prec below_minus {
3151 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt {
3153 $$ = code_append($$, node_exec($3));
3156 MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3157 MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
3159 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
3160 DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
3161 DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
3162 DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
3163 DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
3165 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
3167 $$.cc = code_append($$.cc, $1);
3168 $$.cc = code_append($$.cc, $3.c);
3171 DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
3173 $$.number = $1.number+2;
3174 $$.cc = code_append($$.cc, $3);
3175 $$.cc = code_append($$.cc, $5.c);
3178 // ----------------------- expression evaluation -------------------------------------
3180 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3181 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3182 E : NEW {$$ = mkcodenode($1);}
3183 E : DELETE {$$ = mkcodenode($1);}
3184 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3185 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
3188 $$ = mkconstnode($1);
3194 multiname_t m = {QNAME, &stdns, 0, "XML"};
3195 v.c = abc_getlex2(v.c, &m);
3196 v.c = abc_pushstring(v.c, $1);
3197 v.c = abc_construct(v.c, 1);
3206 multiname_t m = {QNAME, &stdns, 0, "RegExp"};
3208 v.c = abc_getlex2(v.c, &m);
3209 v.c = abc_pushstring(v.c, $1.pattern);
3210 v.c = abc_construct(v.c, 1);
3212 v.c = abc_getlex2(v.c, &m);
3213 v.c = abc_pushstring(v.c, $1.pattern);
3214 v.c = abc_pushstring(v.c, $1.options);
3215 v.c = abc_construct(v.c, 2);
3223 state->method->need_arguments = 1;
3226 v.c = abc_getlocal(0, state->method->need_arguments);
3232 E : '[' MAYBE_EXPRESSION_LIST ']' {
3235 v.c = code_append(v.c, $2.cc);
3236 v.c = abc_newarray(v.c, $2.number);
3237 v.t = registry_getarrayclass();
3242 E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
3245 v.c = code_append(v.c, $2.cc);
3246 v.c = abc_newobject(v.c, $2.number/2);
3247 v.t = registry_getobjectclass();
3251 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3252 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3253 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3254 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3255 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3256 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3257 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3258 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3259 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3260 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3261 E : '!' E {$$ = mknode1(&node_not, $2);}
3262 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3263 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3264 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3265 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3266 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3267 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3268 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3269 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3270 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3271 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3272 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3273 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3274 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3275 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3276 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3277 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3278 E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
3279 E : "void" E {$$ = mknode1(&node_void, $2);}
3280 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3281 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3282 E : '-' E {$$ = mknode1(&node_neg, $2);}
3283 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3284 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3285 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3286 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3287 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3288 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3289 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3290 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3291 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3292 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3293 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3294 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3295 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3296 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3298 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3299 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3300 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3301 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3303 E : "super" '.' T_IDENTIFIER
3304 { if(!state->cls->info)
3305 syntaxerror("super keyword not allowed outside a class");
3306 classinfo_t*t = state->cls->info->superclass;
3307 if(!t) t = TYPE_OBJECT;
3308 memberinfo_t*f = findmember_nsset(t, $3, 1);
3309 MEMBER_MULTINAME(m, f, $3);
3312 v.c = abc_getlocal_0(v.c);
3313 v.c = abc_getsuper2(v.c, &m);
3314 v.t = slotinfo_gettype((slotinfo_t*)f);
3318 E : '@' T_IDENTIFIER {
3320 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
3321 v.c = abc_getlex2(0, &m);
3326 E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
3329 typedcode_t v = node_read($1);
3330 typedcode_t w = node_read($5);
3332 int index = alloc_local();
3333 int result = alloc_local();
3334 int tmp = alloc_local();
3335 int xml = alloc_local();
3337 c = code_append(c, v.c);
3338 c = abc_checkfilter(c);
3339 c = abc_coerce_a(c); //hasnext2 converts to *
3340 c = abc_setlocal(c, xml);
3341 multiname_t m = {QNAME, &stdns, 0, "XMLList"};
3342 c = abc_getlex2(c, &m);
3343 c = abc_construct(c, 0);
3344 c = abc_setlocal(c, result);
3345 c = abc_pushbyte(c, 0);
3346 c = abc_setlocal(c, index);
3347 code_t*jmp = c = abc_jump(c, 0);
3348 code_t*loop = c = abc_label(c);
3349 c = abc_getlocal(c, xml);
3350 c = abc_getlocal(c, index);
3351 c = abc_nextvalue(c);
3353 c = abc_setlocal(c, tmp);
3354 c = abc_pushwith(c);
3355 c = code_append(c, w.c);
3356 c = abc_popscope(c);
3357 code_t*b = c = abc_iffalse(c, 0);
3358 c = abc_getlocal(c, result);
3359 c = abc_getlocal(c, index);
3360 c = abc_getlocal(c, tmp);
3361 multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3362 c = abc_setproperty2(c, &m2);
3363 c = b->branch = jmp->branch = abc_nop(c);
3364 c = abc_kill(c, tmp);
3365 c = abc_hasnext2(c, xml, index);
3366 c = abc_iftrue(c, loop);
3367 c = abc_getlocal(c, result);
3368 c = abc_kill(c, xml);
3369 c = abc_kill(c, result);
3370 c = abc_kill(c, index);
3380 ID_OR_NS : T_IDENTIFIER {$$=$1;}
3381 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
3382 SUBNODE: T_IDENTIFIER
3385 E : E '.' ID_OR_NS "::" SUBNODE {
3386 typedcode_t v = node_read($1);
3387 typedcode_t w = node_read(resolve_identifier($3));
3388 v.c = code_append(v.c, w.c);
3389 if(!TYPE_IS_NAMESPACE(w.t)) {
3390 as3_softwarning("%s might not be a namespace", $3);
3392 v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
3393 multiname_t m = {RTQNAME, 0, 0, $5};
3394 v.c = abc_getproperty2(v.c, &m);
3395 if(TYPE_IS_XML(v.t)) {
3398 v.c = abc_coerce_a(v.c);
3403 E : E ".." SUBNODE {
3404 typedcode_t v = node_read($1);
3405 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3406 v.c = abc_getdescendants2(v.c, &m);
3410 E : E '.' '[' E ']' {
3411 typedcode_t v = node_read($1);
3412 typedcode_t w = node_read($4);
3413 multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
3414 v.c = code_append(v.c, w.c);
3415 v.c = converttype(w.c, w.t, TYPE_STRING);
3416 v.c = abc_getproperty2(v.c, &m);
3421 E : E '.' '@' SUBNODE {
3422 typedcode_t v = node_read($1);
3423 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3424 v.c = abc_getproperty2(v.c, &m);
3428 E : E ".." '@' SUBNODE {
3429 typedcode_t v = node_read($1);
3430 multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
3431 v.c = abc_getdescendants2(v.c, &m);
3435 E : E '.' '@' '[' E ']' {
3436 typedcode_t v = node_read($1);
3437 typedcode_t w = node_read($5);
3438 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3439 v.c = code_append(v.c, w.c);
3440 v.c = converttype(w.c, w.t, TYPE_STRING);
3441 v.c = abc_getproperty2(v.c, &m);
3445 E : E ".." '@' '[' E ']' {
3446 typedcode_t v = node_read($1);
3447 typedcode_t w = node_read($5);
3448 multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
3449 v.c = code_append(v.c, w.c);
3450 v.c = converttype(w.c, w.t, TYPE_STRING);
3451 v.c = abc_getdescendants2(v.c, &m);
3456 MEMBER : E '.' SUBNODE {
3457 typedcode_t v1 = node_read($1);
3459 classinfo_t*t = v1.t;
3461 if(TYPE_IS_CLASS(t) && t->data) {
3465 if(TYPE_IS_XML(t)) {
3466 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3467 $$.c = abc_getproperty2($$.c, &m);
3468 $$.c = abc_coerce_a($$.c);
3469 $$.t = TYPE_XMLLIST;
3471 if(t->subtype==INFOTYPE_UNRESOLVED) {
3472 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3474 memberinfo_t*f = findmember_nsset(t, $3, 1);
3476 if(f && !is_static != !(f->flags&FLAG_STATIC))
3478 if(f && f->slot && !noslot) {
3479 $$.c = abc_getslot($$.c, f->slot);
3482 as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
3484 MEMBER_MULTINAME(m, f, $3);
3485 $$.c = abc_getproperty2($$.c, &m);
3487 /* determine type */
3488 $$.t = slotinfo_gettype((slotinfo_t*)f);
3490 $$.c = abc_coerce_a($$.c);
3492 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3493 string_t*package = v1.c->data[0];
3494 char*package2 = concat3(package->str, ".", $3);
3496 slotinfo_t*a = registry_find(package->str, $3);
3499 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3500 registry_ispackage(package2)) {
3502 $$.c->data[0] = string_new4(package2);
3505 syntaxerror("couldn't resolve %s", package2);
3508 /* when resolving a property on an unknown type, we do know the
3509 name of the property (and don't seem to need the package), but
3510 we need to make avm2 try out all access modes */
3511 as3_softwarning("Resolving %s on unknown type", $3);
3512 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3513 $$.c = abc_getproperty2($$.c, &m);
3514 $$.c = abc_coerce_a($$.c);
3520 node_t* resolve_identifier(char*name)
3530 /* look at variables */
3531 if((v = find_variable(state, name))) {
3532 // name is a local variable
3533 o.c = abc_getlocal(o.c, v->index);
3535 return mkcodenode(o);
3537 if((v = find_slot(state, name))) {
3538 o.c = abc_getscopeobject(o.c, 1);
3539 o.c = abc_getslot(o.c, v->index);
3541 return mkcodenode(o);
3544 int i_am_static = state->method->is_static;
3546 /* look at current class' members */
3547 if(!state->method->inner &&
3548 !state->xmlfilter &&
3550 (f = findmember_nsset(state->cls->info, name, 1)))
3552 // name is a member or attribute in this class
3553 int var_is_static = (f->flags&FLAG_STATIC);
3555 if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
3556 /* if the variable is a constant (and we know what is evaluates to), we
3557 can just use the value itself */
3558 varinfo_t*v = (varinfo_t*)f;
3560 return mkconstnode(v->value);
3564 if(var_is_static >= i_am_static) {
3565 if(f->kind == INFOTYPE_METHOD) {
3566 o.t = TYPE_FUNCTION(f);
3571 if(var_is_static && !i_am_static) {
3572 /* access to a static member from a non-static location.
3573 do this via findpropstrict:
3574 there doesn't seem to be any non-lookup way to access
3575 static properties of a class */
3576 state->method->late_binding = 1;
3578 namespace_t ns = {f->access, f->package};
3579 multiname_t m = {QNAME, &ns, 0, name};
3580 o.c = abc_findpropstrict2(o.c, &m);
3581 o.c = abc_getproperty2(o.c, &m);
3582 return mkcodenode(o);
3583 } else if(f->slot>0) {
3584 o.c = abc_getlocal_0(o.c);
3585 o.c = abc_getslot(o.c, f->slot);
3586 return mkcodenode(o);
3588 MEMBER_MULTINAME(m, f, name);
3589 o.c = abc_getlocal_0(o.c);
3590 o.c = abc_getproperty2(o.c, &m);
3591 return mkcodenode(o);
3596 /* look at actual classes, in the current package and imported */
3597 if(!state->xmlfilter && (a = find_class(name))) {
3598 if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
3599 o.c = abc_getlocal_0(0);
3600 o.t = TYPE_CLASS((classinfo_t*)a);
3604 return mkcodenode(o);
3607 /* look through package prefixes */
3608 if(!state->xmlfilter &&
3609 (dict_contains(state->import_toplevel_packages, name) ||
3610 registry_ispackage(name))) {
3611 o.c = abc___pushpackage__(o.c, name);
3613 return mkcodenode(o); //?
3616 /* unknown object, let the avm2 resolve it */
3618 if(!state->method->inner && !state->xmlfilter) {
3619 /* we really should make inner functions aware of the class context */
3620 as3_warning("Couldn't resolve '%s', doing late binding", name);
3622 state->method->late_binding = 1;
3624 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
3627 o.c = abc_findpropstrict2(o.c, &m);
3628 o.c = abc_getproperty2(o.c, &m);
3629 return mkcodenode(o);
3634 VAR_READ : T_IDENTIFIER {
3636 /* Queue unresolved identifiers for checking against the parent
3637 function's variables.
3638 We consider everything which is not a local variable "unresolved".
3639 This encompasses class names, members of the surrounding class
3640 etc. which is *correct* because local variables of the parent function
3644 if(!find_variable(state, $1)) {
3645 if(state->method->inner) {
3646 unknown_variable($1);
3648 /* let the compiler know that it might want to check the current directory/package
3649 for this identifier- maybe there's a file $1.as defining $1. */
3650 as3_schedule_class_noerror(state->package, $1);
3656 $$ = resolve_identifier($1);
3659 // ----------------- namespaces -------------------------------------------------
3662 void add_active_url(const char*url)
3666 list_append(state->active_namespace_urls, n);
3670 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3672 NEW(namespace_decl_t,n);
3677 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3679 NEW(namespace_decl_t,n);
3684 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3686 NEW(namespace_decl_t,n);
3691 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3693 trie_put(active_namespaces, $2->name, (void*)$2->url);
3695 namespace_t access = modifiers2access(&$1);
3696 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3697 var->type = TYPE_NAMESPACE;
3699 ns.access = ACCESS_NAMESPACE;
3701 var->value = constant_new_namespace(&ns);
3704 MULTINAME(m, TYPE_NAMESPACE);
3705 trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
3706 t->value = var->value;
3707 t->type_name = multiname_clone(&m);
3713 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3715 const char*url = $3->name;
3717 varinfo_t*s = (varinfo_t*)$3;
3718 if(s->kind == INFOTYPE_UNRESOLVED) {
3719 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3721 syntaxerror("Couldn't resolve namespace %s", $3->name);
3724 if(!s || s->kind != INFOTYPE_VAR)
3725 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3726 if(!s->value || !NS_TYPE(s->value->type))
3727 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3728 url = s->value->ns->name;
3730 trie_put(active_namespaces, $3->name, (void*)url);
3731 add_active_url(url);