char uses_parent_function;
int uses_slots;
dict_t*slots;
+ int activation_var;
abc_method_t*abc;
int var_index; // for inner methods
import_list_t*wildcard_imports;
dict_t*import_toplevel_packages;
dict_t*imports;
- namespace_list_t*active_namespaces;
- namespace_decl_list_t*new_namespaces;
- dict_t*namespace2url;
+
+ namespace_list_t*active_namespace_urls;
+
char has_own_imports;
char new_vars; // e.g. transition between two functions
state = s;
state->level++;
state->has_own_imports = 0;
- state->new_namespaces = 0;
state->vars = dict_new();
state->old = oldstate;
state->new_vars = 0;
- state->namespace2url = 0;
+
+ trie_remember(active_namespaces);
+
+ if(oldstate)
+ state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
}
static void state_has_imports()
{
dict_destroy(state->vars);state->vars=0;
}
+ list_free(state->active_namespace_urls)
+ state->active_namespace_urls = 0;
+
free(state);
}
static void old_state()
{
+ trie_rollback(active_namespaces);
+
if(!state || !state->old)
syntaxerror("invalid nesting");
state_t*leaving = state;
state = state->old;
- namespace_decl_list_t*nl=leaving->new_namespaces;
- while(nl) {
- tokenizer_unregister_namespace(nl->namespace_decl->name);
- nl = nl->next;
- }
- if(leaving->namespace2url)
- dict_destroy(leaving->namespace2url);
-
if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
free(leaving->method);
leaving->method=0;
free(leaving->cls);
leaving->cls=0;
}
-
+
state_destroy(leaving);
}
if(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);
int index;
classinfo_t*type;
char init;
+ char is_parameter;
methodstate_t*is_inner_method;
} variable_t;
}
-static code_t* add_scope_code(code_t*c, methodstate_t*m)
+static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
{
- if(m->uses_slots || (m->late_binding && !m->inner)) {
+ if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
c = abc_getlocal_0(c);
c = abc_pushscope(c);
}
if(m->uses_slots) {
- /* FIXME: does this need to be the same activation object as
- in the function header? */
- c = abc_newactivation(c);
- c = abc_pushscope(c);
+ /* FIXME: this alloc_local() causes variable indexes to be
+ different in pass2 than in pass1 */
+ if(!m->activation_var)
+ m->activation_var = alloc_local();
+ if(init) {
+ c = abc_newactivation(c);
+ c = abc_dup(c);
+ c = abc_pushscope(c);
+ c = abc_setlocal(c, m->activation_var);
+ } else {
+ c = abc_getlocal(c, m->activation_var);
+ c = abc_pushscope(c);
+ }
}
return c;
}
{
code_t*c = 0;
- c = add_scope_code(c, m);
+ c = add_scope_code(c, m, 1);
methodstate_list_t*l = m->innerfunctions;
while(l) {
c = abc_getlocal_0(c);
c = abc_constructsuper(c, 0);
}
+
+ if(m->slots) {
+ /* all parameters that are used by inner functions
+ need to be copied from local to slot */
+ parserassert(m->activation_var);
+ DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
+ if(v->is_parameter) {
+ c = abc_getlocal(c, m->activation_var);
+ c = abc_getlocal(c, v->index);
+ c = abc_setslot(c, v->index);
+ }
+ }
+ }
list_free(m->innerfunctions);
m->innerfunctions = 0;
return c;
syntaxerror("invalid combination of access levels and namespaces");
ns.access = ACCESS_NAMESPACE;
state_t*s = state;
- const char*url = (const char*)dict_lookup(state->namespace2url, mod->ns);
+ const char*url = (const char*)trie_lookup(active_namespaces, 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);
}
ns.name = url;
}
static slotinfo_t* find_class(const char*name);
+static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
+{
+ return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
+}
+
+void add_active_url(const char*url)
+{
+ NEW(namespace_t,n);
+ n->name = url;
+ list_append(state->active_namespace_urls, n);
+}
+
static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
{
if(var0) {
if(params) {
param_list_t*p=0;
for(p=params->list;p;p=p->next) {
- new_variable(p->param->name, p->param->type, 0, 1);
+ variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
+ v->is_parameter = 1;
}
}
-
- if(as3_pass==2) {
- m->scope_code = add_scope_code(m->scope_code, m);
+ if(m->uses_slots) {
+ dict_dump(m->slots, stdout, "");
}
-
methodstate_list_t*l = m->innerfunctions;
while(l) {
methodstate_t*m = l->methodstate;
l = l->next;
}
+ if(as3_pass==2) {
+ m->scope_code = add_scope_code(m->scope_code, m, 0);
+ }
+
if(as3_pass==2 && 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) {
- v->type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
- if(!v->type || v->type->kind != INFOTYPE_CLASS) {
- syntaxerror("Couldn't find class %s", v->type->name);
+ classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
+ if(!type || type->kind != INFOTYPE_CLASS) {
+ syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
}
+ v->type = type;
}
}
}
//flash doesn't seem to allow us to access function slots
//state->method->info->slot = slot;
- if(mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
+ if(mod && mod->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;
return 0;
}
-void register_namespace(const char*name, const char*url)
-{
- NEW(namespace_decl_t,n);
- n->name = name;
- n->url = url;
- if(!state->namespace2url) {
- state->namespace2url = dict_new();
- }
- dict_put(state->namespace2url, name, url);
- list_append(state->new_namespaces, n);
- tokenizer_register_namespace(name);
-}
-
#define IS_FINALLY_TARGET(op) \
((op) == OPCODE___CONTINUE__ || \
(op) == OPCODE___BREAK__ || \
if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
as3_schedule_class($2->package, $2->name);
}
-
- PASS2
classinfo_t*c = $2;
if(!c)
syntaxerror("Couldn't import class\n");
as3_schedule_package($2);
}
- PASS2
NEW(import_t,i);
i->package = $2;
state_has_imports();
$$.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;}
// ----------------------- expression evaluation -------------------------------------
E : INNERFUNCTION %prec prec_none {$$ = $1;}
-//V : CONSTANT {$$ = 0;}
E : CONSTANT
-//V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
-//V : NEW {$$ = $1.c;}
E : NEW {$$ = $1;}
-//V : DELETE {$$ = $1.c;}
E : DELETE {$$ = $1;}
E : FUNCTIONCALL
classinfo_t*t = state->cls->info->superclass;
if(!t) t = TYPE_OBJECT;
- memberinfo_t*f = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
+ memberinfo_t*f = findmember_nsset(t, $3, 1);
MEMBER_MULTINAME(m, f, $3);
$$.c = 0;
as3_warning("ignored .() operator");
}
-//VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
-
+//E : E "::" '[' E ']' {
+// // qualified expression TODO
+// $$.c = abc_pushundefined(0);
+// $$.t = 0;
+// as3_warning("ignored ::[] operator");
+// }
E : E '.' T_IDENTIFIER {
if(t->subtype==INFOTYPE_UNRESOLVED) {
syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
}
- memberinfo_t*f = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
+ memberinfo_t*f = findmember_nsset(t, $3, 1);
char noslot = 0;
if(f && !is_static != !(f->flags&FLAG_STATIC))
noslot=1;
if(f && f->slot && !noslot) {
$$.c = abc_getslot($$.c, f->slot);
} else {
+ if(!f)
+ as3_warning("Access of undefined property '%s' in %s", $3, t->name);
+
MEMBER_MULTINAME(m, f, $3);
$$.c = abc_getproperty2($$.c, &m);
}
} else if($1.c && $1.c->opcode == OPCODE___PUSHPACKAGE__) {
string_t*package = $1.c->data[0];
char*package2 = concat3(package->str, ".", $3);
- if(dict_contains(state->import_toplevel_packages, package2)) {
+
+ slotinfo_t*a = registry_find(package->str, $3);
+ if(a) {
+ $$ = push_class(a);
+ } else if(dict_contains(state->import_toplevel_packages, package2) ||
+ registry_ispackage(package2)) {
$$.c = $1.c;
$$.c->data[0] = string_new4(package2);
$$.t = 0;
} else {
- slotinfo_t*a = registry_find(package->str, $3);
- if(!a)
- syntaxerror("couldn't resolve %s", package2);
- $$ = push_class(a);
+ syntaxerror("couldn't resolve %s", package2);
}
} else {
/* when resolving a property on an unknown type, we do know the
name of the property (and don't seem to need the package), but
we need to make avm2 try out all access modes */
+ as3_warning("Resolving %s on unknown type", $3);
multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
$$.c = abc_getproperty2($$.c, &m);
$$.c = abc_coerce_a($$.c);
unknown_variable($1);
}
- /* let the compiler know that it might check the current directory/package
+ /* let the compiler know that it might want to check the current directory/package
for this identifier- maybe there's a file $1.as defining $1. */
as3_schedule_class_noerror(state->package, $1);
PASS2
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_nsset(state->cls->info, state->active_namespaces, $1, 1)) &&
- (f->flags&FLAG_STATIC) >= i_am_static) {
+ if(!state->method->inner &&
+ state->cls &&
+ (f = findmember_nsset(state->cls->info, $1, 1)) &&
+ (f->flags&FLAG_STATIC) >= i_am_static)
+ {
// $1 is a function in this class
int var_is_static = (f->flags&FLAG_STATIC);
static properties of a class */
state->method->late_binding = 1;
$$.t = f->type;
- namespace_t ns = {f->access, ""};
+ namespace_t ns = {f->access, f->package};
multiname_t m = {QNAME, &ns, 0, $1};
$$.c = abc_findpropstrict2($$.c, &m);
$$.c = abc_getproperty2($$.c, &m);
$$.c = abc_getslot($$.c, f->slot);
break;
} else {
- namespace_t ns = {f->access, ""};
+ namespace_t ns = {f->access, f->package};
multiname_t m = {QNAME, &ns, 0, $1};
$$.c = abc_getlocal_0($$.c);
$$.c = abc_getproperty2($$.c, &m);
}
/* look through package prefixes */
- if(dict_contains(state->import_toplevel_packages, $1)) {
+ if(dict_contains(state->import_toplevel_packages, $1) ||
+ registry_ispackage($1)) {
$$.c = abc___pushpackage__($$.c, $1);
$$.t = 0;
break;
}
NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
PASS12
- register_namespace($2->name, $2->url);
+ trie_put(active_namespaces, $2->name, (void*)$2->url);
namespace_t access = modifiers2access(&$1);
varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
PASS12
- char*url = 0;
- register_namespace($3->name, url);
+ const char*url = $3->name;
+
+ varinfo_t*s = (varinfo_t*)$3;
+ if(s->kind == INFOTYPE_UNRESOLVED) {
+ s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
+ if(!s)
+ syntaxerror("Couldn't resolve namespace %s", $3->name);
+ }
+
+ if(!s || s->kind != INFOTYPE_SLOT)
+ 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, $3->name, (void*)url);
+ add_active_url(url);
$$=0;
}