as3compile: added -R option, fixed some namespace bugs
[swftools.git] / lib / as3 / parser.y
index 2de22f6..d0927b2 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;
@@ -329,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
@@ -336,6 +340,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 +355,9 @@ typedef struct _state {
     import_list_t*wildcard_imports;
     dict_t*import_toplevel_packages;
     dict_t*imports;
-    namespace_list_t*active_namespaces;
+
+    namespace_list_t*active_namespace_urls;
+    
     char has_own_imports;
     char new_vars; // e.g. transition between two functions
   
@@ -357,6 +365,8 @@ typedef struct _state {
     methodstate_t*method;
 
     char*exception_name;
+
+    int switch_var;
     
     dict_t*vars;
 } state_t;
@@ -436,6 +446,11 @@ static void new_state()
     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()
 {
@@ -477,17 +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;
-    
+
     if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
         free(leaving->method);
         leaving->method=0;
@@ -496,7 +516,7 @@ static void old_state()
         free(leaving->cls);
         leaving->cls=0;
     }
-    
+
     state_destroy(leaving);
 }
 
@@ -511,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);
     
@@ -525,11 +548,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
     }
 }
 
@@ -602,6 +625,7 @@ typedef struct _variable {
     int index;
     classinfo_t*type;
     char init;
+    char is_parameter;
     methodstate_t*is_inner_method;
 } variable_t;
 
@@ -636,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) {
@@ -645,11 +674,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 +757,36 @@ 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, char init)
 {
-    code_t*c = 0;
-    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) {
-        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;
+}
+
+static code_t* method_header(methodstate_t*m)
+{
+    code_t*c = 0;
+
+    c = add_scope_code(c, m, 1);
+
     methodstate_list_t*l = m->innerfunctions;
     while(l) {
         parserassert(l->methodstate->abc);
@@ -763,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;
@@ -813,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");
@@ -833,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) {
@@ -847,41 +929,54 @@ 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) {
         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(m->uses_slots) {
+        dict_dump(m->slots, stdout, "");
+    }
+
     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->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) {
+                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;
+            }
+        }
+    }
 }
 
 
@@ -902,6 +997,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 +1038,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 +1057,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 +1218,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 +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);
@@ -1366,6 +1468,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 +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);
@@ -1417,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;
@@ -1450,11 +1553,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 +1704,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 +1994,6 @@ char is_break_or_jump(code_t*c)
     return 0;
 }
 
-
 #define IS_FINALLY_TARGET(op) \
         ((op) == OPCODE___CONTINUE__ || \
          (op) == OPCODE___BREAK__ || \
@@ -1970,10 +2101,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 +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);
@@ -2317,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;
@@ -2364,6 +2497,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 +2540,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 +2568,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 +2604,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);}
@@ -2492,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");
@@ -2508,7 +2663,6 @@ IMPORT : "import" PACKAGE '.' '*' {
            as3_schedule_package($2);
        }
 
-       PASS2
        NEW(import_t,i);
        i->package = $2;
        state_has_imports();
@@ -2529,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;}
@@ -2543,8 +2696,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 +2960,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 +3015,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 +3042,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 +3050,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 +3082,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 +3094,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 +3131,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;
 }
