%union tokenunion {
enum yytokentype token;
- int flags;
classinfo_t*classinfo;
classinfo_list_t*classinfo_list;
+ slotinfo_t*slotinfo;
+ slotinfo_list_t*slotinfo_list;
int number_int;
unsigned int number_uint;
for_start_t for_start;
abc_exception_t *exception;
regexp_t regexp;
+ modifiers_t flags;
struct {
abc_exception_list_t *l;
code_t*finally;
%token<token> T_SHR ">>"
%type <for_start> FOR_START
-%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
+%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER NAMESPACE_ID
%type <token> VARCONST
%type <code> CODE
%type <code> CODEPIECE CODE_STATEMENT
%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
-%type <code> PACKAGE_DECLARATION SLOT_DECLARATION
+%type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
%type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
-%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
+%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
%type <exception> CATCH FINALLY
%type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
%type <code> CLASS_DECLARATION
%type <params> MAYBE_PARAM_LIST
%type <flags> MAYBE_MODIFIERS
%type <flags> MODIFIER_LIST
+%type <flags> MODIFIER
%type <constant> STATICCONSTANT MAYBESTATICCONSTANT
%type <classinfo_list> IMPLEMENTS_LIST
-%type <classinfo> EXTENDS
+%type <classinfo> EXTENDS CLASS_SPEC
%type <classinfo_list> EXTENDS_LIST
-%type <classinfo> CLASS PACKAGEANDCLASS CLASS_SPEC
+
+%type <classinfo> CLASS PACKAGEANDCLASS
%type <classinfo_list> CLASS_SPEC_LIST
+
%type <classinfo> TYPE
//%type <token> VARIABLE
%type <value> VAR_READ
%type <value> NEW
//%type <token> T_IDENTIFIER
-%type <token> MODIFIER
%type <value> FUNCTIONCALL
%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
char is_global;
int variable_count;
+ dict_t*unresolved_variables;
+
char inner;
+ char uses_parent_function;
+ int uses_slots;
+ dict_t*slots;
+
abc_method_t*abc;
int var_index; // for inner methods
+ int slot_index; // for inner methods
+ char is_a_slot; // for inner methods
code_t*header;
abc_exception_list_t*exceptions;
char*package;
import_list_t*wildcard_imports;
+ namespace_list_t*active_namespaces;
dict_t*imports;
char has_own_imports;
char new_vars; // e.g. transition between two functions
multiname_t m;\
namespace_t m##_ns;\
if(f) { \
- m##_ns.access = (f)->access; \
- m##_ns.name = ""; \
+ if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
+ m##_ns.name = ((slotinfo_t*)(f))->package; \
+ else \
+ m##_ns.name = ""; \
m.type = QNAME; \
m.ns = &m##_ns; \
m.namespace_set = 0; \
- m.name = f->name; \
+ m.name = ((slotinfo_t*)(f))->name; \
} else { \
m.type = MULTINAME; \
m.ns =0; \
state->has_own_imports = 0;
state->vars = dict_new();
state->old = oldstate;
+ state->new_vars = 0;
}
static void state_has_imports()
{
static code_t* method_header(methodstate_t*m);
static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
-static void function_initvars(methodstate_t*m, params_t*params, int flags);
+static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
static char* internal_filename_package = 0;
dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
} else {
state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
- function_initvars(state->method, 0, 0);
+ function_initvars(state->method, 0, 0, 1);
global->init = abc_initscript(global->file);
state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
}
c = abc_iftrue(c,xx);*/
}
-
typedef struct _variable {
int index;
classinfo_t*type;
char init;
+ methodstate_t*is_inner_method;
} variable_t;
-static variable_t* find_variable(char*name)
+static variable_t* find_variable(state_t*s, char*name)
{
- state_t* s = state;
while(s) {
variable_t*v = 0;
- if(s->method)
- v = dict_lookup(s->vars, name);
- if(v) {
- return v;
- }
- if(s->new_vars)
- break;
+ v = dict_lookup(s->vars, name);
+ if(v) return v;
+ if(s->new_vars) break;
s = s->old;
}
return 0;
-}
-static variable_t* find_variable_safe(char*name)
+}
+static variable_t* find_slot(state_t*s, const char*name)
{
- variable_t* v = find_variable(name);
+ if(s->method && s->method->slots)
+ return dict_lookup(s->method->slots, name);
+ return 0;
+}
+
+static variable_t* find_variable_safe(state_t*s, char*name)
+{
+ variable_t* v = find_variable(s, name);
if(!v)
syntaxerror("undefined variable: %s", name);
return v;
}
static char variable_exists(char*name)
{
- return dict_lookup(state->vars, name)!=0;
+ return dict_contains(state->vars, name);
}
code_t*defaultvalue(code_t*c, classinfo_t*type);
-static int new_variable(const char*name, classinfo_t*type, char init)
+
+static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
{
+ if(maybeslot) {
+ variable_t*v = find_slot(state, name);
+ if(v)
+ return v;
+ }
+
NEW(variable_t, v);
- v->index = state->method->variable_count;
+ v->index = state->method->variable_count++;
v->type = type;
v->init = init;
dict_put(state->vars, name, v);
- return state->method->variable_count++;
+ return v;
+}
+static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
+{
+ return new_variable2(name, type, init, maybeslot)->index;
}
+
#define TEMPVARNAME "__as3_temp__"
static int gettempvar()
{
- variable_t*v = find_variable(TEMPVARNAME);
+ variable_t*v = find_variable(state, TEMPVARNAME);
if(v)
return v->index;
- return new_variable(TEMPVARNAME, 0, 0);
+ return new_variable(TEMPVARNAME, 0, 0, 0);
}
code_t* var_block(code_t*body)
return c;
}
+void unknown_variable(char*name)
+{
+ if(!state->method->unresolved_variables)
+ state->method->unresolved_variables = dict_new();
+ if(!dict_contains(state->method->unresolved_variables, name))
+ dict_put(state->method->unresolved_variables, name, 0);
+}
+
#define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
static void parsererror(const char*file, int line, const char*f)
static code_t* method_header(methodstate_t*m)
{
code_t*c = 0;
- if(m->late_binding && !m->inner) {
+ if(m->uses_slots || (m->late_binding && !m->inner)) {
c = abc_getlocal_0(c);
c = abc_pushscope(c);
}
- /*if(m->innerfunctions) {
+ if(m->uses_slots) {
c = abc_newactivation(c);
c = abc_pushscope(c);
- }*/
+ }
methodstate_list_t*l = m->innerfunctions;
while(l) {
parserassert(l->methodstate->abc);
- c = abc_newfunction(c, l->methodstate->abc);
- c = abc_setlocal(c, l->methodstate->var_index);
+ if(m->uses_slots && l->methodstate->is_a_slot) {
+ c = abc_getscopeobject(c, 1);
+ c = abc_newfunction(c, l->methodstate->abc);
+ c = abc_dup(c);
+ c = abc_setlocal(c, l->methodstate->var_index);
+ c = abc_setslot(c, l->methodstate->slot_index);
+ } else {
+ c = abc_newfunction(c, l->methodstate->abc);
+ c = abc_setlocal(c, l->methodstate->var_index);
+ }
free(l->methodstate);l->methodstate=0;
l = l->next;
}
#define FLAG_PACKAGEINTERNAL 2048
#define FLAG_NAMESPACE 4096
-static int flags2access(int flags)
+static namespace_t modifiers2access(modifiers_t*mod)
{
- int access = 0;
- if(flags&FLAG_PUBLIC) {
- if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
+ namespace_t ns;
+ ns.access = 0;
+ ns.name = "";
+ if(mod->flags&FLAG_NAMESPACE) {
+ if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
+ syntaxerror("invalid combination of access levels and namespaces");
+ ns.access = ACCESS_NAMESPACE;
+ ns.name = mod->ns;
+ } else if(mod->flags&FLAG_PUBLIC) {
+ if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
syntaxerror("invalid combination of access levels");
- access = ACCESS_PACKAGE;
- } else if(flags&FLAG_PRIVATE) {
- if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
+ ns.access = ACCESS_PACKAGE;
+ } else if(mod->flags&FLAG_PRIVATE) {
+ if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
syntaxerror("invalid combination of access levels");
- access = ACCESS_PRIVATE;
- } else if(flags&FLAG_PROTECTED) {
- if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
+ ns.access = ACCESS_PRIVATE;
+ } else if(mod->flags&FLAG_PROTECTED) {
+ if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
syntaxerror("invalid combination of access levels");
- access = ACCESS_PROTECTED;
+ ns.access = ACCESS_PROTECTED;
} else {
- access = ACCESS_PACKAGEINTERNAL;
+ ns.access = ACCESS_PACKAGEINTERNAL;
}
- return access;
+ return ns;
}
-static void function_initvars(methodstate_t*m, params_t*params, int flags)
+static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
{
- if(m->inner)
- new_variable("this", 0, 0);
- else if(!m->is_global)
- new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0);
- else
- new_variable("globalscope", 0, 0);
+ if(var0) {
+ int index = -1;
+ if(m->inner)
+ index = new_variable("this", 0, 0, 0);
+ else if(!m->is_global)
+ index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
+ else
+ index = new_variable("globalscope", 0, 0, 0);
+ if(index)
+ *(int*)0=0;
+ parserassert(!index);
+ }
+ if(m->uses_slots) {
+ /* as variables and slots share the same number, make sure
+ that those variable indices are reserved. It's up to the
+ optimizer to later shuffle the variables down to lower
+ indices */
+ m->variable_count = m->uses_slots;
+ }
if(params) {
param_list_t*p=0;
for(p=params->list;p;p=p->next) {
- new_variable(p->param->name, p->param->type, 0);
+ new_variable(p->param->name, p->param->type, 0, 1);
}
}
methodstate_list_t*l = m->innerfunctions;
while(l) {
methodstate_t*m = l->methodstate;
- m->var_index = new_variable(m->info->name, TYPE_FUNCTION(m->info), 0);
+ variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
+ m->var_index = v->index;
+ m->slot_index = v->index;
+ v->is_inner_method = m;
l = l->next;
}
}
char*as3_globalclass=0;
-static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements)
+static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
{
if(state->cls) {
syntaxerror("inner classes now allowed");
token_list_t*t=0;
classinfo_list_t*mlist=0;
- if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
+ if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
syntaxerror("invalid modifier(s)");
- if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
+ if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
syntaxerror("public and internal not supported at the same time.");
/* create the class name, together with the proper attributes */
int access=0;
char*package=0;
- if(!(flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
+ if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
access = ACCESS_PRIVATE; package = internal_filename_package;
- } else if(!(flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
+ } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
access = ACCESS_PACKAGEINTERNAL; package = state->package;
} else if(state->package!=internal_filename_package) {
access = ACCESS_PACKAGE; package = state->package;
/* build info struct */
int num_interfaces = (list_length(implements));
state->cls->info = classinfo_register(access, package, classname, num_interfaces);
- state->cls->info->flags |= flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
+ state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
}
if(as3_pass == 2) {
state->method = state->cls->init;
parserassert(state->cls && state->cls->info);
-
- function_initvars(state->cls->init, 0, 0);
- function_initvars(state->cls->static_init, 0, 0);
+
+ function_initvars(state->cls->init, 0, 0, 1);
+ function_initvars(state->cls->static_init, 0, 0, 0);
if(extends && (extends->flags & FLAG_FINAL))
syntaxerror("Can't extend final class '%s'", extends->name);
/* flash.display.MovieClip handling */
- if(!as3_globalclass && (flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
+ if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
if(state->package && state->package[0]) {
as3_globalclass = concat3(state->package, ".", classname);
} else {
}
}
-static void setstaticfunction(int x)
+static int slotstate_varconst = 0;
+static modifiers_t*slotstate_flags = 0;
+static void setslotstate(modifiers_t* flags, int varconst)
{
+ slotstate_varconst = varconst;
+ slotstate_flags = flags;
if(state->cls) {
- if(x&FLAG_STATIC) {
+ if(flags && flags->flags&FLAG_STATIC) {
state->method = state->cls->static_init;
} else {
state->method = state->cls->init;
}
}
-static methodinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
+static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, char*name, params_t*params, classinfo_t*return_type, int slot)
{
methodinfo_t*minfo = 0;
- U8 access = flags2access(flags);
+ namespace_t ns = modifiers2access(mod);
if(!state->cls) {
//package method
- minfo = methodinfo_register_global(access, state->package, name);
- minfo->return_type = return_type;
+ minfo = methodinfo_register_global(ns.access, state->package, name);
+ minfo->return_type = 0; // save this for pass 2
} else if(getset != KW_GET && getset != KW_SET) {
//class method
- memberinfo_t* m = registry_findmember(state->cls->info, name, 0);
+ memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
if(m) {
+ printf("%s.%s | %s.%s\n",
+ m->package, m->name,
+ ns.name, name);
syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
}
- minfo = methodinfo_register_onclass(state->cls->info, access, name);
- minfo->return_type = return_type;
+ minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
+ minfo->return_type = 0; // save this for pass 2
// getslot on a member slot only returns "undefined", so no need
// to actually store these
//state->minfo->slot = state->method->abc->method->trait->slot_id;
//class getter/setter
int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
classinfo_t*type=0;
- if(getset == KW_GET)
+ if(getset == KW_GET) {
type = return_type;
- else if(params->list && params->list->param)
+ } else if(params->list && params->list->param && !params->list->next) {
type = params->list->param->type;
+ } else
+ syntaxerror("setter function needs to take exactly one argument");
// not sure wether to look into superclasses here, too
- minfo = (methodinfo_t*)registry_findmember(state->cls->info, name, 1);
+ minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
if(minfo) {
if(minfo->kind!=INFOTYPE_SLOT)
syntaxerror("class already contains a method called '%s'", name);
syntaxerror("getter/setter for '%s' already defined", name);
/* make a setter or getter into a getset */
minfo->subtype |= gs;
- if(!minfo->return_type) {
- minfo->return_type = type;
- } else {
- if(minfo && minfo->return_type != type)
- syntaxerror("different type in getter and setter");
- }
+
+ /*
+ FIXME: this check needs to be done in pass 2
+
+ if((!minfo->return_type != !type) ||
+ (minfo->return_type && type &&
+ !strcmp(minfo->return_type->name, type->name))) {
+ syntaxerror("different type in getter and setter: %s and %s",
+ minfo->return_type?minfo->return_type->name:"*",
+ type?type->name:"*");
+ }*/
} else {
- minfo = methodinfo_register_onclass(state->cls->info, access, name);
+ minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
minfo->kind = INFOTYPE_SLOT; //hack
minfo->subtype = gs;
- minfo->return_type = type;
+ minfo->return_type = 0;
}
/* can't assign a slot as getter and setter might have different slots */
//minfo->slot = slot;
}
- if(flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
- if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
- if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
+ if(mod->flags&FLAG_FINAL) minfo->flags |= FLAG_FINAL;
+ if(mod->flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
+ if(mod->flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
+
return minfo;
}
methodstate_t*parent_method = state->method;
if(as3_pass==1) {
- // not valid yet
- params = 0;
- return_type = 0;
+ return_type = 0; // not valid in pass 1
}
new_state();
list_append(parent_method->innerfunctions, state->method);
dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
+
+ function_initvars(state->method, params, 0, 1);
}
if(as3_pass == 2) {
state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+ state->method->variable_count = 0;
parserassert(state->method);
state->method->info->return_type = return_type;
- function_initvars(state->method, params, 0);
+ function_initvars(state->method, params, 0, 1);
}
}
-static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
+static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
params_t*params, classinfo_t*return_type)
{
if(state->method && state->method->info) {
syntaxerror("not able to start another method scope");
}
new_state();
+ state->new_vars = 1;
if(as3_pass == 1) {
state->method = rfx_calloc(sizeof(methodstate_t));
if(state->method->is_constructor)
name = "__as3_constructor__";
- return_type = 0;
- state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
+ state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
+
+ function_initvars(state->method, params, mod->flags, 1);
dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
}
if(as3_pass == 2) {
state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+ state->method->variable_count = 0;
parserassert(state->method);
-
+
if(state->cls) {
- memberinfo_t*m = registry_findmember(state->cls->info, name, 2);
- check_override(m, flags);
+ memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
+ check_override(m, mod->flags);
}
if(state->cls) {
}
state->method->info->return_type = return_type;
- function_initvars(state->method, params, flags);
+ function_initvars(state->method, params, mod->flags, 1);
}
}
-static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
+static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
params_t*params, classinfo_t*return_type, code_t*body)
{
+ int flags = mod?mod->flags:0;
+
if(as3_pass==1) {
+ // store inner methods in variables
+ function_initvars(state->method, 0, 0, 0);
+
+ methodstate_list_t*ml = state->method->innerfunctions;
+ dict_t*xvars = dict_new();
+ while(ml) {
+ methodstate_t*m = ml->methodstate;
+ parserassert(m->inner);
+ if(m->unresolved_variables) {
+ dict_t*d = m->unresolved_variables;
+ int t;
+ for(t=0;t<d->hashsize;t++) {
+ dictentry_t*l = d->slots[t];
+ while(l) {
+ /* check parent method's variables */
+ if(find_variable(state, l->key)) {
+ m->uses_parent_function = 1;
+ state->method->uses_slots = 1;
+ dict_put(xvars, l->key, 0);
+ }
+ l = l->next;
+ }
+ if(l) break;
+ }
+
+ dict_destroy(m->unresolved_variables);
+ m->unresolved_variables = 0;
+ }
+ ml = ml->next;
+ }
+ if(state->method->uses_slots) {
+ state->method->slots = dict_new();
+ int i = 1;
+ DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
+ if(v->index && dict_contains(xvars, name)) {
+ v->init = 0;
+ v->index = i++;
+ if(v->is_inner_method) {
+ v->is_inner_method->is_a_slot = 1;
+ }
+ //v->type = 0;
+ dict_put(state->method->slots, name, v);
+ }
+ }
+ state->method->uses_slots = i;
+ dict_destroy(state->vars);state->vars = 0;
+ }
+ dict_destroy(xvars);
+
old_state();
return 0;
}
- abc_method_t*f = 0;
+ if(as3_pass==2) {
+ /*if(state->method->uses_parent_function){
+ syntaxerror("accessing variables of parent function from inner functions not supported yet");
+ }*/
+
+ abc_method_t*f = 0;
+
+ multiname_t*type2 = sig2mname(return_type);
+ int slot = 0;
+ if(state->method->inner) {
+ f = state->method->abc;
+ abc_method_init(f, global->file, type2, 1);
+ } else if(state->method->is_constructor) {
+ f = abc_class_getconstructor(state->cls->abc, type2);
+ } else if(!state->method->is_global) {
+ namespace_t mname_ns = {state->method->info->access, ""};
+ multiname_t mname = {QNAME, &mname_ns, 0, name};
+
+ if(flags&FLAG_STATIC)
+ f = abc_class_staticmethod(state->cls->abc, type2, &mname);
+ else
+ f = abc_class_method(state->cls->abc, type2, &mname);
+ slot = f->trait->slot_id;
+ } else {
+ namespace_t mname_ns = {state->method->info->access, state->package};
+ multiname_t mname = {QNAME, &mname_ns, 0, name};
+
+ f = abc_method_new(global->file, type2, 1);
+ trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
+ //abc_code_t*c = global->init->method->body->code;
+ }
+ //flash doesn't seem to allow us to access function slots
+ //state->method->info->slot = slot;
- multiname_t*type2 = sig2mname(return_type);
- int slot = 0;
- if(state->method->inner) {
- f = state->method->abc;
- abc_method_init(f, global->file, type2, 1);
- } else if(state->method->is_constructor) {
- f = abc_class_getconstructor(state->cls->abc, type2);
- } else if(!state->method->is_global) {
- namespace_t mname_ns = {state->method->info->access, ""};
- multiname_t mname = {QNAME, &mname_ns, 0, name};
+ if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
+ if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
+ if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
+ if(params->varargs) f->flags |= METHOD_NEED_REST;
- if(flags&FLAG_STATIC)
- f = abc_class_staticmethod(state->cls->abc, type2, &mname);
- else
- f = abc_class_method(state->cls->abc, type2, &mname);
- slot = f->trait->slot_id;
- } else {
- namespace_t mname_ns = {state->method->info->access, state->package};
- multiname_t mname = {QNAME, &mname_ns, 0, name};
-
- f = abc_method_new(global->file, type2, 1);
- trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
- //abc_code_t*c = global->init->method->body->code;
- }
- //flash doesn't seem to allow us to access function slots
- //state->method->info->slot = slot;
-
- if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
- if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
- if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
- if(params->varargs) f->flags |= METHOD_NEED_REST;
-
- char opt=0;
- param_list_t*p=0;
- for(p=params->list;p;p=p->next) {
- if(params->varargs && !p->next) {
- break; //varargs: omit last parameter in function signature
+ char opt=0;
+ param_list_t*p=0;
+ for(p=params->list;p;p=p->next) {
+ if(params->varargs && !p->next) {
+ break; //varargs: omit last parameter in function signature
+ }
+ multiname_t*m = sig2mname(p->param->type);
+ list_append(f->parameters, m);
+ if(p->param->value) {
+ check_constant_against_type(p->param->type, p->param->value);
+ opt=1;list_append(f->optional_parameters, p->param->value);
+ } else if(opt) {
+ syntaxerror("non-optional parameter not allowed after optional parameters");
+ }
}
- multiname_t*m = sig2mname(p->param->type);
- list_append(f->parameters, m);
- if(p->param->value) {
- check_constant_against_type(p->param->type, p->param->value);
- opt=1;list_append(f->optional_parameters, p->param->value);
- } else if(opt) {
- syntaxerror("non-optional parameter not allowed after optional parameters");
+ if(state->method->slots) {
+ DICT_ITERATE_ITEMS(state->method->slots, char*, name, variable_t*, v) {
+ if(v->index) {
+ multiname_t*mname = multiname_new(namespace_new(ACCESS_PACKAGE, ""), name);
+ multiname_t*type = sig2mname(v->type);
+ trait_t*t = trait_new_member(&f->body->traits, type, mname, 0);
+ t->slot_id = v->index;
+ }
+ }
}
- }
- check_code_for_break(body);
- if(f->body) {
- f->body->code = body;
- f->body->exceptions = state->method->exceptions;
- } else { //interface
- if(body)
- syntaxerror("interface methods can't have a method body");
+ check_code_for_break(body);
+
+ if(state->method->exceptions &&
+ (state->method->late_binding || state->method->uses_slots))
+ syntaxerror("try/catch and activation or late binding not supported yet within the same method");
+
+ if(f->body) {
+ f->body->code = body;
+ f->body->exceptions = state->method->exceptions;
+ } else { //interface
+ if(body)
+ syntaxerror("interface methods can't have a method body");
+ }
+
+ old_state();
+ return f;
}
-
- old_state();
- return f;
+
+ return 0;
}
char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
CODE: CODE CODEPIECE {$$=code_append($1,$2);}
CODE: CODEPIECE {$$=$1;}
-// code which also may appear outside a method
+// code which may appear outside of methods
CODE_STATEMENT: IMPORT
CODE_STATEMENT: FOR
CODE_STATEMENT: FOR_IN
CODE_STATEMENT: TRY
CODE_STATEMENT: VOIDEXPRESSION
CODE_STATEMENT: USE_NAMESPACE
+CODE_STATEMENT: NAMESPACE_DECLARATION
CODE_STATEMENT: '{' CODE '}' {$$=$2;}
CODE_STATEMENT: '{' '}' {$$=0;}
-// code which may appear anywhere
+// code which may appear in methods
CODEPIECE: ';' {$$=0;}
CODEPIECE: CODE_STATEMENT
CODEPIECE: VARIABLE_DECLARATION
CODEPIECE: THROW
CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
-CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
-
//CODEBLOCK : '{' CODE '}' {$$=$2;}
//CODEBLOCK : '{' '}' {$$=0;}
CODEBLOCK : CODEPIECE ';' {$$=$1;}
ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
{
+PASS12
if(variable_exists($1))
syntaxerror("Variable %s already defined", $1);
+PASS1
+ new_variable($1, 0, 1, 0);
+PASS2
if(!is_subtype_of($3.t, $2)) {
syntaxerror("Can't convert %s to %s", $3.t->name,
$2->name);
}
- int index = new_variable($1, $2, 1);
+ char slot = 0;
+ int index = 0;
+ if(state->method->uses_slots) {
+ variable_t* v = find_slot(state, $1);
+ if(v && !v->init) {
+ // this variable is stored in a slot
+ v->init = 1;
+ v->type = $2;
+ slot = 1;
+ index = v->index;
+ }
+ }
+ if(!index) {
+ index = new_variable($1, $2, 1, 0);
+ }
+
+ $$ = slot?abc_getscopeobject(0, 1):0;
if($2) {
if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
- $$ = $3.c;
+ $$ = code_append($$, $3.c);
$$ = converttype($$, $3.t, $2);
- $$ = abc_setlocal($$, index);
} else {
code_free($3.c);
- $$ = defaultvalue(0, $2);
- $$ = abc_setlocal($$, index);
+ $$ = defaultvalue($$, $2);
}
} else {
if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
- $$ = $3.c;
+ $$ = code_append($$, $3.c);
$$ = abc_coerce_a($$);
- $$ = abc_setlocal($$, index);
} else {
+ // don't do anything
code_free($3.c);
- $$ = code_new();
+ code_free($$);
+ $$ = 0;
+ break;
}
}
-
- /* that's the default for a local register, anyway
- else {
- state->method->initcode = abc_pushundefined(state->method->initcode);
- state->method->initcode = abc_setlocal(state->method->initcode, index);
- }*/
- //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
+ if(slot) {
+ $$ = abc_setslot($$, index);
+ } else {
+ $$ = abc_setlocal($$, index);
+ }
}
/* ------------ control flow ------------------------- */
MAYBEELSE: "else" CODEBLOCK {$$=$2;}
//MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
-IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
+IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
$$ = code_new();
$$ = code_append($$, $4.c);
myjmp->branch = $$ = abc_nop($$);
}
$$ = var_block($$);
- old_state();
+ PASS12 old_state();
}
FOR_INIT : {$$=code_new();}
// (I don't see any easy way to revolve this conflict otherwise, as we
// can't touch VAR_READ without upsetting the precedence about "return")
FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
- $$=$2;new_variable($2,$3,1);
+ PASS1 $$=$2;new_variable($2,0,1,0);
+ PASS2 $$=$2;new_variable($2,$3,1,0);
}
FOR_IN_INIT : T_IDENTIFIER {
+ PASS12
$$=$1;
}
-FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
-FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
+FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
+FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
myif->branch = out;
$$ = var_block($$);
- old_state();
+ PASS12 old_state();
}
FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
- variable_t*var = find_variable($2);
+ variable_t*var = find_variable(state, $2);
char*tmp1name = concat2($2, "__tmp1__");
- int it = new_variable(tmp1name, TYPE_INT, 0);
+ int it = new_variable(tmp1name, TYPE_INT, 0, 0);
char*tmp2name = concat2($2, "__array__");
- int array = new_variable(tmp1name, 0, 0);
+ int array = new_variable(tmp1name, 0, 0, 0);
$$ = code_new();
$$ = code_append($$, $4.c);
myif->branch = out;
$$ = var_block($$);
- old_state();
free(tmp1name);
free(tmp2name);
+
+ PASS12 old_state();
}
-WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
+WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
$$ = code_new();
continuejumpsto($$, $1, cont);
$$ = var_block($$);
- old_state();
+ PASS12 old_state();
}
-DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
+DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
$$ = code_new();
code_t*loopstart = $$ = abc_label($$);
$$ = code_append($$, $3);
continuejumpsto($$, $1, cont);
$$ = var_block($$);
- old_state();
+ PASS12 old_state();
}
BREAK : "break" %prec prec_none {
DEFAULT: "default" ':' MAYBECODE {
$$ = $3;
}
-SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
+SWITCH : T_SWITCH '(' {PASS12 new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
$$=$4.c;
$$ = code_append($$, $7);
code_t*out = $$ = abc_pop($$);
}
$$ = var_block($$);
- old_state();
+ PASS12 old_state();
}
/* ------------ try / catch /finally ---------------- */
-CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
+CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
+ state->exception_name=$3;
+ PASS1 new_variable($3, 0, 0, 0);
+ PASS2 new_variable($3, $4, 0, 0);
+ }
'{' MAYBECODE '}' {
namespace_t name_ns = {ACCESS_PACKAGE, ""};
multiname_t name = {QNAME, &name_ns, 0, $3};
$$ = e;
code_t*c = 0;
- int i = find_variable_safe($3)->index;
+ int i = find_variable_safe(state, $3)->index;
e->target = c = abc_nop(0);
c = abc_setlocal(c, i);
c = code_append(c, $8);
c = abc_kill(c, i);
c = var_block(c);
- old_state();
+ PASS12 old_state();
}
-FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
+FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
$4 = var_block($4);
if(!$4) {
$$=0;
- old_state();
} else {
NEW(abc_exception_t, e)
e->exc_type = 0; //all exceptions
e->target = 0;
e->to = abc_nop(0);
e->to = code_append(e->to, $4);
- old_state();
$$ = e;
}
+ PASS12 old_state();
}
CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
}
}
-TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
+TRY : "try" '{' {PASS12 new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
code_t*out = abc_nop(0);
code_t*start = abc_nop(0);
int tmp;
if($6.finally)
- tmp = new_variable("__finally__", 0, 0);
+ tmp = new_variable("__finally__", 0, 0, 0);
abc_exception_list_t*l = $6.l;
int count=0;
list_concat(state->method->exceptions, $6.l);
$$ = var_block($$);
- old_state();
+ PASS12 old_state();
}
/* ------------ throw ------------------------------- */
THROW : "throw" %prec prec_none {
if(!state->exception_name)
syntaxerror("re-throw only possible within a catch block");
- variable_t*v = find_variable(state->exception_name);
+ variable_t*v = find_variable(state, state->exception_name);
$$=code_new();
$$=abc_getlocal($$, v->index);
$$=abc_throw($$);
WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
$$ = $3.c;
- $$ = abc_pushscope($$);
+ $$ = abc_pushwith($$);
$$ = code_append($$, $5);
$$ = abc_popscope($$);
}
/* ------------ classes and interfaces (header) -------------- */
-MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
+MAYBE_MODIFIERS : %prec above_function {PASS12 $$.flags=0;$$.ns=0;}
MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
-MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
-
-MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
- | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
- | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
- | KW_STATIC {PASS12 $$=FLAG_STATIC;}
- | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
- | KW_FINAL {PASS12 $$=FLAG_FINAL;}
- | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
- | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
- | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
- | T_NAMESPACE {PASS12 $$=FLAG_NAMESPACE;}
+MODIFIER_LIST : MODIFIER_LIST MODIFIER {
+ PASS12
+ $$.flags=$1.flags|$2.flags;
+ if($1.ns && $2.ns) syntaxerror("only one namespace allowed in one declaration");
+ $$.ns=$1.ns?$1.ns:$2.ns;
+
+}
+
+MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
+ | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
+ | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
+ | KW_STATIC {PASS12 $$.flags=FLAG_STATIC;$$.ns=0;}
+ | KW_DYNAMIC {PASS12 $$.flags=FLAG_DYNAMIC;$$.ns=0;}
+ | KW_FINAL {PASS12 $$.flags=FLAG_FINAL;$$.ns=0;}
+ | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;}
+ | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;}
+ | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;}
+ | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE;
+ $$.ns=$1;
+ }
EXTENDS : {$$=registry_getobjectclass();}
EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
EXTENDS IMPLEMENTS_LIST
- '{' {PASS12 startclass($1,$3,$4,$5);}
+ '{' {PASS12 startclass(&$1,$3,$4,$5);}
MAYBE_CLASS_BODY
'}' {PASS12 endclass();$$=0;}
INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
EXTENDS_LIST
- '{' {PASS12 startclass($1|FLAG_INTERFACE,$3,0,$4);}
+ '{' {PASS12 $1.flags|=FLAG_INTERFACE;
+ startclass(&$1,$3,0,$4);}
MAYBE_INTERFACE_BODY
'}' {PASS12 endclass();$$=0;}
}
IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
PASS12
- $1 |= FLAG_PUBLIC;
- if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
+ $1.flags |= FLAG_PUBLIC;
+ if($1.flags&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
syntaxerror("invalid method modifiers: interface methods always need to be public");
}
- startfunction(0,$1,$3,$4,&$6,$8);
- endfunction(0,$1,$3,$4,&$6,$8, 0);
+ startfunction(&$1,$3,$4,&$6,$8);
+ endfunction(&$1,$3,$4,&$6,$8, 0);
list_deep_free($6.list);
}
VARCONST: "var" | "const"
-SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1);} MAYBETYPE MAYBEEXPRESSION {
- int flags = $1;
- U8 access = flags2access($1);
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {setslotstate(&$1,$2);} SLOT_LIST {$$=$4;setslotstate(0, 0);}
+
+SLOT_LIST: ONE_SLOT {$$ = $1;}
+SLOT_LIST: SLOT_LIST ',' ONE_SLOT {$$ = code_append($1, $3);}
+
+ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
+{
+ int flags = slotstate_flags->flags;
+ namespace_t ns = modifiers2access(slotstate_flags);
varinfo_t* info = 0;
if(state->cls) {
- memberinfo_t*i = registry_findmember(state->cls->info, $3, 1);
+ memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
if(i) {
check_override(i, flags);
}
- info = varinfo_register_onclass(state->cls->info, access, $3);
+ info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
} else {
- slotinfo_t*i = registry_find(state->package, $3);
+ slotinfo_t*i = registry_find(state->package, $1);
if(i) {
- syntaxerror("package %s already contains '%s'", state->package, $3);
+ syntaxerror("package %s already contains '%s'", state->package, $1);
}
- info = varinfo_register_global(access, state->package, $3);
+ if(ns.name && ns.name[0]) {
+ syntaxerror("namespaces not allowed on package-level variables");
+ }
+ info = varinfo_register_global(ns.access, state->package, $1);
}
- info->type = $5;
+ info->type = $2;
info->flags = flags;
/* slot name */
- namespace_t mname_ns = {access, ""};
- multiname_t mname = {QNAME, &mname_ns, 0, $3};
+ multiname_t mname = {QNAME, &ns, 0, $1};
trait_list_t**traits;
code_t**code;
if(!state->cls) {
// global variable
- mname_ns.name = state->package;
+ ns.name = state->package;
traits = &global->init->traits;
code = &global->init->method->body->code;
} else if(flags&FLAG_STATIC) {
}
trait_t*t=0;
- if($5) {
- MULTINAME(m, $5);
+ if($2) {
+ MULTINAME(m, $2);
t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
} else {
t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
/* initalization code (if needed) */
code_t*c = 0;
- if($6.c && !is_pushundefined($6.c)) {
+ if($3.c && !is_pushundefined($3.c)) {
c = abc_getlocal_0(c);
- c = code_append(c, $6.c);
- c = converttype(c, $6.t, $5);
+ c = code_append(c, $3.c);
+ c = converttype(c, $3.t, $2);
c = abc_setslot(c, t->slot_id);
}
*code = code_append(*code, c);
- if($2==KW_CONST) {
+ if(slotstate_varconst==KW_CONST) {
t->kind= TRAIT_CONST;
}
$$=0;
- setstaticfunction(0);
}
/* ------------ constants -------------------------------------- */
STATICCONSTANT : "null" {$$ = constant_new_null($1);}
STATICCONSTANT : T_IDENTIFIER {
// TODO
- as3_warning("Couldn't resolve %s", $1);
+ as3_warning("Couldn't evaluate constant value of %s", $1);
$$ = constant_new_null($1);
}
}
PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
- PASS1 $$=0;
- PASS2
- $$ = malloc(sizeof(param_t));
+ PASS12
+ $$ = rfx_calloc(sizeof(param_t));
$$->name=$1;
$$->type = $3;
+ PASS2
$$->value = $4;
}
PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
- PASS1 $$=0;
- PASS2
- $$ = malloc(sizeof(param_t));
+ PASS12
+ $$ = rfx_calloc(sizeof(param_t));
$$->name=$1;
$$->type = TYPE_ANY;
+ PASS2
$$->value = $2;
}
-GETSET : "get" {$$=$1;}
- | "set" {$$=$1;}
- | {$$=0;}
+GETSET : "get"
+ | "set"
+ | {PASS12 $$=0;}
FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
- MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}'
+ MAYBETYPE '{' {PASS12 startfunction(&$1,$3,$4,&$6,$8);} MAYBECODE '}'
{
- PASS1 old_state();list_deep_free($6.list);
+ PASS1
+ endfunction(&$1,$3,$4,&$6,0,0);
PASS2
if(!state->method->info) syntaxerror("internal error");
code_t*c = method_header(state->method);
c = wrap_function(c, 0, $11);
- endfunction(0,$1,$3,$4,&$6,$8,c);
+ endfunction(&$1,$3,$4,&$6,$8,c);
+ PASS12
list_deep_free($6.list);
$$=0;
}
INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
'{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
{
- PASS1 old_state();list_deep_free($4.list);
+ PASS1
+ endfunction(0,0,$2,&$4,0,0);
PASS2
methodinfo_t*f = state->method->info;
if(!f || !f->kind) syntaxerror("internal error");
c = wrap_function(c, 0, $9);
int index = state->method->var_index;
- endfunction(0,0,0,$2,&$4,$6,c);
- list_deep_free($4.list);
+ endfunction(0,0,$2,&$4,$6,c);
$$.c = abc_getlocal(0, index);
$$.t = TYPE_FUNCTION(f);
+
+ PASS12 list_deep_free($4.list);
}
/* ------------- package + class ids --------------- */
CLASS: T_IDENTIFIER {
- PASS1 $$=0;
+ PASS1 static slotinfo_t c;
+ memset(&c, 0, sizeof(c));
+ c.name = $1;
+ $$ = (classinfo_t*)&c;
PASS2
slotinfo_t*s = find_class($1);
if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
}
PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
- PASS1 static classinfo_t c;
+ PASS1 static slotinfo_t c;
memset(&c, 0, sizeof(c));
c.package = $1;
c.name = $3;
- $$=&c;
+ $$=(classinfo_t*)&c;
PASS2
slotinfo_t*s = registry_find($1, $3);
if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
-TYPE : CLASS_SPEC {$$=$1;}
- | '*' {$$=registry_getanytype();}
- | "void" {$$=registry_getanytype();}
+TYPE : CLASS_SPEC {PASS12 $$=$1;}
+ | '*' {PASS12 $$=registry_getanytype();}
+ | "void" {PASS12 $$=registry_getanytype();}
/*
| "String" {$$=registry_getstringclass();}
| "int" {$$=registry_getintclass();}
| "Number" {$$=registry_getnumberclass();}
*/
-MAYBETYPE: ':' TYPE {$$=$2;}
-MAYBETYPE: {$$=0;}
+MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
+MAYBETYPE: {PASS12 $$=0;}
/* ----------function calls, delete, constructor calls ------ */
multiname_destroy(name);
} else if($$.c->opcode == OPCODE_GETSLOT) {
int slot = (int)(ptroff_t)$$.c->data[0];
- trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
+ trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
multiname_t*name = t->name;
$$.c = code_cutlast($$.c);
$$.c = code_append($$.c, paramcode);
$$.c = code_append($$.c, paramcode);
$$.c = abc_callproperty2($$.c, name, $3.len);
multiname_destroy(name);
- } else if($$.c->opcode == OPCODE_GETSLOT) {
+ } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
int slot = (int)(ptroff_t)$$.c->data[0];
- trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
+ trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
if(t->kind!=TRAIT_METHOD) {
//ok: flash allows to assign closures to members.
}
$$.c->opcode = OPCODE_DELETEPROPERTY;
} else if($$.c->opcode == OPCODE_GETSLOT) {
int slot = (int)(ptroff_t)$$.c->data[0];
- multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
+ multiname_t*name = traits_find_slotid(state->cls->abc->traits,slot)->name;
$$.c = code_cutlast($$.c);
$$.c = abc_deleteproperty2($$.c, name);
} else {
code_t*j2 = $$.c = abc_jump($$.c, 0);
$$.c = j1->branch = abc_label($$.c);
$$.c = code_append($$.c, $5.c);
- $$.c = converttype($$.c, $3.t, $$.t);
+ $$.c = converttype($$.c, $5.t, $$.t);
$$.c = j2->branch = abc_label($$.c);
}
classinfo_t*t = state->cls->info->superclass;
if(!t) t = TYPE_OBJECT;
- memberinfo_t*f = registry_findmember(t, $3, 1);
- namespace_t ns = {f->access, ""};
+ memberinfo_t*f = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
+
MEMBER_MULTINAME(m, f, $3);
$$.c = 0;
$$.c = abc_getlocal_0($$.c);
is_static = 1;
}
if(t) {
- memberinfo_t*f = registry_findmember(t, $3, 1);
+ memberinfo_t*f = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
char noslot = 0;
if(f && !is_static != !(f->flags&FLAG_STATIC))
noslot=1;
}
VAR_READ : T_IDENTIFIER {
+ PASS1
+ /* Queue unresolved identifiers for checking against the parent
+ function's variables.
+ We consider everything which is not a local variable "unresolved".
+ This encompasses class names, members of the surrounding class
+ etc. which *correct* because local variables of the parent function
+ would shadow those.
+ */
+ if(state->method->inner && !find_variable(state, $1)) {
+ unknown_variable($1);
+ }
+ PASS2
+
$$.t = 0;
$$.c = 0;
slotinfo_t*a = 0;
variable_t*v;
/* look at variables */
- if((v = find_variable($1))) {
+ if((v = find_variable(state, $1))) {
// $1 is a local variable
$$.c = abc_getlocal($$.c, v->index);
$$.t = v->type;
break;
}
+ if((v = find_slot(state, $1))) {
+ $$.c = abc_getscopeobject($$.c, 1);
+ $$.c = abc_getslot($$.c, v->index);
+ $$.t = v->type;
+ break;
+ }
int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
/* look at current class' members */
- if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
+ if(state->cls && (f = registry_findmember_nsset(state->cls->info, state->active_namespaces, $1, 1)) &&
(f->flags&FLAG_STATIC) >= i_am_static) {
// $1 is a function in this class
int var_is_static = (f->flags&FLAG_STATIC);
// ----------------- namespaces -------------------------------------------------
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
+NAMESPACE_ID : "namespace" T_IDENTIFIER {
+ PASS12
+ tokenizer_register_namespace($2);
+ $$=$2;
+}
-USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
+ $$=0;
+}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_IDENTIFIER {
+ $$=0;
+}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_STRING {
+ $$=0;
+}
+USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
PASS12
- tokenizer_register_namespace($3);
+ tokenizer_register_namespace($3->name);
$$=0;
}