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"
47 enum yytokentype token;
49 classinfo_t*classinfo;
50 classinfo_list_t*classinfo_list;
52 slotinfo_list_t*slotinfo_list;
55 unsigned int number_uint;
59 //typedcode_list_t*value_list;
60 codeandnumber_t value_list;
66 for_start_t for_start;
67 abc_exception_t *exception;
70 namespace_decl_t* namespace_decl;
73 abc_exception_list_t *l;
79 %token<id> T_IDENTIFIER T_NAMESPACE
81 %token<regexp> T_REGEXP
83 %token<number_int> T_INT
84 %token<number_uint> T_UINT
85 %token<number_float> T_FLOAT
87 %token<id> T_FOR "for"
88 %token<id> T_WHILE "while"
90 %token<id> T_SWITCH "switch"
92 %token<token> KW_IMPLEMENTS "implements"
93 %token<token> KW_NAMESPACE "namespace"
94 %token<token> KW_PACKAGE "package"
95 %token<token> KW_PROTECTED "protected"
96 %token<token> KW_PUBLIC "public"
97 %token<token> KW_PRIVATE "private"
98 %token<token> KW_USE "use"
99 %token<token> KW_INTERNAL "internal"
100 %token<token> KW_NEW "new"
101 %token<token> KW_NATIVE "native"
102 %token<token> KW_FUNCTION "function"
103 %token<token> KW_FINALLY "finally"
104 %token<token> KW_UNDEFINED "undefined"
105 %token<token> KW_NAN "NaN"
106 %token<token> KW_CONTINUE "continue"
107 %token<token> KW_CLASS "class"
108 %token<token> KW_CONST "const"
109 %token<token> KW_CATCH "catch"
110 %token<token> KW_CASE "case"
111 %token<token> KW_SET "set"
112 %token<token> KW_VOID "void"
113 %token<token> KW_THROW "throw"
114 %token<token> KW_STATIC "static"
115 %token<token> KW_WITH "with"
116 %token<token> KW_INSTANCEOF "instanceof"
117 %token<token> KW_IMPORT "import"
118 %token<token> KW_RETURN "return"
119 %token<token> KW_TYPEOF "typeof"
120 %token<token> KW_INTERFACE "interface"
121 %token<token> KW_NULL "null"
122 %token<token> KW_VAR "var"
123 %token<token> KW_DYNAMIC "dynamic"
124 %token<token> KW_OVERRIDE "override"
125 %token<token> KW_FINAL "final"
126 %token<token> KW_EACH "each"
127 %token<token> KW_GET "get"
128 %token<token> KW_TRY "try"
129 %token<token> KW_SUPER "super"
130 %token<token> KW_EXTENDS "extends"
131 %token<token> KW_FALSE "false"
132 %token<token> KW_TRUE "true"
133 %token<token> KW_BOOLEAN "Boolean"
134 %token<token> KW_UINT "uint"
135 %token<token> KW_INT "int"
136 %token<token> KW_NUMBER "Number"
137 %token<token> KW_STRING "String"
138 %token<token> KW_DEFAULT "default"
139 %token<token> KW_DELETE "delete"
140 %token<token> KW_IF "if"
141 %token<token> KW_ELSE "else"
142 %token<token> KW_BREAK "break"
143 %token<token> KW_IS "is"
144 %token<token> KW_IN "in"
145 %token<token> KW_AS "as"
147 %token<token> T_DICTSTART "{ (dictionary)"
148 %token<token> T_EQEQ "=="
149 %token<token> T_EQEQEQ "==="
150 %token<token> T_NE "!="
151 %token<token> T_NEE "!=="
152 %token<token> T_LE "<="
153 %token<token> T_GE ">="
154 %token<token> T_ORBY "|="
155 %token<token> T_DIVBY "/="
156 %token<token> T_MODBY "%="
157 %token<token> T_MULBY "*="
158 %token<token> T_ANDBY "&="
159 %token<token> T_PLUSBY "+="
160 %token<token> T_MINUSBY "-="
161 %token<token> T_XORBY "^="
162 %token<token> T_SHRBY ">>="
163 %token<token> T_SHLBY "<<="
164 %token<token> T_USHRBY ">>>="
165 %token<token> T_OROR "||"
166 %token<token> T_ANDAND "&&"
167 %token<token> T_COLONCOLON "::"
168 %token<token> T_MINUSMINUS "--"
169 %token<token> T_PLUSPLUS "++"
170 %token<token> T_DOTDOT ".."
171 %token<token> T_DOTDOTDOT "..."
172 %token<token> T_SHL "<<"
173 %token<token> T_USHR ">>>"
174 %token<token> T_SHR ">>"
176 %type <number_int> CONDITIONAL_COMPILATION
177 %type <for_start> FOR_START
178 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
179 %type <namespace_decl> NAMESPACE_ID
180 %type <token> VARCONST
182 %type <code> CODEPIECE CODE_STATEMENT
183 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
184 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
185 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
186 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
187 %type <exception> CATCH FINALLY
188 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
189 %type <code> CLASS_DECLARATION
190 %type <code> NAMESPACE_DECLARATION
191 %type <code> INTERFACE_DECLARATION
192 %type <code> VOIDEXPRESSION
193 %type <value> EXPRESSION NONCOMMAEXPRESSION
194 %type <value> MAYBEEXPRESSION
196 %type <node> E COMMA_EXPRESSION
197 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
198 %type <value> INNERFUNCTION
199 %type <code> USE_NAMESPACE
200 %type <code> FOR_INIT
202 %type <classinfo> MAYBETYPE
205 %type <params> PARAM_LIST
206 %type <params> MAYBE_PARAM_LIST
207 %type <flags> MAYBE_MODIFIERS
208 %type <flags> MODIFIER_LIST
209 %type <flags> MODIFIER
210 %type <constant> CONSTANT MAYBECONSTANT
211 %type <classinfo_list> IMPLEMENTS_LIST
212 %type <classinfo> EXTENDS CLASS_SPEC
213 %type <classinfo_list> EXTENDS_LIST
215 %type <classinfo> CLASS PACKAGEANDCLASS
216 %type <classinfo_list> CLASS_SPEC_LIST
218 %type <classinfo> TYPE
219 //%type <token> VARIABLE
220 %type <value> VAR_READ MEMBER
222 //%type <token> T_IDENTIFIER
223 %type <value> FUNCTIONCALL
224 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST WITH_HEAD
226 // precedence: from low to high
230 %left below_semicolon
233 %nonassoc below_assignment // for ?:, contrary to spec
234 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
241 %nonassoc "==" "!=" "===" "!=="
242 %nonassoc "is" "as" "in"
243 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
244 %left "<<" ">>" ">>>"
248 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
250 %nonassoc below_curly
254 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
257 %left above_identifier
261 // needed for "return" precedence:
262 %nonassoc T_STRING T_REGEXP
263 %nonassoc T_INT T_UINT T_FLOAT KW_NAN
264 %nonassoc "false" "true" "null" "undefined" "super" "function"
271 static int a3_error(char*s)
273 syntaxerror("%s", s);
274 return 0; //make gcc happy
277 static void parsererror(const char*file, int line, const char*f)
279 syntaxerror("internal error in %s, %s:%d", f, file, line);
282 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
285 static char* concat2(const char* t1, const char* t2)
289 char*text = malloc(l1+l2+1);
290 memcpy(text , t1, l1);
291 memcpy(text+l1, t2, l2);
295 static char* concat3(const char* t1, const char* t2, const char* t3)
300 char*text = malloc(l1+l2+l3+1);
301 memcpy(text , t1, l1);
302 memcpy(text+l1, t2, l2);
303 memcpy(text+l1+l2, t3, l3);
308 typedef struct _import {
311 DECLARE_LIST(import);
313 DECLARE(methodstate);
314 DECLARE_LIST(methodstate);
316 typedef struct _classstate {
322 methodstate_t*static_init;
324 //code_t*static_init;
326 char has_constructor;
329 struct _methodstate {
339 dict_t*unresolved_variables;
342 char uses_parent_function;
348 int var_index; // for inner methods
349 int slot_index; // for inner methods
350 char is_a_slot; // for inner methods
355 abc_exception_list_t*exceptions;
357 methodstate_list_t*innerfunctions;
360 typedef struct _state {
365 import_list_t*wildcard_imports;
366 dict_t*import_toplevel_packages;
369 namespace_list_t*active_namespace_urls;
371 char has_own_imports;
372 char new_vars; // e.g. transition between two functions
375 methodstate_t*method;
384 typedef struct _global {
388 dict_t*file2token2info;
391 static global_t*global = 0;
392 static state_t* state = 0;
396 #define MULTINAME(m,x) \
400 registry_fill_multiname(&m, &m##_ns, (slotinfo_t*)(x));
402 #define MEMBER_MULTINAME(m,f,n) \
406 if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
407 m##_ns.name = ((slotinfo_t*)(f))->package; \
412 m.namespace_set = 0; \
413 m.name = ((slotinfo_t*)(f))->name; \
415 m.type = MULTINAME; \
417 m.namespace_set = &nopackage_namespace_set; \
421 /* warning: list length of namespace set is undefined */
422 #define MULTINAME_LATE(m, access, package) \
423 namespace_t m##_ns = {access, package}; \
424 namespace_set_t m##_nsset; \
425 namespace_list_t m##_l;m##_l.next = 0; \
426 m##_nsset.namespaces = &m##_l; \
427 m##_nsset = m##_nsset; \
428 m##_l.namespace = &m##_ns; \
429 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
431 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
432 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
433 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
434 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
435 static namespace_list_t nl4 = {&ns4,0};
436 static namespace_list_t nl3 = {&ns3,&nl4};
437 static namespace_list_t nl2 = {&ns2,&nl3};
438 static namespace_list_t nl1 = {&ns1,&nl2};
439 static namespace_set_t nopackage_namespace_set = {&nl1};
441 static dict_t*definitions=0;
442 void as3_set_define(const char*c)
445 definitions = dict_new();
446 if(!dict_contains(definitions,c))
447 dict_put(definitions,c,0);
450 static void new_state()
453 state_t*oldstate = state;
455 memcpy(s, state, sizeof(state_t)); //shallow copy
457 s->imports = dict_new();
459 if(!s->import_toplevel_packages) {
460 s->import_toplevel_packages = dict_new();
464 state->has_own_imports = 0;
465 state->vars = dict_new();
466 state->old = oldstate;
469 trie_remember(active_namespaces);
472 state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
475 static void state_destroy(state_t*state)
477 if(state->has_own_imports) {
478 list_free(state->wildcard_imports);
479 dict_destroy(state->imports);state->imports=0;
481 if(state->imports && (!state->old || state->old->imports!=state->imports)) {
482 dict_destroy(state->imports);state->imports=0;
486 for(t=0;t<state->vars->hashsize;t++) {
487 dictentry_t*e =state->vars->slots[t];
489 free(e->data);e->data=0;
493 dict_destroy(state->vars);state->vars=0;
496 list_free(state->active_namespace_urls)
497 state->active_namespace_urls = 0;
502 static void old_state()
504 trie_rollback(active_namespaces);
506 if(!state || !state->old)
507 syntaxerror("invalid nesting");
508 state_t*leaving = state;
512 if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
513 free(leaving->method);
516 if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
521 state_destroy(leaving);
524 static code_t* method_header(methodstate_t*m);
525 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
526 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
529 static char* internal_filename_package = 0;
530 void initialize_file(char*filename)
533 syntaxerror("invalid call to initialize_file during parsing of another file");
536 active_namespaces = trie_new();
539 state->package = internal_filename_package = strdup(filename);
541 global->token2info = dict_lookup(global->file2token2info,
542 current_filename // use long version
544 if(!global->token2info) {
545 global->token2info = dict_new2(&ptr_type);
546 dict_put(global->file2token2info, current_filename, global->token2info);
550 state->method = rfx_calloc(sizeof(methodstate_t));
551 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
552 state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
554 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
556 syntaxerror("internal error: skewed tokencount");
557 function_initvars(state->method, 0, 0, 1);
558 global->init = abc_initscript(global->file);
564 if(!state || state->level!=1) {
565 syntaxerror("unexpected end of file in pass %d", as3_pass);
569 dict_del(global->file2token2info, current_filename);
571 code_t*header = method_header(state->method);
572 code_t*c = wrap_function(header, 0, global->init->method->body->code);
573 global->init->method->body->code = c;
574 free(state->method);state->method=0;
577 //free(state->package);state->package=0; // used in registry
578 state_destroy(state);state=0;
581 void initialize_parser()
583 global = rfx_calloc(sizeof(global_t));
584 global->file = abc_file_new();
585 global->file->flags &= ~ABCFILE_LAZY;
586 global->file2token2info = dict_new();
587 global->token2info = 0;
590 void* finish_parser()
592 dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
593 global->token2info=0;
597 typedef struct _variable {
602 methodstate_t*is_inner_method;
605 static variable_t* find_variable(state_t*s, char*name)
609 v = dict_lookup(s->vars, name);
611 if(s->new_vars) break;
616 static variable_t* find_slot(state_t*s, const char*name)
618 if(s->method && s->method->slots)
619 return dict_lookup(s->method->slots, name);
623 static variable_t* find_variable_safe(state_t*s, char*name)
625 variable_t* v = find_variable(s, name);
627 syntaxerror("undefined variable: %s", name);
631 static char variable_exists(char*name)
633 return dict_contains(state->vars, name);
636 static code_t*defaultvalue(code_t*c, classinfo_t*type)
638 if(TYPE_IS_INT(type)) {
639 c = abc_pushbyte(c, 0);
640 } else if(TYPE_IS_UINT(type)) {
641 c = abc_pushuint(c, 0);
642 } else if(TYPE_IS_FLOAT(type)) {
644 } else if(TYPE_IS_BOOLEAN(type)) {
645 c = abc_pushfalse(c);
647 //c = abc_pushundefined(c);
648 syntaxerror("internal error: can't generate default value for * type");
652 c = abc_coerce2(c, &m);
657 static int alloc_local()
659 return state->method->variable_count++;
662 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
665 variable_t*v = find_slot(state, name);
671 v->index = alloc_local();
676 dict_put(state->vars, name, v);
680 static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
682 return new_variable2(name, type, init, maybeslot)->index;
685 #define TEMPVARNAME "__as3_temp__"
688 variable_t*v = find_variable(state, TEMPVARNAME);
691 return new_variable(TEMPVARNAME, 0, 0, 0);
694 static code_t* var_block(code_t*body)
700 for(t=0;t<state->vars->hashsize;t++) {
701 dictentry_t*e = state->vars->slots[t];
703 variable_t*v = (variable_t*)e->data;
704 if(v->type && v->init) {
705 c = defaultvalue(c, v->type);
706 c = abc_setlocal(c, v->index);
707 k = abc_kill(k, v->index);
717 if(x->opcode== OPCODE___BREAK__ ||
718 x->opcode== OPCODE___CONTINUE__) {
719 /* link kill code before break/continue */
720 code_t*e = code_dup(k);
721 code_t*s = code_start(e);
733 c = code_append(c, body);
734 c = code_append(c, k);
738 static void unknown_variable(char*name)
740 if(!state->method->unresolved_variables)
741 state->method->unresolved_variables = dict_new();
742 if(!dict_contains(state->method->unresolved_variables, name))
743 dict_put(state->method->unresolved_variables, name, 0);
746 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
748 if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
749 c = abc_getlocal_0(c);
750 c = abc_pushscope(c);
753 /* FIXME: this alloc_local() causes variable indexes to be
754 different in pass2 than in pass1 */
755 if(!m->activation_var)
756 m->activation_var = alloc_local();
758 c = abc_newactivation(c);
760 c = abc_pushscope(c);
761 c = abc_setlocal(c, m->activation_var);
763 c = abc_getlocal(c, m->activation_var);
764 c = abc_pushscope(c);
770 static code_t* method_header(methodstate_t*m)
774 c = add_scope_code(c, m, 1);
776 methodstate_list_t*l = m->innerfunctions;
778 parserassert(l->methodstate->abc);
779 if(m->uses_slots && l->methodstate->is_a_slot) {
780 c = abc_getscopeobject(c, 1);
781 c = abc_newfunction(c, l->methodstate->abc);
783 c = abc_setlocal(c, l->methodstate->var_index);
784 c = abc_setslot(c, l->methodstate->slot_index);
786 c = abc_newfunction(c, l->methodstate->abc);
787 c = abc_setlocal(c, l->methodstate->var_index);
789 free(l->methodstate);l->methodstate=0;
793 c = code_append(c, m->header);
796 if(m->is_constructor && !m->has_super) {
797 // call default constructor
798 c = abc_getlocal_0(c);
799 c = abc_constructsuper(c, 0);
803 /* all parameters that are used by inner functions
804 need to be copied from local to slot */
805 parserassert(m->activation_var);
806 DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
807 if(v->is_parameter) {
808 c = abc_getlocal(c, m->activation_var);
809 c = abc_getlocal(c, v->index);
810 c = abc_setslot(c, v->index);
814 list_free(m->innerfunctions);
815 m->innerfunctions = 0;
820 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
822 c = code_append(c, header);
823 c = code_append(c, var_block(body));
824 /* append return if necessary */
825 if(!c || (c->opcode != OPCODE_RETURNVOID &&
826 c->opcode != OPCODE_RETURNVALUE)) {
827 c = abc_returnvoid(c);
832 static void startpackage(char*name)
835 state->package = strdup(name);
837 static void endpackage()
839 //used e.g. in classinfo_register:
840 //free(state->package);state->package=0;
844 #define FLAG_PUBLIC 256
845 #define FLAG_PROTECTED 512
846 #define FLAG_PRIVATE 1024
847 #define FLAG_PACKAGEINTERNAL 2048
848 #define FLAG_NAMESPACE 4096
850 static namespace_t modifiers2access(modifiers_t*mod)
855 if(mod->flags&FLAG_NAMESPACE) {
856 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
857 syntaxerror("invalid combination of access levels and namespaces");
858 ns.access = ACCESS_NAMESPACE;
860 const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
862 /* shouldn't happen- the tokenizer only reports something as a namespace
863 if it was already registered */
864 trie_dump(active_namespaces);
865 syntaxerror("unknown namespace: %s", mod->ns);
868 } else if(mod->flags&FLAG_PUBLIC) {
869 if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
870 syntaxerror("invalid combination of access levels");
871 ns.access = ACCESS_PACKAGE;
872 } else if(mod->flags&FLAG_PRIVATE) {
873 if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
874 syntaxerror("invalid combination of access levels");
875 ns.access = ACCESS_PRIVATE;
876 } else if(mod->flags&FLAG_PROTECTED) {
877 if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
878 syntaxerror("invalid combination of access levels");
879 ns.access = ACCESS_PROTECTED;
881 ns.access = ACCESS_PACKAGEINTERNAL;
885 static slotinfo_t* find_class(const char*name);
887 static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
889 return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
892 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
897 index = new_variable("this", 0, 0, 0);
898 else if(!m->is_global)
899 index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
901 index = new_variable("globalscope", 0, 0, 0);
904 parserassert(!index);
908 /* as variables and slots share the same number, make sure
909 that those variable indices are reserved. It's up to the
910 optimizer to later shuffle the variables down to lower
912 m->variable_count = m->uses_slots;
917 for(p=params->list;p;p=p->next) {
918 variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
923 methodstate_list_t*l = m->innerfunctions;
925 methodstate_t*m = l->methodstate;
927 variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
928 m->var_index = v->index;
929 m->slot_index = v->index;
930 v->is_inner_method = m;
936 m->scope_code = add_scope_code(m->scope_code, m, 0);
939 if(as3_pass==2 && m->slots) {
940 /* exchange unresolved identifiers with the actual objects */
941 DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
942 if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
943 classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
944 if(!type || type->kind != INFOTYPE_CLASS) {
945 syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
954 char*as3_globalclass=0;
955 static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
958 syntaxerror("inner classes now allowed");
963 classinfo_list_t*mlist=0;
965 if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
966 syntaxerror("invalid modifier(s)");
968 if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
969 syntaxerror("public and internal not supported at the same time.");
971 //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
972 if(!(mod->flags&FLAG_INTERFACE) && !extends) {
973 // all classes extend object
974 extends = registry_getobjectclass();
977 /* create the class name, together with the proper attributes */
981 if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
982 access = ACCESS_PRIVATE; package = internal_filename_package;
983 } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
984 access = ACCESS_PACKAGEINTERNAL; package = state->package;
985 } else if(state->package!=internal_filename_package) {
986 access = ACCESS_PACKAGE; package = state->package;
988 syntaxerror("public classes only allowed inside a package");
992 state->cls = rfx_calloc(sizeof(classstate_t));
993 state->cls->init = rfx_calloc(sizeof(methodstate_t));
994 state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
995 /* notice: we make no effort to initialize the top variable (local0) here,
996 even though it has special meaning. We just rely on the facat
997 that pass 1 won't do anything with variables */
999 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
1001 /* set current method to constructor- all code within the class-level (except
1002 static variable initializations) will be executed during construction time */
1003 state->method = state->cls->init;
1005 if(registry_find(package, classname)) {
1006 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
1008 /* build info struct */
1009 int num_interfaces = (list_length(implements));
1010 state->cls->info = classinfo_register(access, package, classname, num_interfaces);
1011 state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
1014 classinfo_list_t*l = implements;
1015 for(l=implements;l;l=l->next) {
1016 state->cls->info->interfaces[pos++] = l->classinfo;
1021 state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1023 state->method = state->cls->init;
1024 parserassert(state->cls && state->cls->info);
1026 function_initvars(state->cls->init, 0, 0, 1);
1027 function_initvars(state->cls->static_init, 0, 0, 0);
1029 if(extends && (extends->flags & FLAG_FINAL))
1030 syntaxerror("Can't extend final class '%s'", extends->name);
1033 while(state->cls->info->interfaces[pos]) {
1034 if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
1035 syntaxerror("'%s' is not an interface",
1036 state->cls->info->interfaces[pos]->name);
1040 /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
1041 state->cls->info->superclass = extends;
1043 /* generate the abc code for this class */
1044 MULTINAME(classname2,state->cls->info);
1045 multiname_t*extends2 = sig2mname(extends);
1047 state->cls->abc = abc_class_new(global->file, &classname2, extends2);
1048 if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
1049 if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
1050 if(state->cls->info->flags&FLAG_INTERFACE) {
1051 abc_class_interface(state->cls->abc);
1054 abc_class_protectedNS(state->cls->abc, classname);
1056 for(mlist=implements;mlist;mlist=mlist->next) {
1057 MULTINAME(m, mlist->classinfo);
1058 abc_class_add_interface(state->cls->abc, &m);
1061 /* write the construction code for this class to the global init
1063 int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
1065 abc_method_body_t*m = global->init->method->body;
1066 __ getglobalscope(m);
1067 classinfo_t*s = extends;
1072 //TODO: take a look at the current scope stack, maybe
1073 // we can re-use something
1078 multiname_t*s2 = sig2mname(s);
1080 multiname_destroy(s2);
1082 __ pushscope(m); count++;
1083 m->code = m->code->prev->prev; // invert
1085 /* continue appending after last op end */
1086 while(m->code && m->code->next) m->code = m->code->next;
1088 /* TODO: if this is one of *our* classes, we can also
1089 do a getglobalscope/getslot <nr> (which references
1090 the init function's slots) */
1092 __ getlex2(m, extends2);
1094 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
1095 stack is not the superclass */
1096 __ pushscope(m);count++;
1099 /* notice: we get a verify error #1107 if the top element on the scope
1100 stack is not the global object */
1102 __ pushscope(m);count++;
1104 __ newclass(m,state->cls->abc);
1108 __ setslot(m, slotindex);
1109 multiname_destroy(extends2);
1111 /* flash.display.MovieClip handling */
1113 if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
1114 if(state->package && state->package[0]) {
1115 as3_globalclass = concat3(state->package, ".", classname);
1117 as3_globalclass = strdup(classname);
1123 static void endclass()
1126 if(!state->cls->has_constructor && !(state->cls->info->flags&FLAG_INTERFACE)) {
1128 c = abc_getlocal_0(c);
1129 c = abc_constructsuper(c, 0);
1130 state->cls->init->header = code_append(state->cls->init->header, c);
1131 state->cls->has_constructor=1;
1133 if(state->cls->init) {
1134 if(state->cls->info->flags&FLAG_INTERFACE) {
1135 if(state->cls->init->header)
1136 syntaxerror("interface can not have class-level code");
1138 abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
1139 code_t*c = method_header(state->cls->init);
1140 m->body->code = wrap_function(c, 0, m->body->code);
1143 if(state->cls->static_init) {
1144 abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
1145 code_t*c = method_header(state->cls->static_init);
1146 m->body->code = wrap_function(c, 0, m->body->code);
1153 void check_code_for_break(code_t*c)
1156 if(c->opcode == OPCODE___BREAK__) {
1157 char*name = string_cstr(c->data[0]);
1158 syntaxerror("Unresolved \"break %s\"", name);
1160 if(c->opcode == OPCODE___CONTINUE__) {
1161 char*name = string_cstr(c->data[0]);
1162 syntaxerror("Unresolved \"continue %s\"", name);
1164 if(c->opcode == OPCODE___RETHROW__) {
1165 syntaxerror("Unresolved \"rethrow\"");
1167 if(c->opcode == OPCODE___FALLTHROUGH__) {
1168 syntaxerror("Unresolved \"fallthrough\"");
1170 if(c->opcode == OPCODE___PUSHPACKAGE__) {
1171 char*name = string_cstr(c->data[0]);
1172 syntaxerror("Can't reference a package (%s) as such", name);
1178 static void check_constant_against_type(classinfo_t*t, constant_t*c)
1180 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
1181 if(TYPE_IS_NUMBER(t)) {
1182 xassert(c->type == CONSTANT_FLOAT
1183 || c->type == CONSTANT_INT
1184 || c->type == CONSTANT_UINT);
1185 } else if(TYPE_IS_UINT(t)) {
1186 xassert(c->type == CONSTANT_UINT ||
1187 (c->type == CONSTANT_INT && c->i>=0));
1188 } else if(TYPE_IS_INT(t)) {
1189 xassert(c->type == CONSTANT_INT);
1190 } else if(TYPE_IS_BOOLEAN(t)) {
1191 xassert(c->type == CONSTANT_TRUE
1192 || c->type == CONSTANT_FALSE);
1196 static void check_override(memberinfo_t*m, int flags)
1200 if(m->parent == state->cls->info)
1201 syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
1203 syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
1204 if(m->access==ACCESS_PRIVATE)
1206 if(m->flags & FLAG_FINAL)
1207 syntaxerror("can't override final member %s", m->name);
1209 /* allow this. it's no issue.
1210 if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
1211 syntaxerror("can't override static member %s", m->name);*/
1213 if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
1214 syntaxerror("can't override non-static member %s with static declaration", m->name);
1216 if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
1217 if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
1218 if(m->kind == INFOTYPE_METHOD)
1219 syntaxerror("can't override without explicit 'override' declaration");
1221 syntaxerror("can't override '%s'", m->name);
1226 static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
1228 methodinfo_t*minfo = 0;
1229 namespace_t ns = modifiers2access(mod);
1232 minfo = methodinfo_register_global(ns.access, state->package, name);
1233 minfo->return_type = 0; // save this for pass 2
1234 } else if(getset != KW_GET && getset != KW_SET) {
1236 memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
1238 syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
1240 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1241 minfo->return_type = 0; // save this for pass 2
1242 // getslot on a member slot only returns "undefined", so no need
1243 // to actually store these
1244 //state->minfo->slot = state->method->abc->method->trait->slot_id;
1246 //class getter/setter
1247 int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
1249 if(getset == KW_GET) {
1251 } else if(params->list && params->list->param && !params->list->next) {
1252 type = params->list->param->type;
1254 syntaxerror("setter function needs to take exactly one argument");
1255 // not sure wether to look into superclasses here, too
1256 minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
1258 if(minfo->kind!=INFOTYPE_SLOT)
1259 syntaxerror("class already contains a method called '%s'", name);
1260 if(!(minfo->subtype & (SUBTYPE_GETSET)))
1261 syntaxerror("class already contains a field called '%s'", name);
1262 if(minfo->subtype & gs)
1263 syntaxerror("getter/setter for '%s' already defined", name);
1264 /* make a setter or getter into a getset */
1265 minfo->subtype |= gs;
1268 FIXME: this check needs to be done in pass 2
1270 if((!minfo->return_type != !type) ||
1271 (minfo->return_type && type &&
1272 !strcmp(minfo->return_type->name, type->name))) {
1273 syntaxerror("different type in getter and setter: %s and %s",
1274 minfo->return_type?minfo->return_type->name:"*",
1275 type?type->name:"*");
1278 minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
1279 minfo->kind = INFOTYPE_SLOT; //hack
1280 minfo->subtype = gs;
1281 minfo->return_type = 0;
1283 /* can't assign a slot as getter and setter might have different slots */
1284 //minfo->slot = slot;
1286 if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
1287 if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
1288 if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
1293 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1295 //parserassert(state->method && state->method->info);
1297 methodstate_t*parent_method = state->method;
1300 return_type = 0; // not valid in pass 1
1304 state->new_vars = 1;
1307 state->method = rfx_calloc(sizeof(methodstate_t));
1308 state->method->inner = 1;
1309 state->method->variable_count = 0;
1310 state->method->abc = rfx_calloc(sizeof(abc_method_t));
1312 NEW(methodinfo_t,minfo);
1313 minfo->kind = INFOTYPE_METHOD;
1314 minfo->access = ACCESS_PACKAGEINTERNAL;
1316 state->method->info = minfo;
1319 list_append(parent_method->innerfunctions, state->method);
1321 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1323 function_initvars(state->method, params, 0, 1);
1327 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1328 state->method->variable_count = 0;
1329 parserassert(state->method);
1331 state->method->info->return_type = return_type;
1332 function_initvars(state->method, params, 0, 1);
1336 static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1337 params_t*params, classinfo_t*return_type)
1339 if(state->method && state->method->info) {
1340 syntaxerror("not able to start another method scope");
1343 state->new_vars = 1;
1346 state->method = rfx_calloc(sizeof(methodstate_t));
1347 state->method->has_super = 0;
1350 state->method->is_constructor = !strcmp(state->cls->info->name,name);
1352 state->method->is_global = 1;
1353 state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1355 if(state->method->is_constructor)
1356 name = "__as3_constructor__";
1358 state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
1360 function_initvars(state->method, params, mod->flags, 1);
1362 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1366 state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1367 state->method->variable_count = 0;
1368 parserassert(state->method);
1371 memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
1372 check_override(m, mod->flags);
1376 state->cls->has_constructor |= state->method->is_constructor;
1379 state->method->info->return_type = return_type;
1380 function_initvars(state->method, params, mod->flags, 1);
1384 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
1385 params_t*params, classinfo_t*return_type, code_t*body)
1388 // store inner methods in variables
1389 function_initvars(state->method, 0, 0, 0);
1391 methodstate_list_t*ml = state->method->innerfunctions;
1393 dict_t*xvars = dict_new();
1396 methodstate_t*m = ml->methodstate;
1397 parserassert(m->inner);
1398 if(m->unresolved_variables) {
1399 dict_t*d = m->unresolved_variables;
1401 for(t=0;t<d->hashsize;t++) {
1402 dictentry_t*l = d->slots[t];
1404 /* check parent method's variables */
1406 if((v=find_variable(state, l->key))) {
1407 m->uses_parent_function = 1;
1408 state->method->uses_slots = 1;
1409 dict_put(xvars, l->key, 0);
1416 dict_destroy(m->unresolved_variables);
1417 m->unresolved_variables = 0;
1422 if(state->method->uses_slots) {
1423 state->method->slots = dict_new();
1425 DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
1426 if(!name) syntaxerror("internal error");
1427 if(v->index && dict_contains(xvars, name)) {
1430 if(v->is_inner_method) {
1431 v->is_inner_method->is_a_slot = 1;
1434 dict_put(state->method->slots, name, v);
1437 state->method->uses_slots = i;
1438 dict_destroy(state->vars);state->vars = 0;
1445 /*if(state->method->uses_parent_function){
1446 syntaxerror("accessing variables of parent function from inner functions not supported yet");
1451 multiname_t*type2 = sig2mname(return_type);
1453 if(state->method->inner) {
1454 f = state->method->abc;
1455 abc_method_init(f, global->file, type2, 1);
1456 } else if(state->method->is_constructor) {
1457 f = abc_class_getconstructor(state->cls->abc, type2);
1458 } else if(!state->method->is_global) {
1459 namespace_t mname_ns = modifiers2access(mod);
1460 multiname_t mname = {QNAME, &mname_ns, 0, name};
1462 if(mod->flags&FLAG_STATIC)
1463 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1465 f = abc_class_method(state->cls->abc, type2, &mname);
1466 slot = f->trait->slot_id;
1468 namespace_t mname_ns = {state->method->info->access, state->package};
1469 multiname_t mname = {QNAME, &mname_ns, 0, name};
1471 f = abc_method_new(global->file, type2, 1);
1472 trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1473 //abc_code_t*c = global->init->method->body->code;
1475 //flash doesn't seem to allow us to access function slots
1476 //state->method->info->slot = slot;
1478 if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1479 if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1480 if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1481 if(params->varargs) f->flags |= METHOD_NEED_REST;
1485 for(p=params->list;p;p=p->next) {
1486 if(params->varargs && !p->next) {
1487 break; //varargs: omit last parameter in function signature
1489 multiname_t*m = sig2mname(p->param->type);
1490 list_append(f->parameters, m);
1491 if(p->param->value) {
1492 check_constant_against_type(p->param->type, p->param->value);
1493 opt=1;list_append(f->optional_parameters, p->param->value);
1495 syntaxerror("non-optional parameter not allowed after optional parameters");
1498 if(state->method->slots) {
1499 DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
1501 multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
1502 multiname_t*type = sig2mname(v->type);
1503 trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
1504 t->slot_id = v->index;
1509 check_code_for_break(body);
1511 /* Seems this works now.
1512 if(state->method->exceptions && state->method->uses_slots) {
1513 as3_warning("try/catch and activation not supported yet within the same method");
1517 f->body->code = body;
1518 f->body->exceptions = state->method->exceptions;
1519 } else { //interface
1521 syntaxerror("interface methods can't have a method body");
1531 void breakjumpsto(code_t*c, char*name, code_t*jump)
1534 if(c->opcode == OPCODE___BREAK__) {
1535 string_t*name2 = c->data[0];
1536 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1537 c->opcode = OPCODE_JUMP;
1544 void continuejumpsto(code_t*c, char*name, code_t*jump)
1547 if(c->opcode == OPCODE___CONTINUE__) {
1548 string_t*name2 = c->data[0];
1549 if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1550 c->opcode = OPCODE_JUMP;
1558 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1560 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1565 return abc_coerce_a(c);
1569 // cast an "any" type to a specific type. subject to
1570 // runtime exceptions
1571 return abc_coerce2(c, &m);
1574 if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1575 (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1576 // allow conversion between number types
1577 if(TYPE_IS_UINT(to))
1578 return abc_convert_u(c);
1579 else if(TYPE_IS_INT(to))
1580 return abc_convert_i(c);
1581 else if(TYPE_IS_NUMBER(to))
1582 return abc_convert_d(c);
1583 return abc_coerce2(c, &m);
1586 if(TYPE_IS_BOOLEAN(to))
1587 return abc_convert_b(c);
1588 if(TYPE_IS_STRING(to))
1589 return abc_convert_s(c);
1590 if(TYPE_IS_OBJECT(to))
1591 return abc_convert_o(c);
1593 classinfo_t*supertype = from;
1595 if(supertype == to) {
1596 // target type is one of from's superclasses
1597 return abc_coerce2(c, &m);
1600 while(supertype->interfaces[t]) {
1601 if(supertype->interfaces[t]==to) {
1602 // target type is one of from's interfaces
1603 return abc_coerce2(c, &m);
1607 supertype = supertype->superclass;
1609 if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1611 if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1613 if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
1616 as3_error("can't convert type %s%s%s to %s%s%s",
1617 from->package, from->package[0]?".":"", from->name,
1618 to->package, to->package[0]?".":"", to->name);
1622 /* move to ast.c todo end */
1624 char is_pushundefined(code_t*c)
1626 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1629 static const char* get_package_from_name(const char*name)
1631 /* try explicit imports */
1632 dictentry_t* e = dict_get_slot(state->imports, name);
1634 if(!strcmp(e->key, name)) {
1635 slotinfo_t*c = (slotinfo_t*)e->data;
1636 if(c) return c->package;
1642 static namespace_list_t*get_current_imports()
1644 namespace_list_t*searchlist = 0;
1646 list_append(searchlist, namespace_new_package(state->package));
1648 import_list_t*l = state->wildcard_imports;
1650 namespace_t*ns = namespace_new_package(l->import->package);
1651 list_append(searchlist, ns);
1654 list_append(searchlist, namespace_new_package(""));
1655 list_append(searchlist, namespace_new_package(internal_filename_package));
1659 static slotinfo_t* find_class(const char*name)
1663 c = registry_find(state->package, name);
1666 /* try explicit imports */
1667 dictentry_t* e = dict_get_slot(state->imports, name);
1670 if(!strcmp(e->key, name)) {
1671 c = (slotinfo_t*)e->data;
1677 /* try package.* imports */
1678 import_list_t*l = state->wildcard_imports;
1680 //printf("does package %s contain a class %s?\n", l->import->package, name);
1681 c = registry_find(l->import->package, name);
1686 /* try global package */
1687 c = registry_find("", name);
1690 /* try local "filename" package */
1691 c = registry_find(internal_filename_package, name);
1696 typedcode_t push_class(slotinfo_t*a)
1701 if(a->access == ACCESS_PACKAGEINTERNAL &&
1702 strcmp(a->package, state->package) &&
1703 strcmp(a->package, internal_filename_package)
1705 syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
1706 infotypename(a), a->name, a->package, state->package);
1709 if(a->kind != INFOTYPE_CLASS) {
1711 x.c = abc_findpropstrict2(x.c, &m);
1712 x.c = abc_getproperty2(x.c, &m);
1713 if(a->kind == INFOTYPE_METHOD) {
1714 methodinfo_t*f = (methodinfo_t*)a;
1715 x.t = TYPE_FUNCTION(f);
1717 varinfo_t*v = (varinfo_t*)a;
1721 classinfo_t*c = (classinfo_t*)a;
1723 x.c = abc_getglobalscope(x.c);
1724 x.c = abc_getslot(x.c, c->slot);
1727 x.c = abc_getlex2(x.c, &m);
1729 x.t = TYPE_CLASS(c);
1735 char is_break_or_jump(code_t*c)
1739 if(c->opcode == OPCODE_JUMP ||
1740 c->opcode == OPCODE___BREAK__ ||
1741 c->opcode == OPCODE___CONTINUE__ ||
1742 c->opcode == OPCODE_THROW ||
1743 c->opcode == OPCODE_RETURNVOID ||
1744 c->opcode == OPCODE_RETURNVALUE) {
1750 #define IS_FINALLY_TARGET(op) \
1751 ((op) == OPCODE___CONTINUE__ || \
1752 (op) == OPCODE___BREAK__ || \
1753 (op) == OPCODE_RETURNVOID || \
1754 (op) == OPCODE_RETURNVALUE || \
1755 (op) == OPCODE___RETHROW__)
1757 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1759 #define NEED_EXTRA_STACK_ARG
1760 code_t*finally_label = abc_nop(0);
1761 NEW(lookupswitch_t, l);
1767 code_t*prev = i->prev;
1768 if(IS_FINALLY_TARGET(i->opcode)) {
1771 if(i->opcode == OPCODE___RETHROW__ ||
1772 i->opcode == OPCODE_RETURNVALUE) {
1773 if(i->opcode == OPCODE___RETHROW__)
1774 i->opcode = OPCODE_THROW;
1776 p = abc_coerce_a(p);
1777 p = abc_setlocal(p, tempvar);
1779 p = abc_pushbyte(p, count++);
1780 p = abc_jump(p, finally_label);
1781 code_t*target = p = abc_label(p);
1782 #ifdef NEED_EXTRA_STACK_ARG
1786 p = abc_getlocal(p, tempvar);
1789 p->next = i;i->prev = p;
1790 list_append(l->targets, target);
1796 c = abc_pushbyte(c, -1);
1797 c = code_append(c, finally_label);
1798 c = code_append(c, finally);
1800 #ifdef NEED_EXTRA_STACK_ARG
1803 c = abc_lookupswitch(c, l);
1804 c = l->def = abc_label(c);
1805 #ifdef NEED_EXTRA_STACK_ARG
1812 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1816 code_t*prev = i->prev;
1817 if(IS_FINALLY_TARGET(i->opcode)) {
1818 if(i->opcode == OPCODE___RETHROW__)
1819 i->opcode = OPCODE_THROW;
1820 code_t*end = code_dup(finally);
1821 code_t*start = code_start(end);
1822 if(prev) prev->next = start;
1829 return code_append(c, finally);
1832 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1838 int num_insertion_points=0;
1840 if(IS_FINALLY_TARGET(i->opcode))
1841 num_insertion_points++;
1848 if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1853 int simple_version_cost = (1+num_insertion_points)*code_size;
1854 int lookup_version_cost = 4*num_insertion_points + 5;
1856 if(cantdup || simple_version_cost > lookup_version_cost) {
1857 //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
1858 return insert_finally_lookup(c, finally, tempvar);
1860 //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
1861 return insert_finally_simple(c, finally, tempvar);
1865 #define PASS1 }} if(as3_pass == 1) {{
1866 #define PASS1END }} if(as3_pass == 2) {{
1867 #define PASS2 }} if(as3_pass == 2) {{
1868 #define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
1869 #define PASS12END }} if(as3_pass == 2) {{
1870 #define PASS_ALWAYS }} {{
1876 /* ------------ code blocks / statements ---------------- */
1878 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1880 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
1881 PROGRAM_CODE_LIST: PROGRAM_CODE
1882 | PROGRAM_CODE_LIST PROGRAM_CODE
1884 PROGRAM_CODE: PACKAGE_DECLARATION
1885 | INTERFACE_DECLARATION
1887 | FUNCTION_DECLARATION
1890 | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1893 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1894 INPACKAGE_CODE_LIST: INPACKAGE_CODE
1895 | INPACKAGE_CODE_LIST INPACKAGE_CODE
1897 INPACKAGE_CODE: INTERFACE_DECLARATION
1899 | FUNCTION_DECLARATION
1902 | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
1905 MAYBECODE: CODE {$$=$1;}
1906 MAYBECODE: {$$=code_new();}
1908 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1909 CODE: CODEPIECE {$$=$1;}
1911 // code which may appear outside of methods
1912 CODE_STATEMENT: IMPORT
1914 CODE_STATEMENT: FOR_IN
1915 CODE_STATEMENT: WHILE
1916 CODE_STATEMENT: DO_WHILE
1917 CODE_STATEMENT: SWITCH
1919 CODE_STATEMENT: WITH
1921 CODE_STATEMENT: VOIDEXPRESSION
1922 CODE_STATEMENT: USE_NAMESPACE
1923 CODE_STATEMENT: NAMESPACE_DECLARATION
1924 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1925 CODE_STATEMENT: '{' '}' {$$=0;}
1927 // code which may appear in methods
1928 CODEPIECE: ';' {$$=0;}
1929 CODEPIECE: CODE_STATEMENT
1930 CODEPIECE: VARIABLE_DECLARATION
1935 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {PASS_ALWAYS as3_pass=$1;}
1937 //CODEBLOCK : '{' CODE '}' {$$=$2;}
1938 //CODEBLOCK : '{' '}' {$$=0;}
1939 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1940 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1942 /* ------------ package init code ------------------- */
1944 PACKAGE_INITCODE: CODE_STATEMENT {
1945 code_t**cc = &global->init->method->body->code;
1946 *cc = code_append(*cc, $1);
1949 /* ------------ conditional compilation ------------- */
1951 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
1954 char*key = concat3($1,"::",$3);
1955 if(!definitions || !dict_contains(definitions, key)) {
1961 /* ------------ variables --------------------------- */
1964 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1970 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1971 | {$$.c=abc_pushundefined(0);
1975 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1976 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1978 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1979 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1981 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1984 if(variable_exists($1))
1985 syntaxerror("Variable %s already defined", $1);
1987 new_variable($1, 0, 1, 0);
1990 if(!is_subtype_of($3.t, $2)) {
1991 syntaxerror("Can't convert %s to %s", $3.t->name,
1997 if(state->method->uses_slots) {
1998 variable_t* v = find_slot(state, $1);
2000 // this variable is stored in a slot
2008 index = new_variable($1, $2, 1, 0);
2011 $$ = slot?abc_getscopeobject(0, 1):0;
2014 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2015 $$ = code_append($$, $3.c);
2016 $$ = converttype($$, $3.t, $2);
2019 $$ = defaultvalue($$, $2);
2022 if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
2023 $$ = code_append($$, $3.c);
2024 $$ = abc_coerce_a($$);
2026 // don't do anything
2034 $$ = abc_setslot($$, index);
2036 $$ = abc_setlocal($$, index);
2040 /* ------------ control flow ------------------------- */
2042 MAYBEELSE: %prec below_else {$$ = code_new();}
2043 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
2044 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
2046 IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
2049 $$ = code_append($$, $4.c);
2050 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
2052 $$ = code_append($$, $6);
2054 myjmp = $$ = abc_jump($$, 0);
2056 myif->branch = $$ = abc_nop($$);
2058 $$ = code_append($$, $7);
2059 myjmp->branch = $$ = abc_nop($$);
2065 FOR_INIT : {$$=code_new();}
2066 FOR_INIT : VARIABLE_DECLARATION
2067 FOR_INIT : VOIDEXPRESSION
2069 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
2070 // (I don't see any easy way to revolve this conflict otherwise, as we
2071 // can't touch VAR_READ without upsetting the precedence about "return")
2072 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
2073 PASS1 $$=$2;new_variable($2,0,1,0);
2074 PASS2 $$=$2;new_variable($2,$3,1,0);
2076 FOR_IN_INIT : T_IDENTIFIER {
2081 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
2082 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
2084 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
2085 if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
2087 $$ = code_append($$, $2);
2088 code_t*loopstart = $$ = abc_label($$);
2089 $$ = code_append($$, $4.c);
2090 code_t*myif = $$ = abc_iffalse($$, 0);
2091 $$ = code_append($$, $8);
2092 code_t*cont = $$ = abc_nop($$);
2093 $$ = code_append($$, $6);
2094 $$ = abc_jump($$, loopstart);
2095 code_t*out = $$ = abc_nop($$);
2096 breakjumpsto($$, $1.name, out);
2097 continuejumpsto($$, $1.name, cont);
2104 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
2105 variable_t*var = find_variable(state, $2);
2107 syntaxerror("variable %s not known in this scope", $2);
2110 char*tmp1name = concat2($2, "__tmp1__");
2111 int it = new_variable(tmp1name, TYPE_INT, 0, 0);
2112 char*tmp2name = concat2($2, "__array__");
2113 int array = new_variable(tmp1name, 0, 0, 0);
2116 $$ = code_append($$, $4.c);
2117 $$ = abc_coerce_a($$);
2118 $$ = abc_setlocal($$, array);
2119 $$ = abc_pushbyte($$, 0);
2120 $$ = abc_setlocal($$, it);
2122 code_t*loopstart = $$ = abc_label($$);
2124 $$ = abc_hasnext2($$, array, it);
2125 code_t*myif = $$ = abc_iffalse($$, 0);
2126 $$ = abc_getlocal($$, array);
2127 $$ = abc_getlocal($$, it);
2129 $$ = abc_nextname($$);
2131 $$ = abc_nextvalue($$);
2132 $$ = converttype($$, 0, var->type);
2133 $$ = abc_setlocal($$, var->index);
2135 $$ = code_append($$, $6);
2136 $$ = abc_jump($$, loopstart);
2138 code_t*out = $$ = abc_nop($$);
2139 breakjumpsto($$, $1.name, out);
2140 continuejumpsto($$, $1.name, loopstart);
2152 WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
2156 code_t*myjmp = $$ = abc_jump($$, 0);
2157 code_t*loopstart = $$ = abc_label($$);
2158 $$ = code_append($$, $6);
2159 code_t*cont = $$ = abc_nop($$);
2160 myjmp->branch = cont;
2161 $$ = code_append($$, $4.c);
2162 $$ = abc_iftrue($$, loopstart);
2163 code_t*out = $$ = abc_nop($$);
2164 breakjumpsto($$, $1, out);
2165 continuejumpsto($$, $1, cont);
2171 DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
2173 code_t*loopstart = $$ = abc_label($$);
2174 $$ = code_append($$, $3);
2175 code_t*cont = $$ = abc_nop($$);
2176 $$ = code_append($$, $6.c);
2177 $$ = abc_iftrue($$, loopstart);
2178 code_t*out = $$ = abc_nop($$);
2179 breakjumpsto($$, $1, out);
2180 continuejumpsto($$, $1, cont);
2186 BREAK : "break" %prec prec_none {
2187 $$ = abc___break__(0, "");
2189 BREAK : "break" T_IDENTIFIER {
2190 $$ = abc___break__(0, $2);
2192 CONTINUE : "continue" %prec prec_none {
2193 $$ = abc___continue__(0, "");
2195 CONTINUE : "continue" T_IDENTIFIER {
2196 $$ = abc___continue__(0, $2);
2199 MAYBE_CASE_LIST : {$$=0;}
2200 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2201 MAYBE_CASE_LIST : DEFAULT {$$=$1;}
2202 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2203 CASE_LIST: CASE {$$=$1;}
2204 CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
2206 CASE: "case" E ':' MAYBECODE {
2207 $$ = abc_getlocal(0, state->switch_var);
2208 $$ = code_append($$, node_read($2).c);
2209 code_t*j = $$ = abc_ifne($$, 0);
2210 $$ = code_append($$, $4);
2211 if($$->opcode != OPCODE___BREAK__) {
2212 $$ = abc___fallthrough__($$, "");
2214 code_t*e = $$ = abc_nop($$);
2217 DEFAULT: "default" ':' MAYBECODE {
2220 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
2221 $$ = node_read($4).c;
2222 $$ = abc_setlocal($$, state->switch_var);
2223 $$ = code_append($$, $7);
2225 code_t*out = $$ = abc_kill($$, state->switch_var);
2226 breakjumpsto($$, $1, out);
2228 code_t*c = $$,*lastblock=0;
2230 if(c->opcode == OPCODE_IFNE) {
2231 if(!c->next) syntaxerror("internal error in fallthrough handling");
2233 } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2235 c->opcode = OPCODE_JUMP;
2236 c->branch = lastblock;
2238 /* fall through end of switch */
2239 c->opcode = OPCODE_NOP;
2249 /* ------------ try / catch /finally ---------------- */
2251 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
2252 state->exception_name=$3;
2253 PASS1 new_variable($3, 0, 0, 0);
2254 PASS2 new_variable($3, $4, 0, 0);
2257 namespace_t name_ns = {ACCESS_PACKAGE, ""};
2258 multiname_t name = {QNAME, &name_ns, 0, $3};
2260 NEW(abc_exception_t, e)
2261 e->exc_type = sig2mname($4);
2262 e->var_name = multiname_clone(&name);
2266 int i = find_variable_safe(state, $3)->index;
2267 e->target = c = abc_nop(0);
2268 c = abc_setlocal(c, i);
2269 c = code_append(c, code_dup(state->method->scope_code));
2270 c = code_append(c, $8);
2276 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
2281 NEW(abc_exception_t, e)
2282 e->exc_type = 0; //all exceptions
2283 e->var_name = 0; //no name
2286 e->to = code_append(e->to, $4);
2292 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2293 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2294 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2295 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2299 list_append($$.l,$2);
2300 $$.finally = $2->to;$2->to=0;
2303 CATCH_FINALLY_LIST: FINALLY {
2307 list_append($$.l,$1);
2308 $$.finally = $1->to;$1->to=0;
2312 TRY : "try" '{' {PASS12 new_state();
2313 state->method->has_exceptions=1;
2314 state->method->late_binding=1;//for invariant scope_code
2315 } MAYBECODE '}' CATCH_FINALLY_LIST {
2316 code_t*out = abc_nop(0);
2318 code_t*start = abc_nop(0);
2319 $$ = code_append(start, $4);
2320 if(!is_break_or_jump($4)) {
2321 $$ = abc_jump($$, out);
2323 code_t*end = $$ = abc_nop($$);
2327 tmp = new_variable("__finally__", 0, 0, 0);
2329 abc_exception_list_t*l = $6.l;
2332 abc_exception_t*e = l->abc_exception;
2334 $$ = code_append($$, e->target);
2335 $$ = abc_jump($$, out);
2337 parserassert((ptroff_t)$6.finally);
2339 e->target = $$ = abc_nop($$);
2340 $$ = code_append($$, code_dup(state->method->scope_code));
2341 $$ = abc___rethrow__($$);
2349 $$ = code_append($$, out);
2351 $$ = insert_finally($$, $6.finally, tmp);
2353 list_concat(state->method->exceptions, $6.l);
2359 /* ------------ throw ------------------------------- */
2361 THROW : "throw" EXPRESSION {
2365 THROW : "throw" %prec prec_none {
2366 if(!state->exception_name)
2367 syntaxerror("re-throw only possible within a catch block");
2368 variable_t*v = find_variable(state, state->exception_name);
2370 $$=abc_getlocal($$, v->index);
2374 /* ------------ with -------------------------------- */
2376 WITH_HEAD : "with" '(' EXPRESSION ')' {
2378 if(state->method->has_exceptions) {
2379 int v = alloc_local();
2380 state->method->scope_code = abc_getlocal(state->method->scope_code, v);
2381 state->method->scope_code = abc_pushwith(state->method->scope_code);
2386 WITH : WITH_HEAD CODEBLOCK {
2387 /* remove getlocal;pushwith from scope code again */
2388 state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
2391 if(state->method->has_exceptions) {
2393 $$ = abc_setlocal($$, $1.number);
2395 $$ = abc_pushwith($$);
2396 $$ = code_append($$, $2);
2397 $$ = abc_popscope($$);
2401 /* ------------ packages and imports ---------------- */
2403 X_IDENTIFIER: T_IDENTIFIER
2404 | "package" {PASS12 $$="package";}
2405 | T_NAMESPACE {PASS12 $$=$1;}
2407 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2408 PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
2410 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2411 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2412 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
2413 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2416 static void state_has_imports()
2418 state->wildcard_imports = list_clone(state->wildcard_imports);
2419 state->imports = dict_clone(state->imports);
2420 state->has_own_imports = 1;
2422 static void import_toplevel(const char*package)
2424 char* s = strdup(package);
2426 dict_put(state->import_toplevel_packages, s, 0);
2427 char*x = strrchr(s, '.');
2435 IMPORT : "import" PACKAGEANDCLASS {
2437 slotinfo_t*s = registry_find($2->package, $2->name);
2438 if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
2439 as3_schedule_class($2->package, $2->name);
2443 syntaxerror("Couldn't import class\n");
2444 state_has_imports();
2445 dict_put(state->imports, c->name, c);
2446 import_toplevel(c->package);
2449 IMPORT : "import" PACKAGE '.' '*' {
2451 if(strncmp("flash.", $2, 6) && as3_pass==1) {
2452 as3_schedule_package($2);
2457 state_has_imports();
2458 list_append(state->wildcard_imports, i);
2459 import_toplevel(i->package);
2463 /* ------------ classes and interfaces (header) -------------- */
2465 MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
2466 MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
2467 MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
2468 MODIFIER_LIST : MODIFIER_LIST MODIFIER {
2470 $$.flags=$1.flags|$2.flags;
2471 if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
2472 $$.ns=$1.ns?$1.ns:$2.ns;
2475 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
2476 | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
2477 | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
2478 | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
2479 | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
2480 | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
2481 | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
2482 | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
2483 | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
2484 | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
2488 EXTENDS : {PASS12 $$=0;}
2489 EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
2491 EXTENDS_LIST : {PASS12 $$=list_new();}
2492 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2494 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2495 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2497 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
2498 EXTENDS IMPLEMENTS_LIST
2499 '{' {PASS12 startclass(&$1,$3,$4,$5);}
2501 '}' {PASS12 endclass();$$=0;}
2503 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
2505 '{' {PASS12 $1.flags|=FLAG_INTERFACE;
2506 startclass(&$1,$3,0,$4);}
2507 MAYBE_INTERFACE_BODY
2508 '}' {PASS12 endclass();$$=0;}
2510 /* ------------ classes and interfaces (body) -------------- */
2513 MAYBE_CLASS_BODY : CLASS_BODY
2514 CLASS_BODY : CLASS_BODY_ITEM
2515 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2516 CLASS_BODY_ITEM : ';'
2517 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
2518 CLASS_BODY_ITEM : SLOT_DECLARATION
2519 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2521 CLASS_BODY_ITEM : CODE_STATEMENT {
2522 code_t*c = state->cls->static_init->header;
2523 c = code_append(c, $1);
2524 state->cls->static_init->header = c;
2527 MAYBE_INTERFACE_BODY :
2528 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2529 INTERFACE_BODY : IDECLARATION
2530 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2532 IDECLARATION : "var" T_IDENTIFIER {
2533 syntaxerror("variable declarations not allowed in interfaces");
2535 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2537 $1.flags |= FLAG_PUBLIC;
2538 if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2539 syntaxerror("invalid method modifiers: interface methods always need to be public");
2541 startfunction(&$1,$3,$4,&$6,$8);
2542 endfunction(&$1,$3,$4,&$6,$8, 0);
2543 list_deep_free($6.list);
2546 /* ------------ classes and interfaces (body, slots ) ------- */
2549 static int slotstate_varconst = 0;
2550 static modifiers_t*slotstate_flags = 0;
2551 static void setslotstate(modifiers_t* flags, int varconst)
2553 slotstate_varconst = varconst;
2554 slotstate_flags = flags;
2556 if(flags && flags->flags&FLAG_STATIC) {
2557 state->method = state->cls->static_init;
2559 state->method = state->cls->init;
2562 parserassert(state->method);
2567 VARCONST: "var" | "const"
2569 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
2571 SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
2572 SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
2574 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
2577 int flags = slotstate_flags->flags;
2578 namespace_t ns = modifiers2access(slotstate_flags);
2582 varinfo_t* info = 0;
2584 memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
2586 check_override(i, flags);
2588 info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
2590 slotinfo_t*i = registry_find(state->package, $1);
2592 syntaxerror("package %s already contains '%s'", state->package, $1);
2594 if(ns.name && ns.name[0]) {
2595 syntaxerror("namespaces not allowed on package-level variables");
2597 info = varinfo_register_global(ns.access, state->package, $1);
2601 info->flags = flags;
2603 dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
2607 varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
2610 multiname_t mname = {QNAME, &ns, 0, $1};
2612 trait_list_t**traits;
2616 ns.name = state->package;
2617 traits = &global->init->traits;
2618 code = &global->init->method->body->code;
2619 } else if(flags&FLAG_STATIC) {
2621 traits = &state->cls->abc->static_traits;
2622 code = &state->cls->static_init->header;
2624 // instance variable
2625 traits = &state->cls->abc->traits;
2626 code = &state->cls->init->header;
2632 t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2634 t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2636 info->slot = t->slot_id;
2638 /* initalization code (if needed) */
2640 if($3.c && !is_pushundefined($3.c)) {
2641 c = abc_getlocal_0(c);
2642 c = code_append(c, $3.c);
2643 c = converttype(c, $3.t, $2);
2644 c = abc_setslot(c, t->slot_id);
2647 *code = code_append(*code, c);
2649 if(slotstate_varconst==KW_CONST) {
2650 t->kind= TRAIT_CONST;
2657 /* ------------ constants -------------------------------------- */
2659 MAYBECONSTANT: {$$=0;}
2660 MAYBECONSTANT: '=' CONSTANT {$$=$2;}
2662 //CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2663 CONSTANT : T_INT {$$ = constant_new_int($1);}
2665 $$ = constant_new_uint($1);
2667 CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2668 CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2669 CONSTANT : "true" {$$ = constant_new_true($1);}
2670 CONSTANT : "false" {$$ = constant_new_false($1);}
2671 CONSTANT : "null" {$$ = constant_new_null($1);}
2672 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
2673 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
2676 CONSTANT : T_IDENTIFIER {
2677 if(!strcmp($1, "NaN")) {
2678 $$ = constant_new_float(__builtin_nan(""));
2680 as3_warning("Couldn't evaluate constant value of %s", $1);
2681 $$ = constant_new_null($1);
2685 /* ------------ classes and interfaces (body, functions) ------- */
2687 // non-vararg version
2690 memset(&$$,0,sizeof($$));
2692 MAYBE_PARAM_LIST: PARAM_LIST {
2698 MAYBE_PARAM_LIST: "..." PARAM {
2700 memset(&$$,0,sizeof($$));
2702 list_append($$.list, $2);
2704 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2708 list_append($$.list, $4);
2712 PARAM_LIST: PARAM_LIST ',' PARAM {
2715 list_append($$.list, $3);
2719 memset(&$$,0,sizeof($$));
2720 list_append($$.list, $1);
2723 PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
2725 $$ = rfx_calloc(sizeof(param_t));
2731 PARAM: T_IDENTIFIER MAYBECONSTANT {
2733 $$ = rfx_calloc(sizeof(param_t));
2735 $$->type = TYPE_ANY;
2743 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
2744 MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
2747 endfunction(&$1,$3,$4,&$6,0,0);
2749 if(!state->method->info) syntaxerror("internal error");
2751 code_t*c = method_header(state->method);
2752 c = wrap_function(c, 0, $11);
2754 endfunction(&$1,$3,$4,&$6,$8,c);
2756 list_deep_free($6.list);
2760 MAYBE_IDENTIFIER: T_IDENTIFIER
2761 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2762 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
2763 '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2766 endfunction(0,0,$2,&$4,0,0);
2768 methodinfo_t*f = state->method->info;
2769 if(!f || !f->kind) syntaxerror("internal error");
2771 code_t*c = method_header(state->method);
2772 c = wrap_function(c, 0, $9);
2774 int index = state->method->var_index;
2775 endfunction(0,0,$2,&$4,$6,c);
2777 $$.c = abc_getlocal(0, index);
2778 $$.t = TYPE_FUNCTION(f);
2780 PASS12 list_deep_free($4.list);
2784 /* ------------- package + class ids --------------- */
2786 CLASS: X_IDENTIFIER {
2787 PASS1 NEW(unresolvedinfo_t,c);
2788 memset(c, 0, sizeof(*c));
2789 c->kind = INFOTYPE_UNRESOLVED;
2791 c->package = get_package_from_name($1);
2793 c->nsset = get_current_imports();
2794 /* make the compiler look for this class in the current directory,
2796 as3_schedule_class_noerror(state->package, $1);
2798 $$ = (classinfo_t*)c;
2800 slotinfo_t*s = find_class($1);
2801 if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
2802 $$ = (classinfo_t*)s;
2805 PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
2806 PASS1 NEW(unresolvedinfo_t,c);
2807 memset(c, 0, sizeof(*c));
2808 c->kind = INFOTYPE_UNRESOLVED;
2811 $$ = (classinfo_t*)c;
2813 slotinfo_t*s = registry_find($1, $3);
2814 if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2816 $$ = (classinfo_t*)s;
2819 CLASS_SPEC: PACKAGEANDCLASS
2822 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2823 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2825 TYPE : CLASS_SPEC {PASS12 $$=$1;}
2826 | '*' {PASS12 $$=registry_getanytype();}
2827 | "void" {PASS12 $$=registry_getanytype();}
2829 | "String" {$$=registry_getstringclass();}
2830 | "int" {$$=registry_getintclass();}
2831 | "uint" {$$=registry_getuintclass();}
2832 | "Boolean" {$$=registry_getbooleanclass();}
2833 | "Number" {$$=registry_getnumberclass();}
2836 MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
2837 MAYBETYPE: {PASS12 $$=0;}
2839 /* ----------function calls, delete, constructor calls ------ */
2841 MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
2842 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2844 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
2845 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2846 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2848 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
2852 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
2853 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
2854 $$.number= $1.number+1;
2855 $$.cc = code_append($1.cc, $2.c);
2859 NEW : "new" E XX MAYBE_PARAM_VALUES {
2860 typedcode_t v = node_read($2);
2862 if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2864 code_t*paramcode = $4.cc;
2865 if($$.c->opcode == OPCODE_GETPROPERTY) {
2866 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2867 $$.c = code_cutlast($$.c);
2868 $$.c = code_append($$.c, paramcode);
2869 $$.c = abc_constructprop2($$.c, name, $4.number);
2870 multiname_destroy(name);
2871 } else if($$.c->opcode == OPCODE_GETSLOT) {
2872 int slot = (int)(ptroff_t)$$.c->data[0];
2873 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
2874 multiname_t*name = t->name;
2875 $$.c = code_cutlast($$.c);
2876 $$.c = code_append($$.c, paramcode);
2877 $$.c = abc_constructprop2($$.c, name, $4.number);
2879 $$.c = code_append($$.c, paramcode);
2880 $$.c = abc_construct($$.c, $4.number);
2884 if(TYPE_IS_CLASS(v.t) && v.t->data) {
2887 $$.c = abc_coerce_a($$.c);
2892 /* TODO: use abc_call (for calling local variables),
2893 abc_callstatic (for calling own methods)
2896 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2898 typedcode_t v = node_read($1);
2900 if($$.c->opcode == OPCODE_COERCE_A) {
2901 $$.c = code_cutlast($$.c);
2903 code_t*paramcode = $3.cc;
2906 if($$.c->opcode == OPCODE_GETPROPERTY) {
2907 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2908 $$.c = code_cutlast($$.c);
2909 $$.c = code_append($$.c, paramcode);
2910 $$.c = abc_callproperty2($$.c, name, $3.number);
2911 multiname_destroy(name);
2912 } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
2913 int slot = (int)(ptroff_t)$$.c->data[0];
2914 trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
2915 if(t->kind!=TRAIT_METHOD) {
2916 //ok: flash allows to assign closures to members.
2918 multiname_t*name = t->name;
2919 $$.c = code_cutlast($$.c);
2920 $$.c = code_append($$.c, paramcode);
2921 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2922 $$.c = abc_callproperty2($$.c, name, $3.number);
2923 } else if($$.c->opcode == OPCODE_GETSUPER) {
2924 multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2925 $$.c = code_cutlast($$.c);
2926 $$.c = code_append($$.c, paramcode);
2927 $$.c = abc_callsuper2($$.c, name, $3.number);
2928 multiname_destroy(name);
2930 $$.c = abc_getglobalscope($$.c);
2931 $$.c = code_append($$.c, paramcode);
2932 $$.c = abc_call($$.c, $3.number);
2935 if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
2936 $$.t = ((methodinfo_t*)(v.t->data))->return_type;
2938 $$.c = abc_coerce_a($$.c);
2943 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2944 if(!state->cls) syntaxerror("super() not allowed outside of a class");
2945 if(!state->method) syntaxerror("super() not allowed outside of a function");
2946 if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2949 $$.c = abc_getlocal_0($$.c);
2951 $$.c = code_append($$.c, $3.cc);
2953 this is dependent on the control path, check this somewhere else
2954 if(state->method->has_super)
2955 syntaxerror("constructor may call super() only once");
2957 state->method->has_super = 1;
2959 $$.c = abc_constructsuper($$.c, $3.number);
2960 $$.c = abc_pushundefined($$.c);
2964 DELETE: "delete" E {
2965 typedcode_t v = node_read($2);
2967 if($$.c->opcode == OPCODE_COERCE_A) {
2968 $$.c = code_cutlast($$.c);
2970 multiname_t*name = 0;
2971 if($$.c->opcode == OPCODE_GETPROPERTY) {
2972 $$.c->opcode = OPCODE_DELETEPROPERTY;
2973 } else if($$.c->opcode == OPCODE_GETSLOT) {
2974 int slot = (int)(ptroff_t)$$.c->data[0];
2975 multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
2976 $$.c = code_cutlast($$.c);
2977 $$.c = abc_deleteproperty2($$.c, name);
2979 $$.c = abc_getlocal_0($$.c);
2980 MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
2981 $$.c = abc_deleteproperty2($$.c, &m);
2983 $$.t = TYPE_BOOLEAN;
2986 RETURN: "return" %prec prec_none {
2987 $$ = abc_returnvoid(0);
2989 RETURN: "return" EXPRESSION {
2991 $$ = abc_returnvalue($$);
2994 // ----------------------- expression types -------------------------------------
2996 NONCOMMAEXPRESSION : E %prec below_minus {
2999 EXPRESSION : COMMA_EXPRESSION {
3002 COMMA_EXPRESSION : E %prec below_minus {
3003 $$ = mkmultinode(&node_comma, $1);
3005 COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_minus {
3006 $$ = multinode_extend($1, $3);
3008 VOIDEXPRESSION : E %prec below_minus {
3011 VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_minus {
3013 $$ = code_append($$, node_exec($3));
3016 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
3017 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
3019 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3021 $$.cc = code_append($$.cc, $1.c);
3022 $$.cc = code_append($$.cc, $3.c);
3025 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
3027 $$.number = $1.number+2;
3028 $$.cc = code_append($$.cc, $3.c);
3029 $$.cc = code_append($$.cc, $5.c);
3032 // ----------------------- expression evaluation -------------------------------------
3034 E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
3035 E : VAR_READ %prec T_IDENTIFIER {$$ = mkcodenode($1);}
3036 E : MEMBER %prec '.' {$$ = mkcodenode($1);}
3037 E : NEW {$$ = mkcodenode($1);}
3038 E : DELETE {$$ = mkcodenode($1);}
3039 E : FUNCTIONCALL {$$ = mkcodenode($1);}
3042 $$ = mkconstnode($1);
3049 namespace_t ns = {ACCESS_PACKAGE, ""};
3050 multiname_t m = {QNAME, &ns, 0, "RegExp"};
3052 v.c = abc_getlex2(v.c, &m);
3053 v.c = abc_pushstring(v.c, $1.pattern);
3054 v.c = abc_construct(v.c, 1);
3056 v.c = abc_getlex2(v.c, &m);
3057 v.c = abc_pushstring(v.c, $1.pattern);
3058 v.c = abc_pushstring(v.c, $1.options);
3059 v.c = abc_construct(v.c, 2);
3066 E : '[' MAYBE_EXPRESSION_LIST ']' {
3069 v.c = code_append(v.c, $2.cc);
3070 v.c = abc_newarray(v.c, $2.number);
3071 v.t = registry_getarrayclass();
3076 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
3079 v.c = code_append(v.c, $2.cc);
3080 v.c = abc_newobject(v.c, $2.number/2);
3081 v.t = registry_getobjectclass();
3085 E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
3086 E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
3087 E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
3088 E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
3089 E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
3090 E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
3091 E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
3092 E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
3093 E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
3094 E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
3095 E : '!' E {$$ = mknode1(&node_not, $2);}
3096 E : '~' E {$$ = mknode1(&node_bitnot, $2);}
3097 E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
3098 E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
3099 E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
3100 E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
3101 E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
3102 E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
3103 E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
3104 E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
3105 E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
3106 E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
3107 E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
3108 E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
3109 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
3110 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
3111 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
3112 E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
3113 E : "void" E {$$ = mknode1(&node_void, $2);}
3114 E : "void" { $$ = mkconstnode(constant_new_undefined());}
3115 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
3116 E : '-' E {$$ = mknode1(&node_neg, $2);}
3117 E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
3118 E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
3119 E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
3120 E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
3121 E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
3122 E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
3123 E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
3124 E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
3125 E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
3126 E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
3127 E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
3128 E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
3129 E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
3130 E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
3132 E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
3133 E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
3134 E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
3135 E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
3137 E : "super" '.' T_IDENTIFIER
3138 { if(!state->cls->info)
3139 syntaxerror("super keyword not allowed outside a class");
3140 classinfo_t*t = state->cls->info->superclass;
3141 if(!t) t = TYPE_OBJECT;
3142 memberinfo_t*f = findmember_nsset(t, $3, 1);
3143 MEMBER_MULTINAME(m, f, $3);
3146 v.c = abc_getlocal_0(v.c);
3147 v.c = abc_getsuper2(v.c, &m);
3148 v.t = slotinfo_gettype((slotinfo_t*)f);
3152 E : '@' T_IDENTIFIER {
3155 as3_warning("ignored @ operator");
3158 E : E '.' '@' T_IDENTIFIER {
3159 // child attribute TODO
3161 as3_warning("ignored .@ operator");
3164 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3165 // namespace declaration TODO
3167 as3_warning("ignored :: operator");
3170 E : E ".." T_IDENTIFIER {
3173 as3_warning("ignored .. operator");
3176 E : E '.' '(' E ')' {
3179 as3_warning("ignored .() operator");
3182 //E : E "::" '[' E ']' {
3183 // // qualified expression TODO
3184 // $$.c = abc_pushundefined(0);
3186 // as3_warning("ignored ::[] operator");
3189 MEMBER : E '.' T_IDENTIFIER {
3190 typedcode_t v1 = node_read($1);
3192 classinfo_t*t = v1.t;
3194 if(TYPE_IS_CLASS(t) && t->data) {
3199 if(t->subtype==INFOTYPE_UNRESOLVED) {
3200 syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
3202 memberinfo_t*f = findmember_nsset(t, $3, 1);
3204 if(f && !is_static != !(f->flags&FLAG_STATIC))
3206 if(f && f->slot && !noslot) {
3207 $$.c = abc_getslot($$.c, f->slot);
3210 as3_warning("Access of undefined property '%s' in %s", $3, t->name);
3213 MEMBER_MULTINAME(m, f, $3);
3214 $$.c = abc_getproperty2($$.c, &m);
3216 /* determine type */
3217 $$.t = slotinfo_gettype((slotinfo_t*)f);
3219 $$.c = abc_coerce_a($$.c);
3220 } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
3221 string_t*package = v1.c->data[0];
3222 char*package2 = concat3(package->str, ".", $3);
3224 slotinfo_t*a = registry_find(package->str, $3);
3227 } else if(dict_contains(state->import_toplevel_packages, package2) ||
3228 registry_ispackage(package2)) {
3230 $$.c->data[0] = string_new4(package2);
3233 syntaxerror("couldn't resolve %s", package2);
3236 /* when resolving a property on an unknown type, we do know the
3237 name of the property (and don't seem to need the package), but
3238 we need to make avm2 try out all access modes */
3239 as3_warning("Resolving %s on unknown type", $3);
3240 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3241 $$.c = abc_getproperty2($$.c, &m);
3242 $$.c = abc_coerce_a($$.c);
3243 $$.t = registry_getanytype();
3247 VAR_READ : T_IDENTIFIER {
3249 /* Queue unresolved identifiers for checking against the parent
3250 function's variables.
3251 We consider everything which is not a local variable "unresolved".
3252 This encompasses class names, members of the surrounding class
3253 etc. which is *correct* because local variables of the parent function
3256 if(state->method->inner && !find_variable(state, $1)) {
3257 unknown_variable($1);
3260 /* let the compiler know that it might want to check the current directory/package
3261 for this identifier- maybe there's a file $1.as defining $1. */
3262 as3_schedule_class_noerror(state->package, $1);
3271 /* look at variables */
3272 if((v = find_variable(state, $1))) {
3273 // $1 is a local variable
3274 $$.c = abc_getlocal($$.c, v->index);
3278 if((v = find_slot(state, $1))) {
3279 $$.c = abc_getscopeobject($$.c, 1);
3280 $$.c = abc_getslot($$.c, v->index);
3285 int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3287 /* look at current class' members */
3288 if(!state->method->inner &&
3290 (f = findmember_nsset(state->cls->info, $1, 1)) &&
3291 (f->flags&FLAG_STATIC) >= i_am_static)
3293 // $1 is a function in this class
3294 int var_is_static = (f->flags&FLAG_STATIC);
3296 if(f->kind == INFOTYPE_METHOD) {
3297 $$.t = TYPE_FUNCTION(f);
3301 if(var_is_static && !i_am_static) {
3302 /* access to a static member from a non-static location.
3303 do this via findpropstrict:
3304 there doesn't seem to be any non-lookup way to access
3305 static properties of a class */
3306 state->method->late_binding = 1;
3308 namespace_t ns = {f->access, f->package};
3309 multiname_t m = {QNAME, &ns, 0, $1};
3310 $$.c = abc_findpropstrict2($$.c, &m);
3311 $$.c = abc_getproperty2($$.c, &m);
3313 } else if(f->slot>0) {
3314 $$.c = abc_getlocal_0($$.c);
3315 $$.c = abc_getslot($$.c, f->slot);
3318 namespace_t ns = {f->access, f->package};
3319 multiname_t m = {QNAME, &ns, 0, $1};
3320 $$.c = abc_getlocal_0($$.c);
3321 $$.c = abc_getproperty2($$.c, &m);
3326 /* look at actual classes, in the current package and imported */
3327 if((a = find_class($1))) {
3332 /* look through package prefixes */
3333 if(dict_contains(state->import_toplevel_packages, $1) ||
3334 registry_ispackage($1)) {
3335 $$.c = abc___pushpackage__($$.c, $1);
3340 /* unknown object, let the avm2 resolve it */
3342 //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3343 as3_warning("Couldn't resolve '%s', doing late binding", $1);
3344 state->method->late_binding = 1;
3346 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3349 $$.c = abc_findpropstrict2($$.c, &m);
3350 $$.c = abc_getproperty2($$.c, &m);
3354 // ----------------- namespaces -------------------------------------------------
3356 NAMESPACE_ID : "namespace" T_IDENTIFIER {
3358 NEW(namespace_decl_t,n);
3363 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
3365 NEW(namespace_decl_t,n);
3370 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
3372 NEW(namespace_decl_t,n);
3377 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
3379 trie_put(active_namespaces, $2->name, (void*)$2->url);
3381 namespace_t access = modifiers2access(&$1);
3382 varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
3383 var->type = TYPE_NAMESPACE;
3385 ns.access = ACCESS_NAMESPACE;
3387 var->value = constant_new_namespace(&ns);
3393 void add_active_url(const char*url)
3397 list_append(state->active_namespace_urls, n);
3401 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
3403 const char*url = $3->name;
3405 varinfo_t*s = (varinfo_t*)$3;
3406 if(s->kind == INFOTYPE_UNRESOLVED) {
3407 s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
3409 syntaxerror("Couldn't resolve namespace %s", $3->name);
3412 if(!s || s->kind != INFOTYPE_SLOT)
3413 syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
3414 if(!s->value || !NS_TYPE(s->value->type))
3415 syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
3416 url = s->value->ns->name;
3418 trie_put(active_namespaces, $3->name, (void*)url);
3419 add_active_url(url);