added rollbacking functionality to trier (for namespaces)
[swftools.git] / lib / as3 / parser.y
index 2de22f6..a81e4e0 100644 (file)
@@ -65,6 +65,7 @@ extern int a3_lex();
     abc_exception_t *exception;
     regexp_t regexp;
     modifiers_t flags;
+    namespace_decl_t* namespace_decl;
     struct {
         abc_exception_list_t *l;
         code_t*finally;
@@ -170,7 +171,8 @@ extern int a3_lex();
 %token<token> T_SHR ">>"
 
 %type <for_start> FOR_START
-%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER NAMESPACE_ID
+%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
+%type <namespace_decl>  NAMESPACE_ID
 %type <token> VARCONST
 %type <code> CODE
 %type <code> CODEPIECE CODE_STATEMENT
@@ -215,7 +217,7 @@ extern int a3_lex();
 %type <value> NEW
 //%type <token> T_IDENTIFIER
 %type <value> FUNCTIONCALL
-%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
+%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST WITH_HEAD
 
 // precedence: from low to high
 
@@ -317,6 +319,7 @@ typedef struct _classstate {
 struct _methodstate {
     /* method data */
     methodinfo_t*info;
+    char has_exceptions;
     char late_binding;
     char is_constructor;
     char has_super;
@@ -336,6 +339,8 @@ struct _methodstate {
     char is_a_slot; // for inner methods
 
     code_t*header;
+
+    code_t*scope_code;
     abc_exception_list_t*exceptions;
     
     methodstate_list_t*innerfunctions;
@@ -349,7 +354,7 @@ typedef struct _state {
     import_list_t*wildcard_imports;
     dict_t*import_toplevel_packages;
     dict_t*imports;
-    namespace_list_t*active_namespaces;
+    
     char has_own_imports;
     char new_vars; // e.g. transition between two functions
   
@@ -357,6 +362,8 @@ typedef struct _state {
     methodstate_t*method;
 
     char*exception_name;
+
+    int switch_var;
     
     dict_t*vars;
 } state_t;
@@ -436,6 +443,8 @@ static void new_state()
     state->vars = dict_new(); 
     state->old = oldstate;
     state->new_vars = 0;
+
+    trie_remember(active_namespaces);
 }
 static void state_has_imports()
 {
@@ -482,12 +491,14 @@ 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;
     
     state = state->old;
-    
+
     if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
         free(leaving->method);
         leaving->method=0;
@@ -511,6 +522,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);
     
@@ -525,11 +539,11 @@ void initialize_file(char*filename)
     if(as3_pass==1) {
         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
     } else {
         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
         function_initvars(state->method, 0, 0, 1);
         global->init = abc_initscript(global->file);
-        state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
     }
 }
 
@@ -636,6 +650,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) {
@@ -645,11 +664,12 @@ 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;
-    
-    dict_put(state->vars, name, v);
+    if(name) 
+        dict_put(state->vars, name, v);
 
     return v;
 }
@@ -727,17 +747,27 @@ static void parsererror(const char*file, int line, const char*f)
 }
 
    
-static code_t* method_header(methodstate_t*m)
+static code_t* add_scope_code(code_t*c, methodstate_t*m)
 {
-    code_t*c = 0;
     if(m->uses_slots || (m->late_binding && !m->inner)) {
         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);
     }
+    return c;
+}
+
+static code_t* method_header(methodstate_t*m)
+{
+    code_t*c = 0;
+
+    c = add_scope_code(c, m);
+
     methodstate_list_t*l = m->innerfunctions;
     while(l) {
         parserassert(l->methodstate->abc);
@@ -813,7 +843,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;
-        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 */
+            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");
@@ -833,6 +870,12 @@ static namespace_t modifiers2access(modifiers_t*mod)
 }
 static slotinfo_t* find_class(const char*name);
 
+memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
+{
+    /* FIXME- we need to loop through namespaces here */
+    return registry_findmember(cls, "", name, recurse);
+}
+
 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
 {
     if(var0) {
@@ -847,23 +890,13 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char
             *(int*)0=0;
         parserassert(!index);
     }
+
     if(m->uses_slots) {
         /* as variables and slots share the same number, make sure
            that those variable indices are reserved. It's up to the
            optimizer to later shuffle the variables down to lower
            indices */
         m->variable_count = m->uses_slots;
-        DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
-            if(v->type) {
-                if(v->type->package)
-                    v->type = (classinfo_t*)registry_find(v->type->package, v->type->name);
-                else
-                    v->type = (classinfo_t*)find_class(v->type->name);
-                if(!v->type || v->type->kind != INFOTYPE_CLASS) {
-                    syntaxerror("Couldn't find class %s", v->type->name);
-                }
-            }
-        }
     }
 
     if(params) {
@@ -872,16 +905,35 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char
             new_variable(p->param->name, p->param->type, 0, 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;
+        
         variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
         m->var_index = v->index;
         m->slot_index = v->index;
         v->is_inner_method = m;
+
         l = l->next;
     }
+    
+    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);
+                }
+            }
+        }
+    }
 }
 
 
