implemented asset resolving
[swftools.git] / lib / as3 / parser.y
index 0589116..b181866 100644 (file)
@@ -1,4 +1,4 @@
-/* parser.lex
+/* parser.y
 
    Routines for compiling Flash2 AVM2 ABC Actionscript
 
@@ -77,7 +77,7 @@ extern int a3_lex();
 }
 
 
-%token<id> T_IDENTIFIER T_NAMESPACE
+%token<id> T_IDENTIFIER
 %token<str> T_STRING
 %token<regexp> T_REGEXP
 %token<token> T_EMPTY
@@ -267,7 +267,6 @@ 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
 
@@ -345,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;
@@ -368,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 {
@@ -384,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;
@@ -398,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 {
@@ -492,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);
@@ -510,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;
@@ -526,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;
@@ -557,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
@@ -575,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;
@@ -638,7 +637,7 @@ typedef struct _variable {
 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) {
@@ -673,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)) {
@@ -719,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;
@@ -881,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)) {
@@ -908,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;
@@ -917,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, (unsigned char*)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)) 
@@ -943,7 +966,6 @@ 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, char is_static)
 {
@@ -1004,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;
+                }
+           }
         }
     }
 }
@@ -1060,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
@@ -1348,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;
@@ -1392,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;
 
@@ -1464,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);
                     }
                 }
             }
@@ -1476,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;
@@ -1498,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;
@@ -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;
@@ -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;
@@ -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
@@ -3506,7 +3535,6 @@ 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
        | '*' {$$="*";}
 
@@ -3714,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, 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);
-                }
-            }
-        } 
+        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);
@@ -3802,11 +3841,6 @@ MEMBER : E '.' SUBNODE {
     }
 };
 
-/* TODO: causes 16 r/r conflicts */
-VAR_READ : T_NAMESPACE {
-    PASS2 
-    $$ = resolve_identifier($1);
-}
 VAR_READ : T_IDENTIFIER {
     PASS1
     /* Queue unresolved identifiers for checking against the parent
@@ -3864,7 +3898,7 @@ NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
 }
 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
     PASS12
-    trie_put(active_namespaces, (unsigned char*)$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);
@@ -3893,7 +3927,6 @@ DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
 
 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
     PASS12
-    const char*url = $3->name;
 
     varinfo_t*s = (varinfo_t*)$3;
     if(s->kind == INFOTYPE_UNRESOLVED) {
@@ -3906,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, (unsigned char*)$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;
 }