X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=3abeaa3c6a88db79b95b2b34cd6f3c2cb3d18a4e;hb=79e69e1d109a95f9495b96b29a723758d06a71d9;hp=5670793a9ed41a8f35622fe4752e0f5f0b1412e5;hpb=15d3df10f09bd780efa101d0c253db96716eb145;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index 5670793..3abeaa3 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -332,6 +332,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 +355,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 @@ -363,6 +365,8 @@ typedef struct _state { methodstate_t*method; char*exception_name; + + int switch_var; dict_t*vars; } state_t; @@ -439,10 +443,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() { @@ -484,23 +492,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; @@ -509,7 +516,7 @@ static void old_state() free(leaving->cls); leaving->cls=0; } - + state_destroy(leaving); } @@ -524,6 +531,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); @@ -615,6 +625,7 @@ typedef struct _variable { int index; classinfo_t*type; char init; + char is_parameter; methodstate_t*is_inner_method; } variable_t; @@ -649,6 +660,11 @@ static char variable_exists(char*name) } code_t*defaultvalue(code_t*c, classinfo_t*type); +static int alloc_local() +{ + return state->method->variable_count++; +} + static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot) { if(maybeslot) { @@ -658,7 +674,7 @@ static variable_t* new_variable2(const char*name, classinfo_t*type, char init, c } NEW(variable_t, v); - v->index = state->method->variable_count++; + v->index = alloc_local(); v->type = type; v->init = init; @@ -741,17 +757,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; } @@ -760,7 +785,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) { @@ -787,6 +812,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; @@ -837,7 +875,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"); @@ -857,6 +903,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) { @@ -883,15 +941,14 @@ 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); + if(m->uses_slots) { + dict_dump(m->slots, stdout, ""); } - methodstate_list_t*l = m->innerfunctions; while(l) { methodstate_t*m = l->methodstate; @@ -904,14 +961,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; } } } @@ -1367,8 +1429,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); @@ -1441,10 +1501,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); @@ -1460,7 +1520,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; @@ -1934,7 +1994,6 @@ char is_break_or_jump(code_t*c) return 0; } - #define IS_FINALLY_TARGET(op) \ ((op) == OPCODE___CONTINUE__ || \ (op) == OPCODE___BREAK__ || \ @@ -2376,7 +2435,7 @@ CASE_LIST: CASE {$$=$1;} CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);} CASE: "case" E ':' MAYBECODE { - $$ = abc_dup(0); + $$ = abc_getlocal(0, state->switch_var); $$ = code_append($$, $2.c); code_t*j = $$ = abc_ifne($$, 0); $$ = code_append($$, $4); @@ -2389,10 +2448,12 @@ CASE: "case" E ':' MAYBECODE { DEFAULT: "default" ':' MAYBECODE { $$ = $3; } -SWITCH : T_SWITCH '(' {PASS12 new_state();} E ')' '{' MAYBE_CASE_LIST '}' { +SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' { $$=$4.c; + $$ = abc_setlocal($$, state->switch_var); $$ = code_append($$, $7); - code_t*out = $$ = abc_pop($$); + + code_t*out = $$ = abc_kill($$, state->switch_var); breakjumpsto($$, $1, out); code_t*c = $$,*lastblock=0; @@ -2546,9 +2607,7 @@ THROW : "throw" %prec prec_none { WITH_HEAD : "with" '(' EXPRESSION ')' { new_state(); if(state->method->has_exceptions) { - char var[32]; - sprintf(var, "#with#_%d", as3_tokencount); - int v = new_variable(var,$3.t,0,0); + int v = alloc_local(); state->method->scope_code = abc_getlocal(state->method->scope_code, v); state->method->scope_code = abc_pushwith(state->method->scope_code); $$.number = v; @@ -2574,6 +2633,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);} @@ -2589,8 +2649,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"); @@ -2605,7 +2663,6 @@ IMPORT : "import" PACKAGE '.' '*' { as3_schedule_package($2); } - PASS2 NEW(import_t,i); i->package = $2; state_has_imports(); @@ -2626,7 +2683,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;} @@ -2904,7 +2960,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; @@ -2914,7 +2970,7 @@ CLASS: T_IDENTIFIER { c->nsset = get_current_imports(); /* make the compiler look for this class in the current directory, just in case: */ - as3_schedule_class_noerror(state->package, $1); + //as3_schedule_class_noerror(state->package, $1); } $$ = (classinfo_t*)c; PASS2 @@ -2923,7 +2979,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; @@ -3586,7 +3642,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; @@ -3646,7 +3702,7 @@ 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; @@ -3663,15 +3719,17 @@ 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 @@ -3697,9 +3755,9 @@ 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); + //as3_schedule_class_noerror(state->package, $1); PASS2 $$.t = 0; @@ -3725,8 +3783,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); @@ -3767,7 +3828,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; @@ -3793,7 +3855,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 { @@ -3812,20 +3874,31 @@ 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 || 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; }