@@ -902,6 +954,7 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
     if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
         syntaxerror("public and internal not supported at the same time.");
     
+    //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
     if(!(mod->flags&FLAG_INTERFACE) && !extends) {
         // all classes extend object
         extends = registry_getobjectclass();
@@ -942,6 +995,12 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
         int num_interfaces = (list_length(implements));
         state->cls->info = classinfo_register(access, package, classname, num_interfaces);
         state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
+        
+        int pos = 0;
+        classinfo_list_t*l = implements;
+        for(l=implements;l;l=l->next) {
+            state->cls->info->interfaces[pos++] = l->classinfo;
+        }
     }
     
     if(as3_pass == 2) {
@@ -955,16 +1014,17 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
 
         if(extends && (extends->flags & FLAG_FINAL))
             syntaxerror("Can't extend final class '%s'", extends->name);
+        
+        int pos = 0;
+        while(state->cls->info->interfaces[pos]) {
+            if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
+                syntaxerror("'%s' is not an interface", 
+                    state->cls->info->interfaces[pos]->name);
+            pos++;
+        }
 
         /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
         state->cls->info->superclass = extends;
-        int pos = 0;
-        classinfo_list_t*l = implements;
-        for(l=implements;l;l=l->next) {
-            if(!(l->classinfo->flags & FLAG_INTERFACE))
-                syntaxerror("'%s' is not an interface", l->classinfo->name);
-            state->cls->info->interfaces[pos++] = l->classinfo;
-        }
 
         /* generate the abc code for this class */
         MULTINAME(classname2,state->cls->info);
@@ -1115,6 +1175,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
@@ -1325,8 +1386,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);
@@ -1366,6 +1425,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
             state->method->slots = dict_new();
             int i = 1;
             DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
+                if(!name) syntaxerror("internal error");
                 if(v->index && dict_contains(xvars, name)) {
                     v->init = 0;
                     v->index = i++;
@@ -1398,10 +1458,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);
@@ -1417,7 +1477,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;
@@ -1450,11 +1510,10 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
 
         check_code_for_break(body);
 
-        if(state->method->exceptions &&
-           (state->method->late_binding || state->method->uses_slots)) {
-           //syntaxerror("try/catch and activation or late binding not supported yet within the same method");
-           as3_warning("try/catch and activation or late binding not supported yet within the same method");
-        }
+        /* Seems this works now.
+        if(state->method->exceptions && state->method->uses_slots) {
+           as3_warning("try/catch and activation not supported yet within the same method");
+        }*/
 
         if(f->body) {
             f->body->code = body;
@@ -1602,6 +1661,36 @@ char is_pushundefined(code_t*c)
     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
 }
 
+static const char* get_package_from_name(const char*name)
+{
+    /* try explicit imports */
+    dictentry_t* e = dict_get_slot(state->imports, name);
+    while(e) {
+        if(!strcmp(e->key, name)) {
+            slotinfo_t*c = (slotinfo_t*)e->data;
+            if(c) return c->package;
+        }
+        e = e->next;
+    }
+    return 0;
+}
+static namespace_list_t*get_current_imports()
+{
+    namespace_list_t*searchlist = 0;
+    
+    list_append(searchlist, namespace_new_package(state->package));
+
+    import_list_t*l = state->wildcard_imports;
+    while(l) {
+        namespace_t*ns = namespace_new_package(l->import->package);
+        list_append(searchlist, ns);
+        l = l->next;
+    }
+    list_append(searchlist, namespace_new_package(""));
+    list_append(searchlist, namespace_new_package(internal_filename_package));
+    return searchlist;
+}
+
 static slotinfo_t* find_class(const char*name)
 {
     slotinfo_t*c=0;
@@ -1862,7 +1951,6 @@ char is_break_or_jump(code_t*c)
     return 0;
 }
 
-
 #define IS_FINALLY_TARGET(op) \
         ((op) == OPCODE___CONTINUE__ || \
          (op) == OPCODE___BREAK__ || \
@@ -1970,10 +2058,10 @@ code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
     int lookup_version_cost = 4*num_insertion_points + 5;
 
     if(cantdup || simple_version_cost > lookup_version_cost) {
-        printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
+        //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
         return insert_finally_lookup(c, finally, tempvar);
     } else {
-        printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
+        //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
         return insert_finally_simple(c, finally, tempvar);
     }
 }
