X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=ec7c39bd163da5105a7b1b57fa3de5bc6ef27427;hb=015233e6dbf54b574dd7f55d11c0d0d614802fde;hp=d6cf02aefa59475fc73a3bb800b57bfc64d52836;hpb=6b14c68239f98b818a7aacacc49bb7a16bfa7812;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index d6cf02a..ec7c39b 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -170,6 +170,7 @@ extern int a3_lex(); %token T_USHR ">>>" %token T_SHR ">>" +%type CONDITIONAL_COMPILATION %type FOR_START %type X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER %type NAMESPACE_ID @@ -332,6 +333,7 @@ struct _methodstate { char uses_parent_function; int uses_slots; dict_t*slots; + int activation_var; abc_method_t*abc; int var_index; // for inner methods @@ -354,8 +356,9 @@ typedef struct _state { import_list_t*wildcard_imports; dict_t*import_toplevel_packages; dict_t*imports; - namespace_list_t*active_namespaces; - namespace_decl_list_t*new_namespaces; + + namespace_list_t*active_namespace_urls; + char has_own_imports; char new_vars; // e.g. transition between two functions @@ -426,6 +429,15 @@ static namespace_list_t nl2 = {&ns2,&nl3}; static namespace_list_t nl1 = {&ns1,&nl2}; static namespace_set_t nopackage_namespace_set = {&nl1}; +dict_t*conditionals=0; +void as3_set_definition(const char*c) +{ + if(!conditionals) + conditionals = dict_new(); + if(!dict_contains(conditionals,c)) + dict_put(conditionals,c,0); +} + static void new_state() { NEW(state_t, s); @@ -441,10 +453,14 @@ static void new_state() state = s; state->level++; state->has_own_imports = 0; - state->new_namespaces = 0; state->vars = dict_new(); state->old = oldstate; state->new_vars = 0; + + trie_remember(active_namespaces); + + if(oldstate) + state->active_namespace_urls = list_clone(oldstate->active_namespace_urls); } static void state_has_imports() { @@ -486,23 +502,22 @@ static void state_destroy(state_t*state) 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(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) { free(leaving->method); leaving->method=0; @@ -511,7 +526,7 @@ static void old_state() free(leaving->cls); leaving->cls=0; } - + state_destroy(leaving); } @@ -526,6 +541,9 @@ void initialize_file(char*filename) 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); @@ -617,6 +635,7 @@ typedef struct _variable { int index; classinfo_t*type; char init; + char is_parameter; methodstate_t*is_inner_method; } variable_t; @@ -748,17 +767,26 @@ static void parsererror(const char*file, int line, const char*f) } -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; } @@ -767,7 +795,7 @@ static code_t* method_header(methodstate_t*m) { 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) { @@ -794,6 +822,19 @@ static code_t* method_header(methodstate_t*m) 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; @@ -844,7 +885,15 @@ static namespace_t modifiers2access(modifiers_t*mod) 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; + state_t*s = state; + 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; } else if(mod->flags&FLAG_PUBLIC) { if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) syntaxerror("invalid combination of access levels"); @@ -864,6 +913,18 @@ static namespace_t modifiers2access(modifiers_t*mod) } 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) { @@ -890,15 +951,11 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char 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); - } - - methodstate_list_t*l = m->innerfunctions; while(l) { methodstate_t*m = l->methodstate; @@ -911,14 +968,19 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char 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; } } } @@ -1163,6 +1225,7 @@ void check_code_for_break(code_t*c) static void check_constant_against_type(classinfo_t*t, constant_t*c) { + return; #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name) if(TYPE_IS_NUMBER(t)) { xassert(c->type == CONSTANT_FLOAT @@ -1221,9 +1284,6 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c //class method 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, ns.access, ns.name, name); @@ -1373,8 +1433,6 @@ static void startfunction(modifiers_t*mod, 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); @@ -1447,10 +1505,10 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char* } 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, ""}; + namespace_t mname_ns = modifiers2access(mod); multiname_t mname = {QNAME, &mname_ns, 0, name}; - if(flags&FLAG_STATIC) + if(mod->flags&FLAG_STATIC) f = abc_class_staticmethod(state->cls->abc, type2, &mname); else f = abc_class_method(state->cls->abc, type2, &mname); @@ -1466,7 +1524,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char* //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(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; @@ -1622,6 +1680,7 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to) as3_error("can't convert type %s%s%s to %s%s%s", from->package, from->package?".":"", from->name, to->package, to->package?".":"", to->name); + return c; } @@ -1940,7 +1999,6 @@ char is_break_or_jump(code_t*c) return 0; } - #define IS_FINALLY_TARGET(op) \ ((op) == OPCODE___CONTINUE__ || \ (op) == OPCODE___BREAK__ || \ @@ -2059,8 +2117,9 @@ code_t* insert_finally(code_t*c, code_t*finally, int tempvar) #define PASS1 }} if(as3_pass == 1) {{ #define PASS1END }} if(as3_pass == 2) {{ #define PASS2 }} if(as3_pass == 2) {{ -#define PASS12 }} {{ +#define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{ #define PASS12END }} if(as3_pass == 2) {{ +#define PASS_ALWAYS }} {{ %} @@ -2080,7 +2139,7 @@ PROGRAM_CODE: PACKAGE_DECLARATION | FUNCTION_DECLARATION | SLOT_DECLARATION | PACKAGE_INITCODE - | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' // conditional compilation + | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;} | ';' MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST @@ -2092,7 +2151,7 @@ INPACKAGE_CODE: INTERFACE_DECLARATION | FUNCTION_DECLARATION | SLOT_DECLARATION | PACKAGE_INITCODE - | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' // conditional compilation + | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;} | ';' MAYBECODE: CODE {$$=$1;} @@ -2125,7 +2184,7 @@ CODEPIECE: BREAK CODEPIECE: CONTINUE CODEPIECE: RETURN CODEPIECE: THROW -CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;} +CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {PASS_ALWAYS as3_pass=$1;} //CODEBLOCK : '{' CODE '}' {$$=$2;} //CODEBLOCK : '{' '}' {$$=0;} @@ -2141,7 +2200,15 @@ PACKAGE_INITCODE: CODE_STATEMENT { /* ------------ conditional compilation ------------- */ -CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER +CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER { + PASS12 + $$=as3_pass; + char*key = concat3($1,"::",$3); + if(!conditionals || !dict_contains(conditionals, key)) { + as3_pass=0; + } + free(key); +} /* ------------ variables --------------------------- */ @@ -2580,6 +2647,7 @@ WITH : WITH_HEAD CODEBLOCK { X_IDENTIFIER: T_IDENTIFIER | "package" {PASS12 $$="package";} + | T_NAMESPACE {PASS12 $$=$1;} PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;} PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);} @@ -2595,8 +2663,6 @@ IMPORT : "import" PACKAGEANDCLASS { 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"); @@ -2611,7 +2677,6 @@ IMPORT : "import" PACKAGE '.' '*' { as3_schedule_package($2); } - PASS2 NEW(import_t,i); i->package = $2; state_has_imports(); @@ -2632,7 +2697,6 @@ MODIFIER_LIST : MODIFIER_LIST MODIFIER { $$.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;} @@ -2675,7 +2739,7 @@ MAYBE_CLASS_BODY : CLASS_BODY CLASS_BODY : CLASS_BODY_ITEM CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM CLASS_BODY_ITEM : ';' -CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' +CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;} CLASS_BODY_ITEM : SLOT_DECLARATION CLASS_BODY_ITEM : FUNCTION_DECLARATION @@ -2708,79 +2772,89 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI VARCONST: "var" | "const" -SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {setslotstate(&$1,$2);} SLOT_LIST {$$=$4;setslotstate(0, 0);} +SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);} -SLOT_LIST: ONE_SLOT {$$ = $1;} -SLOT_LIST: SLOT_LIST ',' ONE_SLOT {$$ = code_append($1, $3);} +SLOT_LIST: ONE_SLOT {PASS12 $$=0;} +SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;} ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION { +PASS12 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, $1, 1); - if(i) { - check_override(i, flags); - } - info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1); - } else { - slotinfo_t*i = registry_find(state->package, $1); - if(i) { - 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, $1); - } + if(as3_pass == 1) { - info->type = $2; - info->flags = flags; + varinfo_t* info = 0; + if(state->cls) { + 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, $1); + } else { + slotinfo_t*i = registry_find(state->package, $1); + if(i) { + 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, $1); + } - /* slot name */ - multiname_t mname = {QNAME, &ns, 0, $1}; - - trait_list_t**traits; - code_t**code; - if(!state->cls) { - // global variable - ns.name = state->package; - traits = &global->init->traits; - code = &global->init->method->body->code; - } else if(flags&FLAG_STATIC) { - // static variable - traits = &state->cls->abc->static_traits; - code = &state->cls->static_init->header; - } else { - // instance variable - traits = &state->cls->abc->traits; - code = &state->cls->init->header; - } - - trait_t*t=0; - 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); - } - info->slot = t->slot_id; - - /* initalization code (if needed) */ - code_t*c = 0; - if($3.c && !is_pushundefined($3.c)) { - c = abc_getlocal_0(c); - c = code_append(c, $3.c); - c = converttype(c, $3.t, $2); - c = abc_setslot(c, t->slot_id); + info->type = $2; + info->flags = flags; + + dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info); } - *code = code_append(*code, c); + if(as3_pass == 2) { + varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount); + + /* slot name */ + multiname_t mname = {QNAME, &ns, 0, $1}; + + trait_list_t**traits; + code_t**code; + if(!state->cls) { + // global variable + ns.name = state->package; + traits = &global->init->traits; + code = &global->init->method->body->code; + } else if(flags&FLAG_STATIC) { + // static variable + traits = &state->cls->abc->static_traits; + code = &state->cls->static_init->header; + } else { + // instance variable + traits = &state->cls->abc->traits; + code = &state->cls->init->header; + } + + trait_t*t=0; + 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); + } + info->slot = t->slot_id; + + /* initalization code (if needed) */ + code_t*c = 0; + if($3.c && !is_pushundefined($3.c)) { + c = abc_getlocal_0(c); + 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(slotstate_varconst==KW_CONST) { - t->kind= TRAIT_CONST; + if(slotstate_varconst==KW_CONST) { + t->kind= TRAIT_CONST; + } } $$=0; @@ -2910,7 +2984,7 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE /* ------------- package + class ids --------------- */ -CLASS: T_IDENTIFIER { +CLASS: X_IDENTIFIER { PASS1 NEW(unresolvedinfo_t,c); memset(c, 0, sizeof(*c)); c->kind = INFOTYPE_UNRESOLVED; @@ -2929,7 +3003,7 @@ CLASS: T_IDENTIFIER { $$ = (classinfo_t*)s; } -PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER { +PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER { PASS1 NEW(unresolvedinfo_t,c); memset(c, 0, sizeof(*c)); c->kind = INFOTYPE_UNRESOLVED; @@ -3132,13 +3206,9 @@ VOIDEXPRESSION : EXPRESSION %prec below_minus { // ----------------------- 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 @@ -3592,7 +3662,7 @@ E : "super" '.' T_IDENTIFIER 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; @@ -3636,8 +3706,12 @@ E : E '.' '(' E ')' { 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 { @@ -3652,13 +3726,17 @@ 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); } @@ -3669,20 +3747,23 @@ E : E '.' T_IDENTIFIER { } 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); @@ -3703,7 +3784,7 @@ VAR_READ : T_IDENTIFIER { 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 @@ -3731,8 +3812,11 @@ VAR_READ : T_IDENTIFIER { 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); @@ -3748,7 +3832,7 @@ VAR_READ : T_IDENTIFIER { 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); @@ -3758,7 +3842,7 @@ VAR_READ : T_IDENTIFIER { $$.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); @@ -3773,7 +3857,8 @@ VAR_READ : T_IDENTIFIER { } /* 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; @@ -3799,7 +3884,7 @@ NAMESPACE_ID : "namespace" T_IDENTIFIER { PASS12 NEW(namespace_decl_t,n); n->name = $2; - n->url = 0; + n->url = $2; $$=n; } NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER { @@ -3818,20 +3903,38 @@ NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING { } NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID { PASS12 - list_append(state->new_namespaces, $2); - tokenizer_register_namespace($2->name); + 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); + var->type = TYPE_NAMESPACE; + namespace_t ns; + ns.access = ACCESS_NAMESPACE; + ns.name = $2->url; + var->value = constant_new_namespace(&ns); + $$=0; } USE_NAMESPACE : "use" "namespace" CLASS_SPEC { PASS12 - 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); + 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; }