X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=818a090b38f669500bdcba7b28d56d9f66717b60;hb=bb864e1a88e670c99d559c7dee4f74e9bf7d978b;hp=3f72304339cc6e1dc45f0701a9a5cd271168a7b6;hpb=434d5040b814eae784d080c695fe8c3d370a166b;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index 3f72304..818a090 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -65,6 +65,7 @@ extern int a3_lex(); abc_exception_t *exception; regexp_t regexp; modifiers_t flags; + namespace_decl_t* namespace_decl; struct { abc_exception_list_t *l; code_t*finally; @@ -170,12 +171,13 @@ extern int a3_lex(); %token T_SHR ">>" %type FOR_START -%type X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER NAMESPACE_ID +%type X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER +%type NAMESPACE_ID %type VARCONST %type CODE %type CODEPIECE CODE_STATEMENT %type CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH -%type PACKAGE_DECLARATION SLOT_DECLARATION +%type PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT %type FUNCTION_DECLARATION PACKAGE_INITCODE %type VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW %type CATCH FINALLY @@ -347,8 +349,10 @@ typedef struct _state { 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; + namespace_decl_list_t*new_namespaces; char has_own_imports; char new_vars; // e.g. transition between two functions @@ -426,9 +430,13 @@ static void new_state() 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->new_namespaces = 0; state->vars = dict_new(); state->old = oldstate; state->new_vars = 0; @@ -439,6 +447,18 @@ static void state_has_imports() 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) { @@ -471,6 +491,12 @@ static void old_state() 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(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) { free(leaving->method); @@ -815,6 +841,7 @@ static namespace_t modifiers2access(modifiers_t*mod) } return ns; } +static slotinfo_t* find_class(const char*name); static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0) { @@ -835,7 +862,18 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char 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) { @@ -863,6 +901,7 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl if(state->cls) { syntaxerror("inner classes now allowed"); } + new_state(); token_list_t*t=0; classinfo_list_t*mlist=0; @@ -872,6 +911,11 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl 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; @@ -923,7 +967,7 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl 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) { @@ -1012,10 +1056,14 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl } } -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; @@ -1066,6 +1114,10 @@ void check_code_for_break(code_t*c) 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; } } @@ -1101,12 +1153,15 @@ static void check_override(memberinfo_t*m, int flags) 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"); @@ -1123,7 +1178,7 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c if(!state->cls) { //package method minfo = methodinfo_register_global(ns.access, state->package, name); - minfo->return_type = return_type; + 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, ns.name, name, 0); @@ -1134,7 +1189,7 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c 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->return_type = return_type; + 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; @@ -1142,10 +1197,12 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c //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, ns.name, name, 1); if(minfo) { @@ -1157,17 +1214,22 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c 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, 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; @@ -1208,7 +1270,7 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type) 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); } @@ -1244,7 +1306,6 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name, if(state->method->is_constructor) name = "__as3_constructor__"; - return_type = 0; state->method->info = registerfunction(getset, mod, name, params, return_type, 0); function_initvars(state->method, params, mod->flags, 1); @@ -1281,7 +1342,9 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char* 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); @@ -1292,7 +1355,8 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char* 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); @@ -1307,6 +1371,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char* } ml = ml->next; } + if(state->method->uses_slots) { state->method->slots = dict_new(); int i = 1; @@ -1324,8 +1389,6 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char* state->method->uses_slots = i; dict_destroy(state->vars);state->vars = 0; } - dict_destroy(xvars); - old_state(); return 0; } @@ -1397,6 +1460,12 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char* 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"); + as3_warning("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; @@ -1543,7 +1612,7 @@ char is_pushundefined(code_t*c) 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; @@ -1580,6 +1649,43 @@ static slotinfo_t* find_class(char*name) 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) { @@ -1627,7 +1733,7 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r } else { prefix = 0; } - + char use_temp_var = readbefore; /* generate the write instruction, and maybe append a dup to the prefix code */ @@ -1676,6 +1782,10 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r 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"); @@ -2103,6 +2213,10 @@ FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK { 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__"); @@ -2364,7 +2478,7 @@ THROW : "throw" %prec prec_none { WITH : "with" '(' EXPRESSION ')' CODEBLOCK { $$ = $3.c; - $$ = abc_pushscope($$); + $$ = abc_pushwith($$); $$ = code_append($$, $5); $$ = abc_popscope($$); } @@ -2385,7 +2499,7 @@ PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");} 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); } @@ -2395,11 +2509,12 @@ IMPORT : "import" PACKAGEANDCLASS { 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); } @@ -2408,6 +2523,7 @@ IMPORT : "import" PACKAGE '.' '*' { i->package = $2; state_has_imports(); list_append(state->wildcard_imports, i); + import_toplevel(i->package); $$=0; } @@ -2437,7 +2553,7 @@ MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;} $$.ns=$1; } -EXTENDS : {$$=registry_getobjectclass();} +EXTENDS : {$$=0;} EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;} EXTENDS_LIST : {PASS12 $$=list_new();} @@ -2499,33 +2615,39 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI VARCONST: "var" | "const" -SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1.flags);} MAYBETYPE MAYBEEXPRESSION { - int flags = $1.flags; - namespace_t ns = modifiers2access(&$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, ns.name, $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, ns.access, ns.name, $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); } if(ns.name && ns.name[0]) { syntaxerror("namespaces not allowed on package-level variables"); } - info = varinfo_register_global(ns.access, state->package, $3); + info = varinfo_register_global(ns.access, state->package, $1); } - info->type = $5; + info->type = $2; info->flags = flags; /* slot name */ - multiname_t mname = {QNAME, &ns, 0, $3}; + multiname_t mname = {QNAME, &ns, 0, $1}; trait_list_t**traits; code_t**code; @@ -2545,8 +2667,8 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1.fl } 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); @@ -2555,21 +2677,20 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1.fl /* 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 -------------------------------------- */ @@ -2587,9 +2708,12 @@ STATICCONSTANT : "true" {$$ = constant_new_true($1);} STATICCONSTANT : "false" {$$ = constant_new_false($1);} STATICCONSTANT : "null" {$$ = constant_new_null($1);} STATICCONSTANT : T_IDENTIFIER { - // TODO - as3_warning("Couldn't resolve %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) ------- */ @@ -2694,10 +2818,15 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE /* ------------- 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); @@ -2705,11 +2834,13 @@ CLASS: T_IDENTIFIER { } 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); @@ -2723,9 +2854,9 @@ CLASS_SPEC: PACKAGEANDCLASS 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();} @@ -2734,8 +2865,8 @@ TYPE : CLASS_SPEC {$$=$1;} | "Number" {$$=registry_getnumberclass();} */ -MAYBETYPE: ':' TYPE {$$=$2;} -MAYBETYPE: {$$=0;} +MAYBETYPE: ':' TYPE {PASS12 $$=$2;} +MAYBETYPE: {PASS12 $$=0;} /* ----------function calls, delete, constructor calls ------ */ @@ -3293,7 +3424,7 @@ E : E '?' E ':' E %prec below_assignment { 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)) { @@ -3414,39 +3545,55 @@ E : E '.' '(' E ')' { -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 @@ -3454,12 +3601,16 @@ VAR_READ : T_IDENTIFIER { 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; @@ -3522,41 +3673,21 @@ VAR_READ : T_IDENTIFIER { /* 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}; @@ -3571,22 +3702,41 @@ VAR_READ : T_IDENTIFIER { NAMESPACE_ID : "namespace" T_IDENTIFIER { PASS12 - tokenizer_register_namespace($2); - $$=$2; + NEW(namespace_decl_t,n); + n->name = $2; + n->url = 0; + $$=n; } - -NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID { - $$=0; +NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER { + PASS12 + NEW(namespace_decl_t,n); + n->name = $2; + n->url = $4; + $$=n; } -NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_IDENTIFIER { - $$=0; +NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING { + PASS12 + NEW(namespace_decl_t,n); + n->name = $2; + n->url = $4.str; + $$=n; } -NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_STRING { +NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID { + PASS12 + list_append(state->new_namespaces, $2); + tokenizer_register_namespace($2->name); $$=0; } -USE_NAMESPACE : "use" PACKAGEANDCLASS { + +USE_NAMESPACE : "use" "namespace" CLASS_SPEC { PASS12 - tokenizer_register_namespace($2->name); + NEW(namespace_decl_t,n); + n->name = $3->name; + n->url = 0; + /* FIXME: for pass2, we should now try to figure out what the URL of + this thing is */ + list_append(state->new_namespaces, n); + tokenizer_register_namespace($3->name); $$=0; }