@@ -2304,7 +2392,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);
@@ -2317,10 +2405,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;
@@ -2364,6 +2454,7 @@ CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
     int i = find_variable_safe(state, $3)->index;
     e->target = c = abc_nop(0);
     c = abc_setlocal(c, i);
+    c = code_append(c, code_dup(state->method->scope_code));
     c = code_append(c, $8);
     c = abc_kill(c, i);
 
@@ -2406,7 +2497,10 @@ CATCH_FINALLY_LIST: FINALLY {
     }
 }
 
-TRY : "try" '{' {PASS12 new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
+TRY : "try" '{' {PASS12 new_state();
+                 state->method->has_exceptions=1;
+                 state->method->late_binding=1;//for invariant scope_code
+                } MAYBECODE '}' CATCH_FINALLY_LIST {
     code_t*out = abc_nop(0);
 
     code_t*start = abc_nop(0);
@@ -2431,6 +2525,7 @@ TRY : "try" '{' {PASS12 new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
             parserassert((ptroff_t)$6.finally);
             // finally block
             e->target = $$ = abc_nop($$);
+            $$ = code_append($$, code_dup(state->method->scope_code));
             $$ = abc___rethrow__($$);
         }
         
@@ -2466,17 +2561,36 @@ THROW : "throw" %prec prec_none {
 
 /* ------------ with -------------------------------- */
 
-WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
-     $$ = $3.c;
+WITH_HEAD : "with" '(' EXPRESSION ')' {
+     new_state();
+     if(state->method->has_exceptions) {
+         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;
+     }
+     $$.cc = $3.c;
+} 
+WITH : WITH_HEAD CODEBLOCK {
+     /* remove getlocal;pushwith from scope code again */
+     state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
+
+     $$ = $1.cc;
+     if(state->method->has_exceptions) {
+         $$ = abc_dup($$);
+         $$ = abc_setlocal($$, $1.number);
+     }
      $$ = abc_pushwith($$);
-     $$ = code_append($$, $5);
+     $$ = code_append($$, $2);
      $$ = abc_popscope($$);
+     old_state();
 }
 
 /* ------------ packages and imports ---------------- */
 
 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);}
@@ -2529,7 +2643,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;}
@@ -2543,8 +2656,8 @@ MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
                                $$.ns=$1;
                        }
 
-EXTENDS : {$$=0;}
-EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
+EXTENDS : {PASS12 $$=0;}
+EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
 
 EXTENDS_LIST : {PASS12 $$=list_new();}
 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
@@ -2807,30 +2920,32 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
 
 /* ------------- package + class ids --------------- */
 
-CLASS: T_IDENTIFIER {
-    PASS1 static classinfo_t c;
-          memset(&c, 0, sizeof(c));
-          c.kind = INFOTYPE_CLASS;
-          c.subtype = 255;
-          c.name = $1;
-          $$ = &c;
-   
-          /* let the compiler know that we might be looking for this soon */
-          as3_schedule_class_noerror(state->package, $1);
+CLASS: X_IDENTIFIER {
+    PASS1 NEW(unresolvedinfo_t,c);
+          memset(c, 0, sizeof(*c));
+          c->kind = INFOTYPE_UNRESOLVED;
+          c->name = $1;
+          c->package = get_package_from_name($1);
+          if(!c->package) {
+              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);
+          }
+          $$ = (classinfo_t*)c;
     PASS2
     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;
 }
 
-PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
-    PASS1 static classinfo_t c;
-          memset(&c, 0, sizeof(c));
-          c.kind = INFOTYPE_CLASS;
-          c.subtype = 255;
-          c.package = $1;
-          c.name = $3;
-          $$ = &c;
+PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
+    PASS1 NEW(unresolvedinfo_t,c);
+          memset(c, 0, sizeof(*c));
+          c->kind = INFOTYPE_UNRESOLVED;
+          c->package = $1;
+          c->name = $3;
+          $$ = (classinfo_t*)c;
     PASS2
     slotinfo_t*s = registry_find($1, $3);
     if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
@@ -2860,20 +2975,20 @@ MAYBETYPE:          {PASS12 $$=0;}
 
 /* ----------function calls, delete, constructor calls ------ */
 
-MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.len=0;}
+MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.number=0;}
 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
 
-MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
+MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
 
-EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.len=1;
+EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.number=1;
                                                   $$.cc = $1.c;
                                                  }
 
 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
-                                                  $$.len= $1.len+1;
+                                                  $$.number= $1.number+1;
                                                   $$.cc = code_append($1.cc, $2.c);
                                                   }
                