@@ -3027,13 +3182,9 @@ VOIDEXPRESSION : EXPRESSION %prec below_minus {
 // ----------------------- expression evaluation -------------------------------------
 
 E : INNERFUNCTION %prec prec_none {$$ = $1;}
-//V : CONSTANT                    {$$ = 0;}
 E : CONSTANT
-//V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
-//V : NEW                         {$$ = $1.c;}
 E : NEW                         {$$ = $1;}
-//V : DELETE                      {$$ = $1.c;}
 E : DELETE                      {$$ = $1;}
 
 E : FUNCTIONCALL
@@ -3285,22 +3436,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 +3461,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 +3638,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;
@@ -3531,8 +3682,12 @@ E : E '.' '(' E ')' {
               as3_warning("ignored .() operator");
            }
 
-//VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
-
+//E : E "::" '[' E ']' {
+//              // qualified expression TODO
+//              $$.c = abc_pushundefined(0);
+//              $$.t = 0;
+//              as3_warning("ignored ::[] operator");
+//           }
 
 
 E : E '.' T_IDENTIFIER {
@@ -3544,16 +3699,19 @@ 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;
         if(f && f->slot && !noslot) {
             $$.c = abc_getslot($$.c, f->slot);
         } else {
+            if(!f) 
+                as3_warning("Access of undefined property '%s' in %s", $3, t->name);
+            
             MEMBER_MULTINAME(m, f, $3);
             $$.c = abc_getproperty2($$.c, &m);
         }
@@ -3564,20 +3722,23 @@ E : E '.' T_IDENTIFIER {
     } else if($1.c && $1.c->opcode == OPCODE___PUSHPACKAGE__) {
         string_t*package = $1.c->data[0];
         char*package2 = concat3(package->str, ".", $3);
-        if(dict_contains(state->import_toplevel_packages, package2)) {
+
+        slotinfo_t*a = registry_find(package->str, $3);
+        if(a) {
+            $$ = push_class(a);
+        } else if(dict_contains(state->import_toplevel_packages, package2) ||
+                  registry_ispackage(package2)) {
             $$.c = $1.c;
             $$.c->data[0] = string_new4(package2);
             $$.t = 0;
         } else {
-            slotinfo_t*a = registry_find(package->str, $3);
-            if(!a) 
-                syntaxerror("couldn't resolve %s", package2);
-            $$ = push_class(a);
+            syntaxerror("couldn't resolve %s", package2);
         }
     } else {
         /* when resolving a property on an unknown type, we do know the
            name of the property (and don't seem to need the package), but
            we need to make avm2 try out all access modes */
+        as3_warning("Resolving %s on unknown type", $3);
         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
         $$.c = abc_getproperty2($$.c, &m);
         $$.c = abc_coerce_a($$.c);
@@ -3598,7 +3759,7 @@ VAR_READ : T_IDENTIFIER {
         unknown_variable($1);
     }
    
-    /* let the compiler know that it might check the current directory/package
+    /* let the compiler know that it might want to check the current directory/package
        for this identifier- maybe there's a file $1.as defining $1. */
     as3_schedule_class_noerror(state->package, $1);
     PASS2
@@ -3626,8 +3787,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);
 
@@ -3643,7 +3807,7 @@ VAR_READ : T_IDENTIFIER {
            static properties of a class */
             state->method->late_binding = 1;
             $$.t = f->type;
-            namespace_t ns = {f->access, ""};
+            namespace_t ns = {f->access, f->package};
             multiname_t m = {QNAME, &ns, 0, $1};
             $$.c = abc_findpropstrict2($$.c, &m);
             $$.c = abc_getproperty2($$.c, &m);
@@ -3653,7 +3817,7 @@ VAR_READ : T_IDENTIFIER {
             $$.c = abc_getslot($$.c, f->slot);
             break;
         } else {
-            namespace_t ns = {f->access, ""};
+            namespace_t ns = {f->access, f->package};
             multiname_t m = {QNAME, &ns, 0, $1};
             $$.c = abc_getlocal_0($$.c);
             $$.c = abc_getproperty2($$.c, &m);
@@ -3668,7 +3832,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;
@@ -3692,22 +3857,59 @@ 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);
+    const char*url = $3->name;
+
+    varinfo_t*s = (varinfo_t*)$3;
+    if(s->kind == INFOTYPE_UNRESOLVED) {
+        s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
+        if(!s)
+            syntaxerror("Couldn't resolve namespace %s", $3->name);
+    }
+
+    if(!s || s->kind != INFOTYPE_SLOT)
+        syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
+    if(!s->value || !NS_TYPE(s->value->type))
+        syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
+    url = s->value->ns->name;
+
+    trie_put(active_namespaces, $3->name, (void*)url);
+    add_active_url(url);
     $$=0;
 }