-/* parser.lex
+/* parser.y
Routines for compiling Flash2 AVM2 ABC Actionscript
}
-%token<id> T_IDENTIFIER T_NAMESPACE
+%token<id> T_IDENTIFIER
%token<str> T_STRING
%token<regexp> T_REGEXP
%token<token> T_EMPTY
// needed for "return" precedence:
%nonassoc T_STRING T_REGEXP
%nonassoc T_INT T_UINT T_FLOAT KW_NAN
-%left T_NAMESPACE
%nonassoc "false" "true" "null" "undefined" "super" "function"
%left above_function
-
%{
int variable_count;
dict_t*unresolved_variables;
+ dict_t*allvars; // all variables (in all sublevels, but not for inner functions)
char inner;
char uses_parent_function;
methodstate_list_t*innerfunctions;
};
+methodstate_t*methodstate_new()
+{
+ NEW(methodstate_t,m);
+ m->allvars = dict_new();
+ return m;
+}
void methodstate_destroy(methodstate_t*m)
{
- dict_destroy(m->unresolved_variables);
- m->unresolved_variables = 0;
+ dict_destroy(m->unresolved_variables); m->unresolved_variables = 0;
list_free(m->innerfunctions);m->innerfunctions=0;
+
+ if(m->allvars) {
+ DICT_ITERATE_DATA(m->allvars, void*, data) {free(data);}
+ m->allvars = 0;
+ }
}
typedef struct _state {
dict_t*import_toplevel_packages;
dict_t*imports;
+ dict_t*namespaces;
namespace_list_t*active_namespace_urls;
char has_own_imports;
int switch_var;
dict_t*vars;
- dict_t*allvars; // also contains variables from sublevels
} state_t;
typedef struct _global {
state->old = oldstate;
state->new_vars = 0;
- trie_remember(active_namespaces);
+ state->namespaces = dict_new();
if(oldstate)
state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
if(state->vars) {
dict_destroy(state->vars);state->vars=0;
}
- if(state->new_vars && state->allvars) {
- parserassert(!state->old || state->old->allvars != state->allvars);
- DICT_ITERATE_DATA(state->allvars, void*, data) {
- free(data);
- }
- dict_destroy(state->allvars);
- }
list_free(state->active_namespace_urls)
state->active_namespace_urls = 0;
static void old_state()
{
- trie_rollback(active_namespaces);
-
if(!state || !state->old)
syntaxerror("invalid nesting");
state_t*leaving = state;
syntaxerror("invalid call to initialize_file during parsing of another file");
}
- active_namespaces = trie_new();
-
new_state();
state->package = internal_filename_package = strdup(filename);
- state->allvars = dict_new();
global->token2info = dict_lookup(global->file2token2info,
current_filename // use long version
state->method = rfx_calloc(sizeof(methodstate_t));
dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
+ state->method->allvars = dict_new();
} else {
state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
state->method->variable_count = 0;
methodstate_t*is_inner_method;
} variable_t;
-static variable_t* find_variable(state_t*s, char*name)
+static variable_t* find_variable(state_t*s, const char*name)
{
if(s->method->no_variable_scoping) {
- return dict_lookup(s->allvars, name);
+ return dict_lookup(s->method->allvars, name);
} else {
state_t*top = s;
while(s) {
static code_t*defaultvalue(code_t*c, classinfo_t*type)
{
+ parserassert(!type || type->kind!=INFOTYPE_UNRESOLVED);
if(TYPE_IS_INT(type)) {
c = abc_pushbyte(c, 0);
} else if(TYPE_IS_UINT(type)) {
if(!method->no_variable_scoping)
{
if(dict_contains(state->vars, name)) {
- *(int*)0=0;
syntaxerror("variable %s already defined", name);
}
dict_put(state->vars, name, v);
}
if(method->no_variable_scoping &&
as3_pass==2 &&
- dict_contains(state->allvars, name))
+ dict_contains(state->method->allvars, name))
{
- variable_t*v = dict_lookup(state->allvars, name);
- if(v->type != type)
+ variable_t*v = dict_lookup(state->method->allvars, name);
+ if(v->type != type && (!v->type || v->type->kind!=INFOTYPE_UNRESOLVED)) {
syntaxerror("variable %s already defined.", name);
+ }
return v;
}
- dict_put(state->allvars, name, v);
+ dict_put(state->method->allvars, name, v);
}
return v;
static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
{
c = code_append(c, header);
- c = code_append(c, var_block(body, state->method->no_variable_scoping?state->allvars:state->vars));
+ c = code_append(c, var_block(body, state->method->no_variable_scoping?state->method->allvars:state->vars));
/* append return if necessary */
if(!c || (c->opcode != OPCODE_RETURNVOID &&
c->opcode != OPCODE_RETURNVALUE)) {
#define FLAG_PACKAGEINTERNAL 2048
#define FLAG_NAMESPACE 4096
+static slotinfo_t* find_class(const char*name);
+
+const char* lookup_namespace(const char*name)
+{
+ state_t*s = state;
+ while(s) {
+ const char*url = dict_lookup(s->namespaces, name);
+ if(url)
+ return url;
+ s = s->old;
+ }
+ varinfo_t*a;
+ registry_find(state->package, name);
+ if(( a = (varinfo_t*)find_class(name) )) {
+ if(a->kind == INFOTYPE_VAR) {
+ if(!a->value || !NS_TYPE(a->value->type))
+ syntaxerror("%s.%s is not a namespace", a->package, a->name);
+ return a->value->ns->name;
+ }
+ }
+ return 0;
+}
+
static namespace_t modifiers2access(modifiers_t*mod)
{
namespace_t ns;
if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
syntaxerror("invalid combination of access levels and namespaces");
ns.access = ACCESS_NAMESPACE;
- state_t*s = state;
- const char*url = (const char*)trie_lookup(active_namespaces, (unsigned char*)mod->ns);
- if(!url) {
- /* shouldn't happen- the tokenizer only reports something as a namespace
- if it was already registered */
- trie_dump(active_namespaces);
- syntaxerror("unknown namespace: %s", mod->ns);
- }
+ const char*url = lookup_namespace(mod->ns);
+ if(!url) {
+ if(as3_pass>1) {
+ syntaxerror("unknown namespace: %s (pass %d)", mod->ns, as3_pass);
+ } else {
+ url = mod->ns;
+ }
+ }
ns.name = url;
} else if(mod->flags&FLAG_PUBLIC) {
if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
}
return ns;
}
-static slotinfo_t* find_class(const char*name);
-static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
+static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse, char is_static)
{
- return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
+ return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse, is_static);
}
static void innerfunctions2vars(methodstate_t*m)
m->scope_code = add_scope_code(m->scope_code, m, 0);
if(m->slots) {
/* exchange unresolved identifiers with the actual objects */
- DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
- if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
- classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
+ DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v1) {
+ if(v1->type && v1->type->kind == INFOTYPE_UNRESOLVED) {
+ classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v1->type);
if(!type || type->kind != INFOTYPE_CLASS) {
- syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
+ syntaxerror("Couldn't find class %s::%s (%s)", v1->type->package, v1->type->name, name);
}
- v->type = type;
+ v1->type = type;
}
}
+ }
+ if(m->allvars) {
+ DICT_ITERATE_ITEMS(m->allvars, char*, name2, variable_t*, v2) {
+ if(v2->type && v2->type->kind == INFOTYPE_UNRESOLVED) {
+ classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v2->type);
+ if(!type || type->kind != INFOTYPE_CLASS) {
+ syntaxerror("Couldn't find class %s::%s (%s)", v2->type->package, v2->type->name, name2);
+ }
+ v2->type = type;
+ }
+ }
}
}
}
if(as3_pass==1) {
state->cls = rfx_calloc(sizeof(classstate_t));
- state->cls->init = rfx_calloc(sizeof(methodstate_t));
- state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
+ state->cls->init = methodstate_new();
+ state->cls->static_init = methodstate_new();
state->cls->static_init->is_static=FLAG_STATIC;
/* notice: we make no effort to initialize the top variable (local0) here,
even though it has special meaning. We just rely on the fact
{
if(!m)
return;
- if(m->parent == state->cls->info)
+ if(m->parent == state->cls->info && !((flags^m->flags)&FLAG_STATIC))
syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name);
if(!m->parent)
syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name);
minfo->return_type = return_type;
} else if(getset != KW_GET && getset != KW_SET) {
//class method
- memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
+ memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0, mod->flags&FLAG_STATIC);
if(m) {
syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
}
- minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
+ minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name, mod->flags&FLAG_STATIC);
minfo->return_type = return_type;
// getslot on a member slot only returns "undefined", so no need
// to actually store these
} 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, ns.name, name, 1);
+ minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1, mod->flags&FLAG_STATIC);
if(minfo) {
if(minfo->kind!=INFOTYPE_VAR)
syntaxerror("class already contains a method called '%s'", name);
type?type->name:"*");
}*/
} else {
- minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
+ minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name, mod->flags&FLAG_STATIC);
minfo->kind = INFOTYPE_VAR; //hack
minfo->subtype = gs;
minfo->return_type = type;
new_state();
state->new_vars = 1;
- state->allvars = dict_new();
if(as3_pass == 1) {
- state->method = rfx_calloc(sizeof(methodstate_t));
+ state->method = methodstate_new();
state->method->inner = 1;
state->method->is_static = parent_method->is_static;
state->method->variable_count = 0;
}
new_state();
state->new_vars = 1;
- state->allvars = dict_new();
if(as3_pass == 1) {
- state->method = rfx_calloc(sizeof(methodstate_t));
+ state->method = methodstate_new();
state->method->has_super = 0;
state->method->is_static = mod->flags&FLAG_STATIC;
parserassert(state->method);
if(state->cls) {
- memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2);
+ memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2, mod->flags&FLAG_STATIC);
check_override(m, mod->flags);
}
if(state->method->unresolved_variables) {
DICT_ITERATE_KEY(state->method->unresolved_variables, char*, vname) {
- if(!state->method->no_variable_scoping && dict_contains(state->allvars, vname)) {
- variable_t*v = dict_lookup(state->allvars, vname);
+ if(!state->method->no_variable_scoping && dict_contains(state->method->allvars, vname)) {
+ variable_t*v = dict_lookup(state->method->allvars, vname);
if(!v->is_inner_method) {
state->method->no_variable_scoping = 1;
- as3_warning("function %s uses forward or outer block variable references (%s): switching into compatiblity mode", name, vname);
+ as3_warning("function %s uses forward or outer block variable references (%s): switching into compatibility mode", name, vname);
}
}
}
methodstate_list_t*ml = state->method->innerfunctions;
while(ml) {
- insert_unresolved(ml->methodstate, xvars, state->allvars);
+ insert_unresolved(ml->methodstate, xvars, state->method->allvars);
ml = ml->next;
}
if(state->method->uses_slots) {
state->method->slots = dict_new();
int i = 1;
- DICT_ITERATE_ITEMS(state->allvars, char*, name, variable_t*, v) {
+ DICT_ITERATE_ITEMS(state->method->allvars, char*, name, variable_t*, v) {
if(!name) syntaxerror("internal error");
if(v->index && dict_contains(xvars, name)) {
v->init = v->kill = 0;
state->method->uses_slots = i;
dict_destroy(state->vars);state->vars = 0;
parserassert(state->new_vars);
- dict_destroy(state->allvars);state->allvars = 0;
}
old_state();
return 0;
if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
return c;
+
as3_error("can't convert type %s%s%s to %s%s%s",
from->package, from->package[0]?".":"", from->name,
to->package, to->package[0]?".":"", to->name);
if(variable_exists($1))
syntaxerror("Variable %s already defined", $1);
PASS1
- new_variable(state->method, $1, 0, 1, 0);
+ new_variable(state->method, $1, $2, 1, 0);
PASS2
char slot = 0;
CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
state->exception_name=$3;
- PASS1 new_variable(state->method, $3, 0, 0, 0);
+ PASS1 new_variable(state->method, $3, $4, 0, 0);
PASS2 new_variable(state->method, $3, $4, 0, 0);
}
'{' MAYBECODE '}' {
| "package" {PASS12 $$="package";}
| "namespace" {PASS12 $$="namespace";}
| "NaN" {PASS12 $$="NaN";}
- | T_NAMESPACE {PASS12 $$=$1;}
PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
IMPORT : "import" PACKAGEANDCLASS {
PASS12
slotinfo_t*s = registry_find($2->package, $2->name);
- if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
+ if(!s && as3_pass==1) {
as3_schedule_class($2->package, $2->name);
}
+ /*if(s && s->kind == INFOTYPE_VAR && TYPE_IS_NAMESPACE(s->type)) {
+ trie_put(active_namespaces, (unsigned char*)$2->name, 0);
+ }*/
state_has_imports();
dict_put(state->imports, $2->name, $2);
import_toplevel($2->package);
| 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;
+ | T_IDENTIFIER {PASS12 $$.flags=FLAG_NAMESPACE;
$$.ns=$1;
}
CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
CLASS_BODY_ITEM : SLOT_DECLARATION
CLASS_BODY_ITEM : FUNCTION_DECLARATION
+CLASS_BODY_ITEM : '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
CLASS_BODY_ITEM : CODE_STATEMENT {
code_t*c = state->cls->static_init->header;
varinfo_t* info = 0;
if(state->cls) {
- memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
+ memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1, slotstate_flags->flags&FLAG_STATIC);
if(i) {
check_override(i, flags);
}
- info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
+ info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1, slotstate_flags->flags&FLAG_STATIC);
} else {
slotinfo_t*i = registry_find(state->package, $1);
if(i) {
}
}
-//CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
CONSTANT : T_INT {$$ = constant_new_int($1);}
CONSTANT : T_UINT {
$$ = constant_new_uint($1);
CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
-/*CONSTANT : T_NAMESPACE {
- // TODO
- $$ = constant_new_namespace(namespace_new_namespace($1.url));
-}*/
-
/* ---------------------------xml ------------------------------ */
%code {
slotinfo_t*s = find_class($1);
if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
$$ = (classinfo_t*)s;
+ registry_use(s);
}
PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
free($1);$1=0;
$$ = (classinfo_t*)s;
+ registry_use(s);
}
CLASS_SPEC: PACKAGEANDCLASS
syntaxerror("super keyword not allowed outside a class");
classinfo_t*t = state->cls->info->superclass;
if(!t) t = TYPE_OBJECT;
- memberinfo_t*f = findmember_nsset(t, $3, 1);
+ memberinfo_t*f = findmember_nsset(t, $3, 1, 0);
MEMBER_MULTINAME(m, f, $3);
typedcode_t v;
v.c = 0;
ID_OR_NS : T_IDENTIFIER {$$=$1;}
ID_OR_NS : '*' {$$="*";}
-ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
SUBNODE: X_IDENTIFIER
| '*' {$$="*";}
-/*
-MAYBE_NS: T_IDENTIFIER "::" {$$=$1;}
- | T_NAMESPACE "::" {$$=(char*)$1;}
- | '*' "::" {$$="*";}
- | {$$=0;}*/
+%code {
+ node_t* resolve_identifier(const char*name);
+ node_t* get_descendants(node_t*e,const char*ns,const char*subnode,char multi, char attr)
+ {
+ typedcode_t v = node_read(e);
+ typedcode_t w;
+
+ multiname_t m = {0,0,0,subnode};
+ namespace_t zero = {ZERONAMESPACE,"*"};
+ if(!strcmp(ns,"*")) {
+ m.ns = &zero;
+ m.type = attr?QNAMEA:QNAME;
+ } else {
+ typedcode_t w = node_read(resolve_identifier(ns));
+ if(!TYPE_IS_NAMESPACE(w.t)) {
+ as3_softwarning("%s might not be a namespace", ns);
+ }
+ v.c = code_append(v.c, w.c);
+ v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
+ m.type = attr?RTQNAMEA:RTQNAME;
+ }
+
+ if(!multi) {
+ v.c = abc_getproperty2(v.c, &m);
+ } else {
+ v.c = abc_getdescendants2(v.c, &m);
+ }
+
+ if(TYPE_IS_XML(v.t)) {
+ v.t = TYPE_XMLLIST;
+ } else {
+ v.c = abc_coerce_a(v.c);
+ v.t = TYPE_ANY;
+ }
+ return mkcodenode(v);
+ }
+};
E : E '.' ID_OR_NS "::" SUBNODE {
- typedcode_t v = node_read($1);
- typedcode_t w = node_read(resolve_identifier($3));
- v.c = code_append(v.c, w.c);
- if(!TYPE_IS_NAMESPACE(w.t)) {
- as3_softwarning("%s might not be a namespace", $3);
- }
- v.c = converttype(v.c, w.t, TYPE_NAMESPACE);
- multiname_t m = {RTQNAME, 0, 0, $5};
- v.c = abc_getproperty2(v.c, &m);
- if(TYPE_IS_XML(v.t)) {
- v.t = TYPE_XMLLIST;
- } else {
- v.c = abc_coerce_a(v.c);
- v.t = TYPE_ANY;
- }
- $$ = mkcodenode(v);
+ $$ = get_descendants($1, $3, $5, 0, 0);
}
E : E ".." SUBNODE {
typedcode_t v = node_read($1);
v.t = TYPE_XMLLIST;
$$ = mkcodenode(v);
}
+E : E ".." ID_OR_NS "::" SUBNODE {
+ $$ = get_descendants($1, $3, $5, 1, 0);
+}
E : E '.' '[' E ']' {
typedcode_t v = node_read($1);
typedcode_t w = node_read($4);
v.t = TYPE_STRING;
$$ = mkcodenode(v);
}
+
+E : E '.' '@' ID_OR_NS "::" SUBNODE {
+ $$ = get_descendants($1, $4, $6, 0, 1);
+}
+
E : E ".." '@' SUBNODE {
typedcode_t v = node_read($1);
multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
v.t = TYPE_STRING;
$$ = mkcodenode(v);
}
+E : E ".." '@' ID_OR_NS "::" SUBNODE {
+ $$ = get_descendants($1, $4, $6, 1, 1);
+}
+
E : E '.' '@' '[' E ']' {
typedcode_t v = node_read($1);
typedcode_t w = node_read($5);
t = t->data;
is_static = 1;
}
- if(TYPE_IS_XML(t)) {
+ if(TYPE_IS_XML(t) && !findmember_nsset(t, $3, 1, is_static)) {
multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
$$.c = abc_getproperty2($$.c, &m);
$$.c = abc_coerce_a($$.c);
if(t->subtype==INFOTYPE_UNRESOLVED) {
syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
}
- memberinfo_t*f = findmember_nsset(t, $3, 1);
+ memberinfo_t*f = findmember_nsset(t, $3, 1, is_static);
char noslot = 0;
if(f && !is_static != !(f->flags&FLAG_STATIC))
noslot=1;
return mkcodenode(o);
}
- node_t* resolve_identifier(char*name)
+ node_t* resolve_identifier(const char*name)
{
typedcode_t o;
o.t = 0;
int i_am_static = state->method->is_static;
- /* look at current class' members */
- if(!state->method->inner &&
- !state->xmlfilter &&
- state->cls &&
- (f = findmember_nsset(state->cls->info, name, 1)))
- {
- // name is a member or attribute in this class
- int var_is_static = (f->flags&FLAG_STATIC);
-
- if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
- /* if the variable is a constant (and we know what is evaluates to), we
- can just use the value itself */
- varinfo_t*v = (varinfo_t*)f;
- if(v->value) {
- return mkconstnode(v->value);
- }
- }
-
- if(var_is_static >= i_am_static) {
- if(f->kind == INFOTYPE_METHOD) {
- o.t = TYPE_FUNCTION(f);
- } else {
- o.t = f->type;
- }
-
- if(var_is_static && !i_am_static) {
- /* access to a static member from a non-static location.
- do this via findpropstrict:
- there doesn't seem to be any non-lookup way to access
- static properties of a class */
- state->method->late_binding = 1;
- o.t = f->type;
- namespace_t ns = {f->access, f->package};
- multiname_t m = {QNAME, &ns, 0, name};
- o.c = abc_findpropstrict2(o.c, &m);
- o.c = abc_getproperty2(o.c, &m);
- return mkcodenode(o);
- } else if(f->slot>0) {
- o.c = abc_getlocal_0(o.c);
- o.c = abc_getslot(o.c, f->slot);
- return mkcodenode(o);
- } else {
- MEMBER_MULTINAME(m, f, name);
- o.c = abc_getlocal_0(o.c);
- o.c = abc_getproperty2(o.c, &m);
- return mkcodenode(o);
- }
- }
- }
+ if(!state->method->inner && !state->xmlfilter && state->cls)
+ {
+ /* look at current class' members */
+ if((f = findmember_nsset(state->cls->info, name, 1, i_am_static)))
+ {
+ // name is a member or attribute in this class
+ int var_is_static = (f->flags&FLAG_STATIC);
+
+ if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
+ /* if the variable is a constant (and we know what is evaluates to), we
+ can just use the value itself */
+ varinfo_t*v = (varinfo_t*)f;
+ if(v->value) {
+ return mkconstnode(v->value);
+ }
+ }
+
+ if(var_is_static >= i_am_static) {
+ if(f->kind == INFOTYPE_METHOD) {
+ o.t = TYPE_FUNCTION(f);
+ } else {
+ o.t = f->type;
+ }
+
+ if(var_is_static && !i_am_static) {
+ /* access to a static member from a non-static location.
+ do this via findpropstrict:
+ there doesn't seem to be any non-lookup way to access
+ static properties of a class */
+ state->method->late_binding = 1;
+ o.t = f->type;
+ namespace_t ns = {f->access, f->package};
+ multiname_t m = {QNAME, &ns, 0, name};
+ o.c = abc_findpropstrict2(o.c, &m);
+ o.c = abc_getproperty2(o.c, &m);
+ return mkcodenode(o);
+ } else if(f->slot>0) {
+ o.c = abc_getlocal_0(o.c);
+ o.c = abc_getslot(o.c, f->slot);
+ return mkcodenode(o);
+ } else {
+ MEMBER_MULTINAME(m, f, name);
+ o.c = abc_getlocal_0(o.c);
+ o.c = abc_getproperty2(o.c, &m);
+ return mkcodenode(o);
+ }
+ }
+ }
+ /* special case: it's allowed to access non-static constants
+ from a static context */
+ if(i_am_static && (f=findmember_nsset(state->cls->info, name, 1, 0))) {
+ if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
+ varinfo_t*v = (varinfo_t*)f;
+ if(v->value) {
+ return mkconstnode(v->value);
+ }
+ }
+ }
+ }
/* look at actual classes, in the current package and imported */
if(!state->xmlfilter && (a = find_class(name))) {
+ registry_use(a);
if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
o.c = abc_getlocal_0(0);
o.t = TYPE_CLASS((classinfo_t*)a);
if(!state->xmlfilter &&
(dict_contains(state->import_toplevel_packages, name) ||
registry_ispackage(name))) {
- o.c = abc___pushpackage__(o.c, name);
+ o.c = abc___pushpackage__(o.c, (char*)name);
o.t = 0;
return mkcodenode(o); //?
}
}
NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
PASS12
- trie_put(active_namespaces, (unsigned char*)$2->name, (void*)$2->url);
+ dict_put(state->namespaces, (unsigned char*)$2->name, (void*)$2->url);
namespace_t access = modifiers2access(&$1);
varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
{
- as3_warning("default xml namespaces not supported yet");
$$ = 0;
+ $$ = code_append($$, node_read($4).c);
+ $$ = abc_dxnslate($$);
}
USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
PASS12
- const char*url = $3->name;
varinfo_t*s = (varinfo_t*)$3;
if(s->kind == INFOTYPE_UNRESOLVED) {
syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
if(!s->value || !NS_TYPE(s->value->type))
syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
- url = s->value->ns->name;
- trie_put(active_namespaces, (unsigned char*)$3->name, (void*)url);
+ const char*url = s->value->ns->name;
+ dict_put(state->namespaces, (unsigned char*)$3->name, (void*)url);
add_active_url(url);
$$=0;
}