@@ -2887,7 +3002,7 @@ NEW : "new" E XX MAYBE_PARAM_VALUES {
         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
         $$.c = code_cutlast($$.c);
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_constructprop2($$.c, name, $4.len);
+        $$.c = abc_constructprop2($$.c, name, $4.number);
         multiname_destroy(name);
     } else if($$.c->opcode == OPCODE_GETSLOT) {
         int slot = (int)(ptroff_t)$$.c->data[0];
@@ -2895,10 +3010,10 @@ NEW : "new" E XX MAYBE_PARAM_VALUES {
         multiname_t*name = t->name;
         $$.c = code_cutlast($$.c);
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_constructprop2($$.c, name, $4.len);
+        $$.c = abc_constructprop2($$.c, name, $4.number);
     } else {
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_construct($$.c, $4.len);
+        $$.c = abc_construct($$.c, $4.number);
     }
    
     $$.t = TYPE_ANY;
@@ -2927,7 +3042,7 @@ FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
         $$.c = code_cutlast($$.c);
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_callproperty2($$.c, name, $3.len);
+        $$.c = abc_callproperty2($$.c, name, $3.number);
         multiname_destroy(name);
     } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
         int slot = (int)(ptroff_t)$$.c->data[0];
@@ -2939,17 +3054,17 @@ FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
         $$.c = code_cutlast($$.c);
         $$.c = code_append($$.c, paramcode);
         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
-        $$.c = abc_callproperty2($$.c, name, $3.len);
+        $$.c = abc_callproperty2($$.c, name, $3.number);
     } else if($$.c->opcode == OPCODE_GETSUPER) {
         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
         $$.c = code_cutlast($$.c);
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_callsuper2($$.c, name, $3.len);
+        $$.c = abc_callsuper2($$.c, name, $3.number);
         multiname_destroy(name);
     } else {
         $$.c = abc_getglobalscope($$.c);
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_call($$.c, $3.len);
+        $$.c = abc_call($$.c, $3.number);
     }
    
     if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
@@ -2976,7 +3091,7 @@ FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
     */
     state->method->has_super = 1;
 
-    $$.c = abc_constructsuper($$.c, $3.len);
+    $$.c = abc_constructsuper($$.c, $3.number);
     $$.c = abc_pushundefined($$.c);
     $$.t = TYPE_ANY;
 }
@@ -3285,22 +3400,22 @@ E : E '[' E ']' {
 E : '[' MAYBE_EXPRESSION_LIST ']' {
     $$.c = code_new();
     $$.c = code_append($$.c, $2.cc);
-    $$.c = abc_newarray($$.c, $2.len);
+    $$.c = abc_newarray($$.c, $2.number);
     $$.t = registry_getarrayclass();
 }
 
-MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
+MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
 
 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
     $$.cc = 0;
     $$.cc = code_append($$.cc, $1.c);
     $$.cc = code_append($$.cc, $3.c);
-    $$.len = 2;
+    $$.number = 2;
 }
 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
     $$.cc = $1.cc;
-    $$.len = $1.len+2;
+    $$.number = $1.number+2;
     $$.cc = code_append($$.cc, $3.c);
     $$.cc = code_append($$.cc, $5.c);
 }
@@ -3310,7 +3425,7 @@ EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
     $$.c = code_new();
     $$.c = code_append($$.c, $2.cc);
-    $$.c = abc_newobject($$.c, $2.len/2);
+    $$.c = abc_newobject($$.c, $2.number/2);
     $$.t = registry_getobjectclass();
 }
 
@@ -3487,7 +3602,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;
@@ -3544,10 +3659,10 @@ E : E '.' T_IDENTIFIER {
         is_static = 1;
     }
     if(t) {
-        if(t->subtype==0xff) {
+        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;
@@ -3626,7 +3741,7 @@ 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)) &&
+    if(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);
@@ -3692,22 +3807,44 @@ VAR_READ : T_IDENTIFIER {
 
 NAMESPACE_ID : "namespace" T_IDENTIFIER {
     PASS12
-    tokenizer_register_namespace($2);
-    $$=$2;
+    NEW(namespace_decl_t,n);
+    n->name = $2;
+    n->url = $2;
+    $$=n;
 }
-
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
-    $$=0;
+NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
+    PASS12
+    NEW(namespace_decl_t,n);
+    n->name = $2;
+    n->url = $4;
+    $$=n;
 }
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_IDENTIFIER {
-    $$=0;
+NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
+    PASS12
+    NEW(namespace_decl_t,n);
+    n->name = $2;
+    n->url = $4.str;
+    $$=n;
 }
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_STRING {
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
+    PASS12
+    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
-    tokenizer_register_namespace($3->name);
+    char*url = 0;
+    trie_put(active_namespaces, $3->name, url);
     $$=0;
 }