char*package;
import_list_t*wildcard_imports;
- namespace_list_t*active_namespaces;
+ dict_t*import_toplevel_packages;
dict_t*imports;
+ namespace_list_t*active_namespaces;
char has_own_imports;
char new_vars; // e.g. transition between two functions
if(!s->imports) {
s->imports = dict_new();
}
+ if(!s->import_toplevel_packages) {
+ s->import_toplevel_packages = dict_new();
+ }
state = s;
state->level++;
state->has_own_imports = 0;
state->imports = dict_clone(state->imports);
state->has_own_imports = 1;
}
+static void import_toplevel(const char*package)
+{
+ char* s = strdup(package);
+ while(1) {
+ dict_put(state->import_toplevel_packages, s, 0);
+ char*x = strrchr(s, '.');
+ if(!x)
+ break;
+ *x = 0;
+ }
+ free(s);
+}
static void state_destroy(state_t*state)
{
}
return ns;
}
+static slotinfo_t* find_class(const char*name);
static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
{
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;
+ m->variable_count = m->uses_slots;
+ DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
+ if(v->type) {
+ if(v->type->package)
+ v->type = (classinfo_t*)registry_find(v->type->package, v->type->name);
+ else
+ v->type = (classinfo_t*)find_class(v->type->name);
+ if(!v->type || v->type->kind != INFOTYPE_CLASS) {
+ syntaxerror("Couldn't find class %s", v->type->name);
+ }
+ }
+ }
}
if(params) {
if(state->cls) {
syntaxerror("inner classes now allowed");
}
+
new_state();
token_list_t*t=0;
classinfo_list_t*mlist=0;
if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
syntaxerror("public and internal not supported at the same time.");
+
+ if(!(mod->flags&FLAG_INTERFACE) && !extends) {
+ // all classes extend object
+ extends = registry_getobjectclass();
+ }
/* create the class name, together with the proper attributes */
int access=0;
syntaxerror("Can't extend final class '%s'", extends->name);
/* fill out interfaces and extends (we couldn't resolve those during the first pass) */
- state->cls->info->superclass = extends?extends:TYPE_OBJECT;
+ state->cls->info->superclass = extends;
int pos = 0;
classinfo_list_t*l = implements;
for(l=implements;l;l=l->next) {
char*name = string_cstr(c->data[0]);
syntaxerror("Unresolved \"continue %s\"", name);
}
+ if(c->opcode == OPCODE___PUSHPACKAGE__) {
+ char*name = string_cstr(c->data[0]);
+ syntaxerror("Can't reference a package (%s) as such", name);
+ }
c=c->prev;
}
}
return;
if(m->flags & FLAG_FINAL)
syntaxerror("can't override final member %s", m->name);
+
+ /* allow this. it's no issue.
if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
- syntaxerror("can't override static member %s", m->name);
+ syntaxerror("can't override static member %s", m->name);*/
+
if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
syntaxerror("can't override non-static member %s with static declaration", m->name);
- if(!(flags&FLAG_OVERRIDE)) {
+ if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
if(m->kind == INFOTYPE_METHOD)
syntaxerror("can't override without explicit 'override' declaration");
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);
}
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);
dictentry_t*l = d->slots[t];
while(l) {
/* check parent method's variables */
- if(find_variable(state, l->key)) {
+ variable_t*v;
+ if((v=find_variable(state, l->key))) {
m->uses_parent_function = 1;
state->method->uses_slots = 1;
dict_put(xvars, l->key, 0);
}
ml = ml->next;
}
+
if(state->method->uses_slots) {
state->method->slots = dict_new();
int i = 1;
state->method->uses_slots = i;
dict_destroy(state->vars);state->vars = 0;
}
- dict_destroy(xvars);
-
old_state();
return 0;
}
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");
+ (state->method->late_binding || state->method->uses_slots)) {
+ //syntaxerror("try/catch and activation or late binding not supported yet within the same method");
+ as3_warning("try/catch and activation or late binding not supported yet within the same method");
+ }
if(f->body) {
f->body->code = body;
return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
}
-static slotinfo_t* find_class(char*name)
+static slotinfo_t* find_class(const char*name)
{
slotinfo_t*c=0;
return 0;
}
+typedcode_t push_class(slotinfo_t*a)
+{
+ typedcode_t x;
+ x.c = 0;
+ x.t = 0;
+ if(a->access == ACCESS_PACKAGEINTERNAL &&
+ strcmp(a->package, state->package) &&
+ strcmp(a->package, internal_filename_package)
+ ) {
+ syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
+ infotypename(a), a->name, a->package, state->package);
+ }
+
+ if(a->kind != INFOTYPE_CLASS) {
+ MULTINAME(m, a);
+ x.c = abc_findpropstrict2(x.c, &m);
+ x.c = abc_getproperty2(x.c, &m);
+ if(a->kind == INFOTYPE_METHOD) {
+ methodinfo_t*f = (methodinfo_t*)a;
+ x.t = TYPE_FUNCTION(f);
+ } else {
+ varinfo_t*v = (varinfo_t*)a;
+ x.t = v->type;
+ }
+ } else {
+ classinfo_t*c = (classinfo_t*)a;
+ if(c->slot) {
+ x.c = abc_getglobalscope(x.c);
+ x.c = abc_getslot(x.c, c->slot);
+ } else {
+ MULTINAME(m, c);
+ x.c = abc_getlex2(x.c, &m);
+ }
+ x.t = TYPE_CLASS(c);
+ }
+ return x;
+}
static char is_getlocal(code_t*c)
{
} else {
prefix = 0;
}
-
+
char use_temp_var = readbefore;
/* generate the write instruction, and maybe append a dup to the prefix code */
write->opcode = OPCODE_SETLOCAL_2;
} else if(r->opcode == OPCODE_GETLOCAL_3) {
write->opcode = OPCODE_SETLOCAL_3;
+ } else if(r->opcode == OPCODE_GETSUPER) {
+ write->opcode = OPCODE_SETSUPER;
+ multiname_t*m = (multiname_t*)r->data[0];
+ write->data[0] = multiname_clone(m);
} else {
code_dump(r);
syntaxerror("illegal lvalue: can't assign a value to this expression");
FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
variable_t*var = find_variable(state, $2);
+ if(!var) {
+ syntaxerror("variable %s not known in this scope", $2);
+ }
+
char*tmp1name = concat2($2, "__tmp1__");
int it = new_variable(tmp1name, TYPE_INT, 0, 0);
char*tmp2name = concat2($2, "__array__");
IMPORT : "import" PACKAGEANDCLASS {
PASS12
slotinfo_t*s = registry_find($2->package, $2->name);
- if(!s) {// || !(s->flags&FLAG_BUILTIN)) {
+ if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
as3_schedule_class($2->package, $2->name);
}
syntaxerror("Couldn't import class\n");
state_has_imports();
dict_put(state->imports, c->name, c);
+ import_toplevel(c->package);
$$=0;
}
IMPORT : "import" PACKAGE '.' '*' {
PASS12
- if(strncmp("flash.", $2, 6)) {
+ if(strncmp("flash.", $2, 6) && as3_pass==1) {
as3_schedule_package($2);
}
i->package = $2;
state_has_imports();
list_append(state->wildcard_imports, i);
+ import_toplevel(i->package);
$$=0;
}
$$.ns=$1;
}
-EXTENDS : {$$=registry_getobjectclass();}
+EXTENDS : {$$=0;}
EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
EXTENDS_LIST : {PASS12 $$=list_new();}
STATICCONSTANT : "false" {$$ = constant_new_false($1);}
STATICCONSTANT : "null" {$$ = constant_new_null($1);}
STATICCONSTANT : T_IDENTIFIER {
- // TODO
- as3_warning("Couldn't evaluate constant value of %s", $1);
- $$ = constant_new_null($1);
+ if(!strcmp($1, "NaN")) {
+ $$ = constant_new_float(__builtin_nan(""));
+ } else {
+ as3_warning("Couldn't evaluate constant value of %s", $1);
+ $$ = constant_new_null($1);
+ }
}
/* ------------ classes and interfaces (body, functions) ------- */
/* ------------- package + class ids --------------- */
CLASS: T_IDENTIFIER {
- PASS1 static slotinfo_t c;
+ PASS1 static classinfo_t c;
memset(&c, 0, sizeof(c));
+ c.kind = INFOTYPE_CLASS;
+ c.subtype = 255;
c.name = $1;
- $$ = (classinfo_t*)&c;
+ $$ = &c;
+
+ /* let the compiler know that we might be looking for this soon */
+ as3_schedule_class_noerror(state->package, $1);
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 slotinfo_t c;
+ PASS1 static classinfo_t c;
memset(&c, 0, sizeof(c));
+ c.kind = INFOTYPE_CLASS;
+ c.subtype = 255;
c.package = $1;
c.name = $3;
- $$=(classinfo_t*)&c;
+ $$ = &c;
PASS2
slotinfo_t*s = registry_find($1, $3);
if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
E : E "++" { code_t*c = 0;
classinfo_t*type = $1.t;
- if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
+ if(is_getlocal($1.c) && (TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t))) {
int nr = getlocalnr($1.c);
code_free($1.c);$1.c=0;
if(TYPE_IS_INT($1.t)) {
-E : E '.' T_IDENTIFIER
- {$$.c = $1.c;
- classinfo_t*t = $1.t;
- char is_static = 0;
- if(TYPE_IS_CLASS(t) && t->data) {
- t = t->data;
- is_static = 1;
- }
- if(t) {
- 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;
- if(f && f->slot && !noslot) {
- $$.c = abc_getslot($$.c, f->slot);
- } else {
- MEMBER_MULTINAME(m, f, $3);
- $$.c = abc_getproperty2($$.c, &m);
- }
- /* determine type */
- $$.t = slotinfo_gettype((slotinfo_t*)f);
- if(!$$.t)
- $$.c = abc_coerce_a($$.c);
- } 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 */
- multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
- $$.c = abc_getproperty2($$.c, &m);
- $$.c = abc_coerce_a($$.c);
- $$.t = registry_getanytype();
- }
- }
+E : E '.' T_IDENTIFIER {
+ $$.c = $1.c;
+ classinfo_t*t = $1.t;
+ char is_static = 0;
+ if(TYPE_IS_CLASS(t) && t->data) {
+ t = t->data;
+ is_static = 1;
+ }
+ if(t) {
+ if(t->subtype==0xff) {
+ 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);
+ 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 {
+ MEMBER_MULTINAME(m, f, $3);
+ $$.c = abc_getproperty2($$.c, &m);
+ }
+ /* determine type */
+ $$.t = slotinfo_gettype((slotinfo_t*)f);
+ if(!$$.t)
+ $$.c = abc_coerce_a($$.c);
+ } 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)) {
+ $$.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);
+ }
+ } 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 */
+ multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
+ $$.c = abc_getproperty2($$.c, &m);
+ $$.c = abc_coerce_a($$.c);
+ $$.t = registry_getanytype();
+ }
+}
VAR_READ : T_IDENTIFIER {
PASS1
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
+ etc. which is *correct* because local variables of the parent function
would shadow those.
*/
if(state->method->inner && !find_variable(state, $1)) {
unknown_variable($1);
}
+
+ /* let the compiler know that it might 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
$$.t = 0;
/* look at actual classes, in the current package and imported */
if((a = find_class($1))) {
- if(a->access == ACCESS_PACKAGEINTERNAL &&
- strcmp(a->package, state->package) &&
- strcmp(a->package, internal_filename_package)
- )
- syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
- infotypename(a),$1, a->package, state->package);
-
- if(a->kind != INFOTYPE_CLASS) {
- MULTINAME(m, a);
- $$.c = abc_findpropstrict2($$.c, &m);
- $$.c = abc_getproperty2($$.c, &m);
- if(a->kind == INFOTYPE_METHOD) {
- methodinfo_t*f = (methodinfo_t*)a;
- $$.t = TYPE_FUNCTION(f);
- } else {
- varinfo_t*v = (varinfo_t*)a;
- $$.t = v->type;
- }
- } else {
- classinfo_t*c = (classinfo_t*)a;
- if(c->slot) {
- $$.c = abc_getglobalscope($$.c);
- $$.c = abc_getslot($$.c, c->slot);
- } else {
- MULTINAME(m, c);
- $$.c = abc_getlex2($$.c, &m);
- }
- $$.t = TYPE_CLASS(c);
- }
+ $$ = push_class(a);
+ break;
+ }
+
+ /* look through package prefixes */
+ if(dict_contains(state->import_toplevel_packages, $1)) {
+ $$.c = abc___pushpackage__($$.c, $1);
+ $$.t = 0;
break;
}
/* unknown object, let the avm2 resolve it */
if(1) {
- as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
+ //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
+ as3_warning("Couldn't resolve '%s', doing late binding", $1);
state->method->late_binding = 1;
multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};