X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=b181866348f71342fe9c8aa543e112a830ae47b5;hp=b377ba2fa306d9cc3e5e3a4a876c37b56e24ea57;hb=9ed9a87914fc9a590967d46de404e0f6290b7bb2;hpb=597fbcf83f70a40f693a486f3ada0b2294985358 diff --git a/lib/as3/parser.y b/lib/as3/parser.y index b377ba2..b181866 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -1,4 +1,4 @@ -/* parser.lex +/* parser.y Routines for compiling Flash2 AVM2 ABC Actionscript @@ -77,7 +77,7 @@ extern int a3_lex(); } -%token T_IDENTIFIER T_NAMESPACE +%token T_IDENTIFIER %token T_STRING %token T_REGEXP %token T_EMPTY @@ -267,11 +267,9 @@ extern int a3_lex(); // needed for "return" precedence: %nonassoc T_STRING T_REGEXP %nonassoc T_INT T_UINT T_FLOAT KW_NAN -%left T_NAMESPACE %nonassoc "false" "true" "null" "undefined" "super" "function" %left above_function - %{ @@ -346,6 +344,7 @@ struct _methodstate { int variable_count; dict_t*unresolved_variables; + dict_t*allvars; // all variables (in all sublevels, but not for inner functions) char inner; char uses_parent_function; @@ -369,11 +368,21 @@ struct _methodstate { methodstate_list_t*innerfunctions; }; +methodstate_t*methodstate_new() +{ + NEW(methodstate_t,m); + m->allvars = dict_new(); + return m; +} void methodstate_destroy(methodstate_t*m) { - dict_destroy(m->unresolved_variables); - m->unresolved_variables = 0; + dict_destroy(m->unresolved_variables); m->unresolved_variables = 0; list_free(m->innerfunctions);m->innerfunctions=0; + + if(m->allvars) { + DICT_ITERATE_DATA(m->allvars, void*, data) {free(data);} + m->allvars = 0; + } } typedef struct _state { @@ -385,6 +394,7 @@ typedef struct _state { dict_t*import_toplevel_packages; dict_t*imports; + dict_t*namespaces; namespace_list_t*active_namespace_urls; char has_own_imports; @@ -399,7 +409,6 @@ typedef struct _state { int switch_var; dict_t*vars; - dict_t*allvars; // also contains variables from sublevels } state_t; typedef struct _global { @@ -493,7 +502,7 @@ static void new_state() state->old = oldstate; state->new_vars = 0; - trie_remember(active_namespaces); + state->namespaces = dict_new(); if(oldstate) state->active_namespace_urls = list_clone(oldstate->active_namespace_urls); @@ -511,13 +520,6 @@ static void state_destroy(state_t*state) if(state->vars) { dict_destroy(state->vars);state->vars=0; } - if(state->new_vars && state->allvars) { - parserassert(!state->old || state->old->allvars != state->allvars); - DICT_ITERATE_DATA(state->allvars, void*, data) { - free(data); - } - dict_destroy(state->allvars); - } list_free(state->active_namespace_urls) state->active_namespace_urls = 0; @@ -527,8 +529,6 @@ static void state_destroy(state_t*state) static void old_state() { - trie_rollback(active_namespaces); - if(!state || !state->old) syntaxerror("invalid nesting"); state_t*leaving = state; @@ -558,11 +558,8 @@ void initialize_file(char*filename) syntaxerror("invalid call to initialize_file during parsing of another file"); } - active_namespaces = trie_new(); - new_state(); state->package = internal_filename_package = strdup(filename); - state->allvars = dict_new(); global->token2info = dict_lookup(global->file2token2info, current_filename // use long version @@ -576,6 +573,7 @@ void initialize_file(char*filename) state->method = rfx_calloc(sizeof(methodstate_t)); dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method); state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope + state->method->allvars = dict_new(); } else { state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount); state->method->variable_count = 0; @@ -636,10 +634,10 @@ typedef struct _variable { methodstate_t*is_inner_method; } variable_t; -static variable_t* find_variable(state_t*s, char*name) +static variable_t* find_variable(state_t*s, const char*name) { if(s->method->no_variable_scoping) { - return dict_lookup(s->allvars, name); + return dict_lookup(s->method->allvars, name); } else { state_t*top = s; while(s) { @@ -674,6 +672,7 @@ static char variable_exists(char*name) static code_t*defaultvalue(code_t*c, classinfo_t*type) { + parserassert(!type || type->kind!=INFOTYPE_UNRESOLVED); if(TYPE_IS_INT(type)) { c = abc_pushbyte(c, 0); } else if(TYPE_IS_UINT(type)) { @@ -720,21 +719,21 @@ static variable_t* new_variable2(methodstate_t*method, const char*name, classinf if(!method->no_variable_scoping) { if(dict_contains(state->vars, name)) { - *(int*)0=0; syntaxerror("variable %s already defined", name); } dict_put(state->vars, name, v); } if(method->no_variable_scoping && as3_pass==2 && - dict_contains(state->allvars, name)) + dict_contains(state->method->allvars, name)) { - variable_t*v = dict_lookup(state->allvars, name); - if(v->type != type) + variable_t*v = dict_lookup(state->method->allvars, name); + if(v->type != type && (!v->type || v->type->kind!=INFOTYPE_UNRESOLVED)) { syntaxerror("variable %s already defined.", name); + } return v; } - dict_put(state->allvars, name, v); + dict_put(state->method->allvars, name, v); } return v; @@ -882,7 +881,7 @@ static code_t* method_header(methodstate_t*m) static code_t* wrap_function(code_t*c,code_t*header, code_t*body) { c = code_append(c, header); - c = code_append(c, var_block(body, state->method->no_variable_scoping?state->allvars:state->vars)); + c = code_append(c, var_block(body, state->method->no_variable_scoping?state->method->allvars:state->vars)); /* append return if necessary */ if(!c || (c->opcode != OPCODE_RETURNVOID && c->opcode != OPCODE_RETURNVALUE)) { @@ -909,6 +908,29 @@ static void endpackage() #define FLAG_PACKAGEINTERNAL 2048 #define FLAG_NAMESPACE 4096 +static slotinfo_t* find_class(const char*name); + +const char* lookup_namespace(const char*name) +{ + state_t*s = state; + while(s) { + const char*url = dict_lookup(s->namespaces, name); + if(url) + return url; + s = s->old; + } + varinfo_t*a; + registry_find(state->package, name); + if(( a = (varinfo_t*)find_class(name) )) { + if(a->kind == INFOTYPE_VAR) { + if(!a->value || !NS_TYPE(a->value->type)) + syntaxerror("%s.%s is not a namespace", a->package, a->name); + return a->value->ns->name; + } + } + return 0; +} + static namespace_t modifiers2access(modifiers_t*mod) { namespace_t ns; @@ -918,14 +940,14 @@ 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; - 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); - } + const char*url = lookup_namespace(mod->ns); + if(!url) { + if(as3_pass>1) { + syntaxerror("unknown namespace: %s (pass %d)", mod->ns, as3_pass); + } else { + url = mod->ns; + } + } ns.name = url; } else if(mod->flags&FLAG_PUBLIC) { if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) @@ -944,11 +966,10 @@ static namespace_t modifiers2access(modifiers_t*mod) } return ns; } -static slotinfo_t* find_class(const char*name); -static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse) +static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse, char is_static) { - return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse); + return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse, is_static); } static void innerfunctions2vars(methodstate_t*m) @@ -1005,15 +1026,26 @@ static void function_initvars(methodstate_t*m, char has_params, params_t*params, m->scope_code = add_scope_code(m->scope_code, m, 0); if(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) { - classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type); + DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v1) { + if(v1->type && v1->type->kind == INFOTYPE_UNRESOLVED) { + classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v1->type); if(!type || type->kind != INFOTYPE_CLASS) { - syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name); + syntaxerror("Couldn't find class %s::%s (%s)", v1->type->package, v1->type->name, name); } - v->type = type; + v1->type = type; } } + } + if(m->allvars) { + DICT_ITERATE_ITEMS(m->allvars, char*, name2, variable_t*, v2) { + if(v2->type && v2->type->kind == INFOTYPE_UNRESOLVED) { + classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v2->type); + if(!type || type->kind != INFOTYPE_CLASS) { + syntaxerror("Couldn't find class %s::%s (%s)", v2->type->package, v2->type->name, name2); + } + v2->type = type; + } + } } } } @@ -1061,8 +1093,8 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl if(as3_pass==1) { state->cls = rfx_calloc(sizeof(classstate_t)); - state->cls->init = rfx_calloc(sizeof(methodstate_t)); - state->cls->static_init = rfx_calloc(sizeof(methodstate_t)); + state->cls->init = methodstate_new(); + state->cls->static_init = methodstate_new(); state->cls->static_init->is_static=FLAG_STATIC; /* notice: we make no effort to initialize the top variable (local0) here, even though it has special meaning. We just rely on the fact @@ -1239,7 +1271,7 @@ static void check_override(memberinfo_t*m, int flags) { if(!m) return; - if(m->parent == state->cls->info) + if(m->parent == state->cls->info && !((flags^m->flags)&FLAG_STATIC)) syntaxerror("class '%s' already contains a method/slot '%s'", m->parent->name, m->name); if(!m->parent) syntaxerror("internal error: overriding method %s, which doesn't have parent", m->name); @@ -1275,11 +1307,11 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c minfo->return_type = return_type; } else if(getset != KW_GET && getset != KW_SET) { //class method - memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0); + memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0, mod->flags&FLAG_STATIC); if(m) { 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 = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name, mod->flags&FLAG_STATIC); minfo->return_type = return_type; // getslot on a member slot only returns "undefined", so no need // to actually store these @@ -1295,7 +1327,7 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c } 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); + minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1, mod->flags&FLAG_STATIC); if(minfo) { if(minfo->kind!=INFOTYPE_VAR) syntaxerror("class already contains a method called '%s'", name); @@ -1317,7 +1349,7 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c type?type->name:"*"); }*/ } else { - minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name); + minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name, mod->flags&FLAG_STATIC); minfo->kind = INFOTYPE_VAR; //hack minfo->subtype = gs; minfo->return_type = type; @@ -1349,10 +1381,9 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type) new_state(); state->new_vars = 1; - state->allvars = dict_new(); if(as3_pass == 1) { - state->method = rfx_calloc(sizeof(methodstate_t)); + state->method = methodstate_new(); state->method->inner = 1; state->method->is_static = parent_method->is_static; state->method->variable_count = 0; @@ -1393,10 +1424,9 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name, } new_state(); state->new_vars = 1; - state->allvars = dict_new(); if(as3_pass == 1) { - state->method = rfx_calloc(sizeof(methodstate_t)); + state->method = methodstate_new(); state->method->has_super = 0; state->method->is_static = mod->flags&FLAG_STATIC; @@ -1422,7 +1452,7 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name, parserassert(state->method); if(state->cls) { - memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2); + memberinfo_t*m = registry_findmember(state->cls->info, mod->ns, name, 2, mod->flags&FLAG_STATIC); check_override(m, mod->flags); } @@ -1465,11 +1495,11 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char* if(state->method->unresolved_variables) { DICT_ITERATE_KEY(state->method->unresolved_variables, char*, vname) { - if(!state->method->no_variable_scoping && dict_contains(state->allvars, vname)) { - variable_t*v = dict_lookup(state->allvars, vname); + if(!state->method->no_variable_scoping && dict_contains(state->method->allvars, vname)) { + variable_t*v = dict_lookup(state->method->allvars, vname); if(!v->is_inner_method) { state->method->no_variable_scoping = 1; - as3_warning("function %s uses forward or outer block variable references (%s): switching into compatiblity mode", name, vname); + as3_warning("function %s uses forward or outer block variable references (%s): switching into compatibility mode", name, vname); } } } @@ -1477,14 +1507,14 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char* methodstate_list_t*ml = state->method->innerfunctions; while(ml) { - insert_unresolved(ml->methodstate, xvars, state->allvars); + insert_unresolved(ml->methodstate, xvars, state->method->allvars); ml = ml->next; } if(state->method->uses_slots) { state->method->slots = dict_new(); int i = 1; - DICT_ITERATE_ITEMS(state->allvars, char*, name, variable_t*, v) { + DICT_ITERATE_ITEMS(state->method->allvars, char*, name, variable_t*, v) { if(!name) syntaxerror("internal error"); if(v->index && dict_contains(xvars, name)) { v->init = v->kill = 0; @@ -1499,7 +1529,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; parserassert(state->new_vars); - dict_destroy(state->allvars);state->allvars = 0; } old_state(); return 0; @@ -1685,6 +1714,7 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to) if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to)) return c; + as3_error("can't convert type %s%s%s to %s%s%s", from->package, from->package[0]?".":"", from->name, to->package, to->package[0]?".":"", to->name); @@ -2104,7 +2134,7 @@ PASS12 if(variable_exists($1)) syntaxerror("Variable %s already defined", $1); PASS1 - new_variable(state->method, $1, 0, 1, 0); + new_variable(state->method, $1, $2, 1, 0); PASS2 char slot = 0; @@ -2223,10 +2253,9 @@ FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' IF_CODEBLOCK { } FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' IF_CODEBLOCK { - variable_t*var = find_variable(state, $2); - if(!var) { - syntaxerror("variable %s not known in this scope", $2); - } + node_t*n = resolve_identifier($2); + typedcode_t w = node_write(n); + int it = alloc_local(); int array = alloc_local(); @@ -2247,8 +2276,9 @@ FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' IF_CODEBLOCK { $$ = abc_nextname($$); else $$ = abc_nextvalue($$); - $$ = converttype($$, 0, var->type); - $$ = abc_setlocal($$, var->index); + + $$ = converttype($$, 0, w.t); + $$ = code_append($$, w.c); $$ = code_append($$, $6); $$ = abc_jump($$, loopstart); @@ -2361,7 +2391,7 @@ SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ') CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state(); state->exception_name=$3; - PASS1 new_variable(state->method, $3, 0, 0, 0); + PASS1 new_variable(state->method, $3, $4, 0, 0); PASS2 new_variable(state->method, $3, $4, 0, 0); } '{' MAYBECODE '}' { @@ -2515,7 +2545,6 @@ X_IDENTIFIER: T_IDENTIFIER | "package" {PASS12 $$="package";} | "namespace" {PASS12 $$="namespace";} | "NaN" {PASS12 $$="NaN";} - | T_NAMESPACE {PASS12 $$=$1;} PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;} PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);} @@ -2557,9 +2586,12 @@ IMPORT : "import" T_IDENTIFIER { IMPORT : "import" PACKAGEANDCLASS { PASS12 slotinfo_t*s = registry_find($2->package, $2->name); - if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) { + if(!s && as3_pass==1) { as3_schedule_class($2->package, $2->name); } + /*if(s && s->kind == INFOTYPE_VAR && TYPE_IS_NAMESPACE(s->type)) { + trie_put(active_namespaces, (unsigned char*)$2->name, 0); + }*/ state_has_imports(); dict_put(state->imports, $2->name, $2); import_toplevel($2->package); @@ -2600,7 +2632,7 @@ MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;} | KW_OVERRIDE {PASS12 $$.flags=FLAG_OVERRIDE;$$.ns=0;} | KW_NATIVE {PASS12 $$.flags=FLAG_NATIVE;$$.ns=0;} | KW_INTERNAL {PASS12 $$.flags=FLAG_PACKAGEINTERNAL;$$.ns=0;} - | T_NAMESPACE {PASS12 $$.flags=FLAG_NAMESPACE; + | T_IDENTIFIER {PASS12 $$.flags=FLAG_NAMESPACE; $$.ns=$1; } @@ -2636,6 +2668,7 @@ CLASS_BODY_ITEM : ';' CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;} CLASS_BODY_ITEM : SLOT_DECLARATION CLASS_BODY_ITEM : FUNCTION_DECLARATION +CLASS_BODY_ITEM : '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");} CLASS_BODY_ITEM : CODE_STATEMENT { code_t*c = state->cls->static_init->header; @@ -2741,11 +2774,11 @@ PASS12 varinfo_t* info = 0; if(state->cls) { - memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1); + memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1, slotstate_flags->flags&FLAG_STATIC); if(i) { check_override(i, flags); } - info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1); + info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1, slotstate_flags->flags&FLAG_STATIC); } else { slotinfo_t*i = registry_find(state->package, $1); if(i) { @@ -2824,7 +2857,6 @@ MAYBECONSTANT: '=' E { } } -//CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);} CONSTANT : T_INT {$$ = constant_new_int($1);} CONSTANT : T_UINT { $$ = constant_new_uint($1); @@ -2837,11 +2869,6 @@ CONSTANT : "null" {$$ = constant_new_null($1);} CONSTANT : "undefined" {$$ = constant_new_undefined($1);} CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));} -/*CONSTANT : T_NAMESPACE { - // TODO - $$ = constant_new_namespace(namespace_new_namespace($1.url)); -}*/ - /* ---------------------------xml ------------------------------ */ %code { @@ -3061,6 +3088,7 @@ CLASS: X_IDENTIFIER { slotinfo_t*s = find_class($1); if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package); $$ = (classinfo_t*)s; + registry_use(s); } PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER { @@ -3075,6 +3103,7 @@ PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER { if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3); free($1);$1=0; $$ = (classinfo_t*)s; + registry_use(s); } CLASS_SPEC: PACKAGEANDCLASS @@ -3432,7 +3461,7 @@ E : "super" '.' T_IDENTIFIER syntaxerror("super keyword not allowed outside a class"); classinfo_t*t = state->cls->info->superclass; if(!t) t = TYPE_OBJECT; - memberinfo_t*f = findmember_nsset(t, $3, 1); + memberinfo_t*f = findmember_nsset(t, $3, 1, 0); MEMBER_MULTINAME(m, f, $3); typedcode_t v; v.c = 0; @@ -3506,33 +3535,49 @@ E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' { ID_OR_NS : T_IDENTIFIER {$$=$1;} ID_OR_NS : '*' {$$="*";} -ID_OR_NS : T_NAMESPACE {$$=(char*)$1;} SUBNODE: X_IDENTIFIER | '*' {$$="*";} -/* -MAYBE_NS: T_IDENTIFIER "::" {$$=$1;} - | T_NAMESPACE "::" {$$=(char*)$1;} - | '*' "::" {$$="*";} - | {$$=0;}*/ +%code { + node_t* resolve_identifier(const char*name); + node_t* get_descendants(node_t*e,const char*ns,const char*subnode,char multi, char attr) + { + typedcode_t v = node_read(e); + typedcode_t w; + + multiname_t m = {0,0,0,subnode}; + namespace_t zero = {ZERONAMESPACE,"*"}; + if(!strcmp(ns,"*")) { + m.ns = &zero; + m.type = attr?QNAMEA:QNAME; + } else { + typedcode_t w = node_read(resolve_identifier(ns)); + if(!TYPE_IS_NAMESPACE(w.t)) { + as3_softwarning("%s might not be a namespace", ns); + } + v.c = code_append(v.c, w.c); + v.c = converttype(v.c, w.t, TYPE_NAMESPACE); + m.type = attr?RTQNAMEA:RTQNAME; + } + + if(!multi) { + v.c = abc_getproperty2(v.c, &m); + } else { + v.c = abc_getdescendants2(v.c, &m); + } + + if(TYPE_IS_XML(v.t)) { + v.t = TYPE_XMLLIST; + } else { + v.c = abc_coerce_a(v.c); + v.t = TYPE_ANY; + } + return mkcodenode(v); + } +}; E : E '.' ID_OR_NS "::" SUBNODE { - typedcode_t v = node_read($1); - typedcode_t w = node_read(resolve_identifier($3)); - v.c = code_append(v.c, w.c); - if(!TYPE_IS_NAMESPACE(w.t)) { - as3_softwarning("%s might not be a namespace", $3); - } - v.c = converttype(v.c, w.t, TYPE_NAMESPACE); - multiname_t m = {RTQNAME, 0, 0, $5}; - v.c = abc_getproperty2(v.c, &m); - if(TYPE_IS_XML(v.t)) { - v.t = TYPE_XMLLIST; - } else { - v.c = abc_coerce_a(v.c); - v.t = TYPE_ANY; - } - $$ = mkcodenode(v); + $$ = get_descendants($1, $3, $5, 0, 0); } E : E ".." SUBNODE { typedcode_t v = node_read($1); @@ -3541,6 +3586,9 @@ E : E ".." SUBNODE { v.t = TYPE_XMLLIST; $$ = mkcodenode(v); } +E : E ".." ID_OR_NS "::" SUBNODE { + $$ = get_descendants($1, $3, $5, 1, 0); +} E : E '.' '[' E ']' { typedcode_t v = node_read($1); typedcode_t w = node_read($4); @@ -3559,6 +3607,11 @@ E : E '.' '@' SUBNODE { v.t = TYPE_STRING; $$ = mkcodenode(v); } + +E : E '.' '@' ID_OR_NS "::" SUBNODE { + $$ = get_descendants($1, $4, $6, 0, 1); +} + E : E ".." '@' SUBNODE { typedcode_t v = node_read($1); multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4}; @@ -3566,6 +3619,10 @@ E : E ".." '@' SUBNODE { v.t = TYPE_STRING; $$ = mkcodenode(v); } +E : E ".." '@' ID_OR_NS "::" SUBNODE { + $$ = get_descendants($1, $4, $6, 1, 1); +} + E : E '.' '@' '[' E ']' { typedcode_t v = node_read($1); typedcode_t w = node_read($5); @@ -3596,7 +3653,7 @@ MEMBER : E '.' SUBNODE { t = t->data; is_static = 1; } - if(TYPE_IS_XML(t)) { + if(TYPE_IS_XML(t) && !findmember_nsset(t, $3, 1, is_static)) { multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3}; $$.c = abc_getproperty2($$.c, &m); $$.c = abc_coerce_a($$.c); @@ -3605,7 +3662,7 @@ MEMBER : E '.' SUBNODE { if(t->subtype==INFOTYPE_UNRESOLVED) { syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name); } - memberinfo_t*f = findmember_nsset(t, $3, 1); + memberinfo_t*f = findmember_nsset(t, $3, 1, is_static); char noslot = 0; if(f && !is_static != !(f->flags&FLAG_STATIC)) noslot=1; @@ -3653,7 +3710,15 @@ MEMBER : E '.' SUBNODE { } %code { - node_t* resolve_identifier(char*name) + node_t* var_read(variable_t*v) + { + typedcode_t o; + o.c = abc_getlocal(0, v->index); + o.t = v->type; + return mkcodenode(o); + } + + node_t* resolve_identifier(const char*name) { typedcode_t o; o.t = 0; @@ -3666,9 +3731,7 @@ MEMBER : E '.' SUBNODE { /* look at variables */ if((v = find_variable(state, name))) { // name is a local variable - o.c = abc_getlocal(o.c, v->index); - o.t = v->type; - return mkcodenode(o); + return var_read(v); } if((v = find_slot(state->method, name))) { o.c = abc_getscopeobject(o.c, 1); @@ -3679,58 +3742,69 @@ MEMBER : E '.' SUBNODE { int i_am_static = state->method->is_static; - /* look at current class' members */ - if(!state->method->inner && - !state->xmlfilter && - state->cls && - (f = findmember_nsset(state->cls->info, name, 1))) - { - // name is a member or attribute in this class - int var_is_static = (f->flags&FLAG_STATIC); - - if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) { - /* if the variable is a constant (and we know what is evaluates to), we - can just use the value itself */ - varinfo_t*v = (varinfo_t*)f; - if(v->value) { - return mkconstnode(v->value); - } - } - - if(var_is_static >= i_am_static) { - if(f->kind == INFOTYPE_METHOD) { - o.t = TYPE_FUNCTION(f); - } else { - o.t = f->type; - } - - if(var_is_static && !i_am_static) { - /* access to a static member from a non-static location. - do this via findpropstrict: - there doesn't seem to be any non-lookup way to access - static properties of a class */ - state->method->late_binding = 1; - o.t = f->type; - namespace_t ns = {f->access, f->package}; - multiname_t m = {QNAME, &ns, 0, name}; - o.c = abc_findpropstrict2(o.c, &m); - o.c = abc_getproperty2(o.c, &m); - return mkcodenode(o); - } else if(f->slot>0) { - o.c = abc_getlocal_0(o.c); - o.c = abc_getslot(o.c, f->slot); - return mkcodenode(o); - } else { - MEMBER_MULTINAME(m, f, name); - o.c = abc_getlocal_0(o.c); - o.c = abc_getproperty2(o.c, &m); - return mkcodenode(o); - } - } - } + if(!state->method->inner && !state->xmlfilter && state->cls) + { + /* look at current class' members */ + if((f = findmember_nsset(state->cls->info, name, 1, i_am_static))) + { + // name is a member or attribute in this class + int var_is_static = (f->flags&FLAG_STATIC); + + if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) { + /* if the variable is a constant (and we know what is evaluates to), we + can just use the value itself */ + varinfo_t*v = (varinfo_t*)f; + if(v->value) { + return mkconstnode(v->value); + } + } + + if(var_is_static >= i_am_static) { + if(f->kind == INFOTYPE_METHOD) { + o.t = TYPE_FUNCTION(f); + } else { + o.t = f->type; + } + + if(var_is_static && !i_am_static) { + /* access to a static member from a non-static location. + do this via findpropstrict: + there doesn't seem to be any non-lookup way to access + static properties of a class */ + state->method->late_binding = 1; + o.t = f->type; + namespace_t ns = {f->access, f->package}; + multiname_t m = {QNAME, &ns, 0, name}; + o.c = abc_findpropstrict2(o.c, &m); + o.c = abc_getproperty2(o.c, &m); + return mkcodenode(o); + } else if(f->slot>0) { + o.c = abc_getlocal_0(o.c); + o.c = abc_getslot(o.c, f->slot); + return mkcodenode(o); + } else { + MEMBER_MULTINAME(m, f, name); + o.c = abc_getlocal_0(o.c); + o.c = abc_getproperty2(o.c, &m); + return mkcodenode(o); + } + } + } + /* special case: it's allowed to access non-static constants + from a static context */ + if(i_am_static && (f=findmember_nsset(state->cls->info, name, 1, 0))) { + if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) { + varinfo_t*v = (varinfo_t*)f; + if(v->value) { + return mkconstnode(v->value); + } + } + } + } /* look at actual classes, in the current package and imported */ if(!state->xmlfilter && (a = find_class(name))) { + registry_use(a); if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) { o.c = abc_getlocal_0(0); o.t = TYPE_CLASS((classinfo_t*)a); @@ -3744,7 +3818,7 @@ MEMBER : E '.' SUBNODE { if(!state->xmlfilter && (dict_contains(state->import_toplevel_packages, name) || registry_ispackage(name))) { - o.c = abc___pushpackage__(o.c, name); + o.c = abc___pushpackage__(o.c, (char*)name); o.t = 0; return mkcodenode(o); //? } @@ -3824,7 +3898,7 @@ NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING { } NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID { PASS12 - trie_put(active_namespaces, $2->name, (void*)$2->url); + dict_put(state->namespaces, (unsigned char*)$2->name, (void*)$2->url); namespace_t access = modifiers2access(&$1); varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name); @@ -3846,13 +3920,13 @@ NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID { DEFAULT_NAMESPACE : "default xml" "namespace" '=' E { - as3_warning("default xml namespaces not supported yet"); $$ = 0; + $$ = code_append($$, node_read($4).c); + $$ = abc_dxnslate($$); } USE_NAMESPACE : "use" "namespace" CLASS_SPEC { PASS12 - const char*url = $3->name; varinfo_t*s = (varinfo_t*)$3; if(s->kind == INFOTYPE_UNRESOLVED) { @@ -3865,9 +3939,9 @@ USE_NAMESPACE : "use" "namespace" CLASS_SPEC { 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); + const char*url = s->value->ns->name; + dict_put(state->namespaces, (unsigned char*)$3->name, (void*)url); add_active_url(url); $$=0; }