implemented asset resolving
[swftools.git] / lib / as3 / parser.y
index 4699a90..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
@@ -176,14 +176,14 @@ extern int a3_lex();
 %token<token> T_USHR ">>>"
 %token<token> T_SHR ">>"
 
-%type <number_int> CONDITIONAL_COMPILATION
+%type <number_int> CONDITIONAL_COMPILATION EMBED_START
 %type <for_start> FOR_START
 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER ID_OR_NS SUBNODE
 %type <namespace_decl>  NAMESPACE_ID
 %type <token> VARCONST
 %type <code> CODE
 %type <code> CODEPIECE CODE_STATEMENT
-%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
+%type <code> CODEBLOCK IF_CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
@@ -217,7 +217,7 @@ extern int a3_lex();
 %type <classinfo_list> EXTENDS_LIST
 %type <classinfo> CLASS PACKAGEANDCLASS
 %type <classinfo_list> CLASS_SPEC_LIST
-%type <id> XML XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT XML_ID_OR_EXPR XMLEXPR1 XMLEXPR2
+%type <node>  XMLEXPR1 XMLEXPR2 XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT XML_ID_OR_EXPR XML
 %type <classinfo> TYPE
 //%type <token> VARIABLE
 %type <value> MEMBER
@@ -266,11 +266,10 @@ extern int a3_lex();
 
 // needed for "return" precedence:
 %nonassoc T_STRING T_REGEXP
-%nonassoc T_INT T_UINT T_FLOAT KW_NAN
+%nonassoc T_INT T_UINT T_FLOAT KW_NAN 
 %nonassoc "false" "true" "null" "undefined" "super" "function"
 %left above_function
 
-
      
 %{
 
@@ -345,9 +344,11 @@ 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;
+    char no_variable_scoping;
     int uses_slots;
     dict_t*slots;
     int activation_var;
@@ -367,6 +368,23 @@ 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;
+    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 {
     struct _state*old;
     int level;
@@ -376,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;
@@ -390,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 {
@@ -484,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);
@@ -502,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;
@@ -518,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;
@@ -527,8 +536,7 @@ static void old_state()
     state = state->old;
 
     if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
-        free(leaving->method);
-        leaving->method=0;
+        methodstate_destroy(leaving->method);leaving->method=0;
     }
     if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
         free(leaving->cls);
@@ -550,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
@@ -568,12 +573,14 @@ 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;
         if(!state->method)
             syntaxerror("internal error: skewed tokencount");
         function_initvars(state->method, 0, 0, 0, 1);
-        global->init = abc_initscript(global->file);
+        global->init = 0;
     }
 }
 
@@ -586,9 +593,12 @@ void finish_file()
     if(as3_pass==2) {
         dict_del(global->file2token2info, current_filename);
         code_t*header = method_header(state->method);
-        code_t*c = wrap_function(header, 0, global->init->method->body->code);
-        global->init->method->body->code = abc_returnvoid(c);
-        free(state->method);state->method=0;
+        //if(global->init->method->body->code || global->init->traits) {
+        if(global->init) {
+            code_t*c = wrap_function(header, 0, global->init->method->body->code);
+            global->init->method->body->code = abc_returnvoid(c);
+            free(state->method);state->method=0;
+        }
     }
 
     //free(state->package);state->package=0; // used in registry
@@ -619,26 +629,31 @@ typedef struct _variable {
     int index;
     classinfo_t*type;
     char init;
+    char kill;
     char is_parameter;
     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)
 {
-    state_t*top = s;
-    while(s) {
-        variable_t*v = 0;
-        v = dict_lookup(s->vars, name);
-        if(v) return v;
-        if(s->new_vars) break;
-        s = s->old;
+    if(s->method->no_variable_scoping) {
+        return dict_lookup(s->method->allvars, name);
+    } else {
+        state_t*top = s;
+        while(s) {
+            variable_t*v = 0;
+            v = dict_lookup(s->vars, name);
+            if(v) return v;
+            if(s->new_vars) break;
+            s = s->old;
+        }
+        return 0;
     }
-    return dict_lookup(top->allvars, name);
 }
-static variable_t* find_slot(state_t*s, const char*name)
+static variable_t* find_slot(methodstate_t*m, const char*name)
 {
-    if(s->method && s->method->slots)
-        return dict_lookup(s->method->slots, name);
+    if(m && m->slots)
+        return dict_lookup(m->slots, name);
     return 0;
 }
 
@@ -657,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)) {
@@ -684,10 +700,10 @@ static int alloc_local()
     return state->method->variable_count++;
 }
 
-static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
+static variable_t* new_variable2(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
 {
     if(maybeslot) {
-        variable_t*v = find_slot(state, name);
+        variable_t*v = find_slot(method, name);
         if(v) {
             alloc_local(); 
             return v;
@@ -697,18 +713,34 @@ static variable_t* new_variable2(const char*name, classinfo_t*type, char init, c
     NEW(variable_t, v);
     v->index = alloc_local();
     v->type = type;
-    v->init = init;
+    v->init = v->kill = init;
  
     if(name) {
-        dict_put(state->vars, name, v);
-        dict_put(state->allvars, name, v);
+        if(!method->no_variable_scoping) 
+        {
+            if(dict_contains(state->vars, name)) {
+                syntaxerror("variable %s already defined", name);
+            }
+            dict_put(state->vars, name, v);
+        }
+        if(method->no_variable_scoping && 
+           as3_pass==2 && 
+           dict_contains(state->method->allvars, name)) 
+        {
+            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->method->allvars, name, v);
     }
 
     return v;
 }
-static int new_variable(const char*name, classinfo_t*type, char init, char maybeslot)
+static int new_variable(methodstate_t*method, const char*name, classinfo_t*type, char init, char maybeslot)
 {
-    return new_variable2(name, type, init, maybeslot)->index;
+    return new_variable2(method, name, type, init, maybeslot)->index;
 }
 
 #define TEMPVARNAME "__as3_temp__"
@@ -719,23 +751,23 @@ int gettempvar()
     if(v) 
         i = v->index;
     else
-        i = new_variable(TEMPVARNAME, 0, 0, 0);
+        i = new_variable(state->method, TEMPVARNAME, 0, 0, 0);
     parserassert(i);
     return i;
 }
 
-static code_t* var_block(code_t*body) 
+static code_t* var_block(code_t*body, dict_t*vars) 
 {
     code_t*c = 0;
     code_t*k = 0;
     int t;
-    int num=0;
-    DICT_ITERATE_DATA(state->vars, variable_t*, v) {
+    DICT_ITERATE_DATA(vars, variable_t*, v) {
         if(v->type && v->init) {
             c = defaultvalue(c, v->type);
             c = abc_setlocal(c, v->index);
+        }
+        if(v->type && v->kill) {
             k = abc_kill(k, v->index); 
-            num++;
         }
     }
 
@@ -773,7 +805,7 @@ static void unknown_variable(char*name)
 
 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
 {
-    if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
+    if(m->uses_slots || m->innerfunctions || (m->late_binding && !m->inner)) {
         c = abc_getlocal_0(c);
         c = abc_pushscope(c);
     }
@@ -849,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));
+    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)) {
@@ -876,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;
@@ -885,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)) 
@@ -911,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)
@@ -924,7 +978,7 @@ static void innerfunctions2vars(methodstate_t*m)
     while(l) {
         methodstate_t*m = l->methodstate;
         
-        variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 0);
+        variable_t* v = new_variable2(state->method, m->info->name, TYPE_FUNCTION(m->info), 0, 0);
         m->var_index = v->index;
         if(m->is_a_slot)
             m->slot_index = m->is_a_slot;
@@ -938,25 +992,30 @@ static void function_initvars(methodstate_t*m, char has_params, params_t*params,
     if(var0) {
         int index = -1;
         if(m->inner)
-            index = new_variable("this", 0, 0, 0);
+            index = new_variable(m, "this", 0, 0, 0);
         else if(!m->is_global)
-            index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
+            index = new_variable(m, (flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
         else
-            index = new_variable("globalscope", 0, 0, 0);
+            index = new_variable(m, "globalscope", 0, 0, 0);
+        if(index) {
+            DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
+                printf("%s %d\n", name, v->index);
+            }
+        }
         parserassert(!index);
     }
 
     if(has_params) {
         param_list_t*p=0;
         for(p=params->list;p;p=p->next) {
-            variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
+            variable_t*v = new_variable2(m, p->param->name, p->param->type, 0, 1);
             v->is_parameter = 1;
         }
         if(as3_pass==2 && m->need_arguments) {
             /* arguments can never be used by an innerfunction (the inner functions
                have their own arguments var), so it's ok to  not initialize this until
                pass 2. (We don't know whether we need it before, anyway) */
-            variable_t*v = new_variable2("arguments", TYPE_ARRAY, 0, 0);
+            variable_t*v = new_variable2(m, "arguments", TYPE_ARRAY, 0, 0);
             m->need_arguments = v->index;
         }
     }
@@ -967,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;
+                }
+           }
         }
     }
 }
@@ -1023,10 +1093,9 @@ 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;
-        state->cls->static_init->variable_count=1;
         /* notice: we make no effort to initialize the top variable (local0) here,
            even though it has special meaning. We just rely on the fact
            that pass 1 won't do anything with variables */
@@ -1056,10 +1125,12 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
     if(as3_pass == 2) {
         state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
     
-        state->method = state->cls->init;
         parserassert(state->cls && state->cls->info);
        
+        state->method = state->cls->static_init;
+
         function_initvars(state->cls->init, 0, 0, 0, 1);
+        state->cls->static_init->variable_count=1;
         function_initvars(state->cls->static_init, 0, 0, 0, 0);
 
         if(extends && (extends->flags & FLAG_FINAL))
@@ -1200,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);
@@ -1236,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
@@ -1256,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);
@@ -1278,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;
@@ -1299,21 +1370,27 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
     //parserassert(state->method && state->method->info);
 
     methodstate_t*parent_method = state->method;
+    variable_t*v = 0;
 
     if(as3_pass==1) {
         return_type = 0; // not valid in pass 1
+        if(name) {
+            v = new_variable2(parent_method, name, 0, 0, 0);
+        }
     }
 
     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;
         state->method->abc = rfx_calloc(sizeof(abc_method_t));
+        if(v) {
+            v->is_inner_method = state->method;
+        }
 
         NEW(methodinfo_t,minfo);
         minfo->kind = INFOTYPE_METHOD;
@@ -1347,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;
 
@@ -1376,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);
         }
             
@@ -1388,43 +1464,60 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
     } 
 }
 
+static void insert_unresolved(methodstate_t*m, dict_t*xvars, dict_t*allvars)
+{
+    parserassert(m->inner);
+    if(m->unresolved_variables) {
+        dict_t*d = m->unresolved_variables;
+        int t;
+        DICT_ITERATE_KEY(d, char*, id) {
+            /* check parent method's variables */
+            variable_t*v;
+            if(dict_contains(allvars, id)) {
+                m->uses_parent_function = 1;
+                state->method->uses_slots = 1;
+                dict_put(xvars, id, 0);
+            }
+        }
+    }
+    methodstate_list_t*ml = m->innerfunctions;
+    while(ml) {
+        insert_unresolved(ml->methodstate, xvars, allvars);
+        ml = ml->next;
+    }
+}
+
 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
                           params_t*params, classinfo_t*return_type, code_t*body)
 {
     if(as3_pass==1) {
-        innerfunctions2vars(state->method);
-
-        methodstate_list_t*ml = state->method->innerfunctions;
-        
         dict_t*xvars = dict_new();
-
-        while(ml) {
-            methodstate_t*m = ml->methodstate;
-            parserassert(m->inner);
-            if(m->unresolved_variables) {
-                dict_t*d = m->unresolved_variables;
-                int t;
-                DICT_ITERATE_KEY(d, char*, id) {
-                    /* check parent method's variables */
-                    variable_t*v;
-                    if((v=find_variable(state, id))) {
-                        m->uses_parent_function = 1;
-                        state->method->uses_slots = 1;
-                        dict_put(xvars, id, 0);
+        
+        if(state->method->unresolved_variables) {
+            DICT_ITERATE_KEY(state->method->unresolved_variables, char*, 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 compatibility mode", name, vname);
                     }
                 }
-                dict_destroy(m->unresolved_variables);m->unresolved_variables = 0;
             }
+        }
+
+        methodstate_list_t*ml = state->method->innerfunctions;
+        while(ml) {
+            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->vars, 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 = 0;
+                    v->init = v->kill = 0;
                     v->index = i;
                     if(v->is_inner_method) {
                         v->is_inner_method->is_a_slot = i;
@@ -1436,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;
@@ -1469,6 +1561,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
             multiname_t mname = {QNAME, &mname_ns, 0, name};
 
             f = abc_method_new(global->file, type2, 1);
+            if(!global->init) global->init = abc_initscript(global->file);
             trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
             //abc_code_t*c = global->init->method->body->code;
         }
@@ -1621,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);
@@ -1926,6 +2020,7 @@ INPACKAGE_CODE: INTERFACE_DECLARATION
               | SLOT_DECLARATION
               | PACKAGE_INITCODE
               | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
+              | '[' EMBED_START E ']' {PASS_ALWAYS as3_pass=$2;PASS1 as3_warning("embed command ignored");}
               | ';'
 
 MAYBECODE: CODE {$$=$1;}
@@ -1979,8 +2074,20 @@ CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
 /* ------------ package init code ------------------- */
 
 PACKAGE_INITCODE: CODE_STATEMENT {
-    code_t**cc = &global->init->method->body->code;
-    *cc = code_append(*cc, $1);
+    if($1) {
+        if(!global->init) 
+            global->init = abc_initscript(global->file);
+        code_t**cc = &global->init->method->body->code;
+        *cc = code_append(*cc, $1);
+    }
+}
+
+/* ------------ embed code ------------- */
+
+EMBED_START: %prec above_function {
+    PASS_ALWAYS
+    $$ = as3_pass;
+    as3_pass=0;
 }
 
 /* ------------ conditional compilation ------------- */
@@ -2002,6 +2109,14 @@ CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
     {
         return 1; // FIXME
     }
+    char do_init_variable(char*name)
+    {
+        if(!state->method->no_variable_scoping)
+            return 0;
+        if(!state->new_vars)
+            return 1;
+        return 1;
+    }
 };
 
 MAYBEEXPRESSION : '=' E {$$=$2;}
@@ -2016,84 +2131,86 @@ VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
 {
 PASS12
-    if(variable_exists($1))
+    if(variable_exists($1)) 
         syntaxerror("Variable %s already defined", $1);
 PASS1
-    new_variable($1, 0, 1, 0);
+    new_variable(state->method, $1, $2, 1, 0);
 PASS2
    
     char slot = 0;
     int index = 0;
+    variable_t*v = 0;
     if(state->method->uses_slots) {
-        variable_t* v = find_slot(state, $1);
+        v = find_slot(state->method, $1);
         if(v && !v->init) {
             // this variable is stored in a slot
             v->init = 1;
             v->type = $2;
             slot = 1;
-            index = v->index;
         }
     }
-    if(!index) {
-        index = new_variable($1, $2, 1, 0);
+    if(!v) {
+        v = new_variable2(state->method, $1, $2, 1, 0);
     }
 
     $$ = slot?abc_getscopeobject(0, 1):0;
     
-    typedcode_t v = node_read($3);
-    if(!is_subtype_of(v.t, $2)) {
-        syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
+    typedcode_t val = node_read($3);
+    if(!is_subtype_of(val.t, $2)) {
+        syntaxerror("Can't convert %s to %s", val.t->name, $2->name);
     }
     if($2) {
-        if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
-            $$ = code_append($$, v.c);
-            $$ = converttype($$, v.t, $2);
+        if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
+            $$ = code_append($$, val.c);
+            $$ = converttype($$, val.t, $2);
         } else {
-            code_free(v.c);
+            code_free(val.c);
             $$ = defaultvalue($$, $2);
         }
     } else {
-        if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
-            $$ = code_append($$, v.c);
+        if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
+            $$ = code_append($$, val.c);
             $$ = abc_coerce_a($$);
         } else {
             // don't do anything
-            code_free(v.c);
+            code_free(val.c);
             code_free($$);
             $$ = 0;
             break;
         }
     }
     if(slot) {
-        $$ = abc_setslot($$, index);
+        $$ = abc_setslot($$, v->index);
     } else {
-        $$ = abc_setlocal($$, index);
+        $$ = abc_setlocal($$, v->index);
+        v->init = do_init_variable($1);
     }
 }
 
 /* ------------ control flow ------------------------- */
 
+IF_CODEBLOCK: {PASS12 new_state();} CODEBLOCK {
+    $$ = var_block($2, state->vars);
+    PASS12 old_state();
+}
 MAYBEELSE:  %prec below_else {$$ = code_new();}
-MAYBEELSE: "else" CODEBLOCK {$$=$2;}
+MAYBEELSE: "else" IF_CODEBLOCK {$$=$2;}
 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
 
-IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
-     
+IF : "if" '(' EXPRESSION ')' IF_CODEBLOCK MAYBEELSE {
     $$ = code_new();
-    $$ = code_append($$, $4.c);
+    $$ = code_append($$, $3.c);
     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
    
-    $$ = code_append($$, $6);
-    if($7) {
+    $$ = code_append($$, $5);
+    if($6) {
         myjmp = $$ = abc_jump($$, 0);
     }
     myif->branch = $$ = abc_nop($$);
-    if($7) {
-        $$ = code_append($$, $7);
+    if($6) {
+        $$ = code_append($$, $6);
         myjmp->branch = $$ = abc_nop($$);
     }
-    $$ = var_block($$);
-    PASS12 old_state();
 }
 
 FOR_INIT : {$$=code_new();}
@@ -2104,8 +2221,8 @@ FOR_INIT : VOIDEXPRESSION
 //       (I don't see any easy way to revolve this conflict otherwise, as we
 //        can't touch VAR_READ without upsetting the precedence about "return")
 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
-    PASS1 $$=$2;new_variable($2,0,1,0);
-    PASS2 $$=$2;new_variable($2,$3,1,0);
+    PASS1 $$=$2;new_variable(state->method, $2,0,1,0);
+    PASS2 $$=$2;new_variable(state->method, $2,$3,1,0);
 }
 FOR_IN_INIT : T_IDENTIFIER {
     PASS12
@@ -2115,7 +2232,7 @@ FOR_IN_INIT : T_IDENTIFIER {
 FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
 FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
 
-FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
+FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' IF_CODEBLOCK {
     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
     $$ = code_new();
     $$ = code_append($$, $2);
@@ -2131,20 +2248,16 @@ FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
     continuejumpsto($$, $1.name, cont);
     myif->branch = out;
 
-    $$ = var_block($$);
+    $$ = var_block($$, state->vars);
     PASS12 old_state();
 }
 
-FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
-    variable_t*var = find_variable(state, $2);
-    if(!var) {
-        syntaxerror("variable %s not known in this scope", $2);
-    }
-
-    char*tmp1name = concat2($2, "__tmp1__");
-    int it = new_variable(tmp1name, TYPE_INT, 0, 0);
-    char*tmp2name = concat2($2, "__array__");
-    int array = new_variable(tmp1name, 0, 0, 0);
+FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' IF_CODEBLOCK {
+    node_t*n = resolve_identifier($2);
+    typedcode_t w = node_write(n);
+    
+    int it = alloc_local();
+    int array = alloc_local();
 
     $$ = code_new();
     $$ = code_append($$, $4.c);
@@ -2163,8 +2276,9 @@ FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' 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);
@@ -2175,46 +2289,39 @@ FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
     
     myif->branch = out;
 
-    $$ = var_block($$);
-
-    free(tmp1name);
-    free(tmp2name);
+    $$ = abc_kill($$, it);
+    $$ = abc_kill($$, array);
 
+    $$ = var_block($$, state->vars);
     PASS12 old_state();
 }
 
-WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
+WHILE : T_WHILE '(' EXPRESSION ')' IF_CODEBLOCK {
 
     $$ = code_new();
 
     code_t*myjmp = $$ = abc_jump($$, 0);
     code_t*loopstart = $$ = abc_label($$);
-    $$ = code_append($$, $6);
+    $$ = code_append($$, $5);
     code_t*cont = $$ = abc_nop($$);
     myjmp->branch = cont;
-    $$ = code_append($$, $4.c);
+    $$ = code_append($$, $3.c);
     $$ = abc_iftrue($$, loopstart);
     code_t*out = $$ = abc_nop($$);
     breakjumpsto($$, $1, out);
     continuejumpsto($$, $1, cont);
-
-    $$ = var_block($$);
-    PASS12 old_state();
 }
 
-DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
+DO_WHILE : T_DO IF_CODEBLOCK "while" '(' EXPRESSION ')' {
     $$ = code_new();
     code_t*loopstart = $$ = abc_label($$);
-    $$ = code_append($$, $3);
+    $$ = code_append($$, $2);
     code_t*cont = $$ = abc_nop($$);
-    $$ = code_append($$, $6.c);
+    $$ = code_append($$, $5.c);
     $$ = abc_iftrue($$, loopstart);
     code_t*out = $$ = abc_nop($$);
     breakjumpsto($$, $1, out);
     continuejumpsto($$, $1, cont);
-    
-    $$ = var_block($$);
-    PASS12 old_state();
 }
 
 BREAK : "break" %prec prec_none {
@@ -2276,7 +2383,7 @@ SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')
         c=c->prev;
     }
    
-    $$ = var_block($$);
+    $$ = var_block($$, state->vars);
     PASS12 old_state();
 }
 
@@ -2284,8 +2391,8 @@ 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($3, 0, 0, 0);
-                                               PASS2 new_variable($3, $4, 0, 0);
+                                               PASS1 new_variable(state->method, $3, $4, 0, 0);
+                                               PASS2 new_variable(state->method, $3, $4, 0, 0);
                                               } 
         '{' MAYBECODE '}' {
     namespace_t name_ns = {ACCESS_PACKAGE, ""};
@@ -2304,11 +2411,11 @@ CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();
     c = code_append(c, $8);
     c = abc_kill(c, i);
 
-    c = var_block(c);
+    c = var_block(c, state->vars);
     PASS12 old_state();
 }
 FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
-    $4 = var_block($4);
+    $4 = var_block($4, state->vars);
     if(!$4) {
         $$=0;
     } else {
@@ -2358,7 +2465,7 @@ TRY : "try" '{' {PASS12 new_state();
   
     int tmp;
     if($6.finally)
-        tmp = new_variable("__finally__", 0, 0, 0);
+        tmp = alloc_local();
     
     abc_exception_list_t*l = $6.l;
     int count=0;
@@ -2386,7 +2493,7 @@ TRY : "try" '{' {PASS12 new_state();
         
     list_concat(state->method->exceptions, $6.l);
    
-    $$ = var_block($$);
+    $$ = var_block($$, state->vars);
     PASS12 old_state();
 }
 
@@ -2437,7 +2544,7 @@ WITH : WITH_HEAD CODEBLOCK {
 X_IDENTIFIER: T_IDENTIFIER
             | "package" {PASS12 $$="package";}
             | "namespace" {PASS12 $$="namespace";}
-            | T_NAMESPACE {PASS12 $$=$1;}
+            | "NaN" {PASS12 $$="NaN";}
 
 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
 PACKAGE: X_IDENTIFIER             {PASS12 $$=strdup($1);}
@@ -2467,18 +2574,27 @@ PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
         free(s);
     }
 };
+
+IMPORT : "import" T_IDENTIFIER {
+       PASS12
+       slotinfo_t*s = registry_find(state->package, $2);
+       if(!s && as3_pass==1) {as3_schedule_class(state->package, $2);}
+       state_has_imports();
+       dict_put(state->imports, state->package, $2);
+       $$=0;
+}
 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);
        }
-       classinfo_t*c = $2;
-       if(!c) 
-            syntaxerror("Couldn't import class\n");
+       /*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, c->name, c);
-       import_toplevel(c->package);
+       dict_put(state->imports, $2->name, $2);
+       import_toplevel($2->package);
        $$=0;
 }
 IMPORT : "import" PACKAGE '.' '*' {
@@ -2516,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;
                        }
 
@@ -2552,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;
@@ -2614,6 +2731,7 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI
         code_t**code=0;
         if(!state->cls) {
             // global variable
+            if(!global->init) global->init = abc_initscript(global->file);
             ns.name = state->package;
             traits = &global->init->traits;
             code = &global->init->method->body->code;
@@ -2656,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) {
@@ -2739,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);
@@ -2752,82 +2869,103 @@ CONSTANT : "null" {$$ = constant_new_null($1);}
 CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
 CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
 
-/*
-CONSTANT : T_IDENTIFIER {
-    if(!strcmp($1, "NaN")) {
-        $$ = constant_new_float(__builtin_nan(""));
-    } else {
-        as3_warning("Couldn't evaluate constant value of %s", $1);
-        $$ = constant_new_null($1);
-    }
-}*/
-
 /* ---------------------------xml ------------------------------ */
 
 %code {
     static int xml_level = 0;
 };
 
-XML: XMLNODE
+XML: XMLNODE {
+   multiname_t m = {QNAME, &stdns, 0, "XML"};
+   typedcode_t v;
+   v.c = 0;
+   v.c = abc_getlex2(v.c, &m);
+   v.c = code_append(v.c, node_read($1).c);
+   v.c = abc_construct(v.c, 1);
+   v.t = TYPE_XML;
+   $$ = mkcodenode(v);
+}
 
 OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
 CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
 CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
 
 XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
-    $$=strdup("{...}");
-    as3_warning("xml string substitution not yet supported");
+    $$ = $2;
 }
 XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
-    $$=strdup("{...}");
-    as3_warning("xml string substitution not yet supported");
+    $$ = $2;
 }
-XMLTEXT : {$$="";}
+XMLTEXT : {$$=mkstringnode("");}
 XMLTEXT : XMLTEXT XMLEXPR1 {
-    $$ = concat2($1, "{...}");
+    $$ = mkaddnode($1,$2);
+}
+XMLTEXT : XMLTEXT T_STRING {
+    char* str = string_cstr(&$2);
+    $$ = mkaddnode($1,mkstringnode(str));
+    free(str);
+}
+XMLTEXT : XMLTEXT '>' {
+    $$ = mkaddnode($1, mkstringnode(">"));
+}
+XML2 : XMLNODE XMLTEXT {
+    $$ = mkaddnode($1,$2);
+}
+XML2 : XML2 XMLNODE XMLTEXT {
+    $$ = mkaddnode($1, mkaddnode($2,$3));
+}
+XML_ID_OR_EXPR: T_IDENTIFIER {
+    $$ = mkstringnode($1);
+}
+XML_ID_OR_EXPR: XMLEXPR2 {
+    $$ = $1;
 }
-XMLTEXT : XMLTEXT T_STRING {$$=concat2($1, string_cstr(&$2));}
-XMLTEXT : XMLTEXT '>' {$$=concat2($1, ">");}
-
-XML2 : XMLNODE XMLTEXT {$$=concat2($1,$2);}
-XML2 : XML2 XMLNODE XMLTEXT {$$=concat3($1,$2,$3);free($1);free($2);free($3);}
-
-XML_ID_OR_EXPR: T_IDENTIFIER {$$=$1;}
-XML_ID_OR_EXPR: XMLEXPR2      {$$=$1;}
 
-XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
-    $$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
-    free($2);free($3);free($5);free($8);
+MAYBE_XMLATTRIBUTES: {
+    $$ = mkstringnode("");
+}
+MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {
+    $$ = mkaddnode(mkstringnode(" "),$1);
 }
+
 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
-    $$ = allocprintf("<%s%s/>", $2, $3);
+    //$$ = allocprintf("<%s%s/>", $2, $3, $5, $8);
+    $$ = mkaddnode(mkaddnode(mkaddnode(mkstringnode("<"),$2),$3),mkstringnode("/>"));
+}
+XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
+    //$$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
+    $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
+         mkstringnode("<"),$2),$3),mkstringnode(">")),$5),mkstringnode("</")),$8),mkstringnode(">"));
 }
 XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
-    $$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
-    free($2);free($3);free($5);free($6);free($9);
+    //$$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
+    $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
+         mkstringnode("<"),$2),$3),mkstringnode(">")),$5),$6),mkstringnode("</")),$9),mkstringnode(">"));
 }
 
-MAYBE_XMLATTRIBUTES:                      {$$=strdup("");}
-MAYBE_XMLATTRIBUTES: XMLATTRIBUTES        {$$=concat2(" ",$1);}
-XMLATTRIBUTES: XMLATTRIBUTE               {$$=$1;}
-XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {$$=concat3($1," ",$2);free($1);free($2);}
-
+XMLATTRIBUTES: XMLATTRIBUTE {
+    $$ = $1;
+}
+XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {
+    $$ = mkaddnode($1, mkaddnode(mkstringnode(" "),$2));
+}
 XMLATTRIBUTE: XMLEXPR2 {
-    $$ = strdup("{...}");
+    $$ = $1;
 }
 XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
     char* str = string_cstr(&$3);
-    $$ = concat2("{...}=",str);
+    $$ = mkaddnode($1, mkstringnode(concat2("=",str)));
+    free(str);
 }
 XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
-    $$ = strdup("{...}={...}");
+    $$ = mkaddnode($1, mkaddnode(mkstringnode("=\""), mkaddnode($3, mkstringnode("\""))));
 }
 XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
-    $$ = concat2($1,"={...}");
+    $$ = mkaddnode(mkaddnode(mkstringnode(concat2($1,"=\"")), $3), mkstringnode("\""));
 }
 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
     char* str = string_cstr(&$3);
-    $$=allocprintf("%s=%s", $1,str);
+    $$=mkstringnode(allocprintf("%s=%s", $1,str));
     free(str);
     free($1);free((char*)$3.str);
 }
@@ -2950,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 {
@@ -2964,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
@@ -3018,6 +3158,9 @@ NEW : "new" E XX MAYBE_PARAM_VALUES {
         $$.c = code_append($$.c, paramcode);
         $$.c = abc_constructprop2($$.c, name, $4.number);
         multiname_destroy(name);
+    } else if(is_getlocal($$.c)) {
+        $$.c = code_append($$.c, paramcode);
+        $$.c = abc_construct($$.c, $4.number);
     } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
         code_free($$.c);
         classinfo_t*c = v.t->data;
@@ -3209,14 +3352,7 @@ E : CONSTANT {
 }
 
 E : XML {
-    typedcode_t v;
-    v.c = 0;
-    multiname_t m = {QNAME, &stdns, 0, "XML"};
-    v.c = abc_getlex2(v.c, &m);
-    v.c = abc_pushstring(v.c, $1);
-    v.c = abc_construct(v.c, 1);
-    v.t = TYPE_XML;
-    $$ = mkcodenode(v);
+    $$ = $1;
 }
 
 /* regexp */
@@ -3295,7 +3431,7 @@ E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
 E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
 E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
 E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
-E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
+E : "typeof" E  {$$ = mknode1(&node_typeof, $2);}
 E : "void" E {$$ = mknode1(&node_void, $2);}
 E : "void" { $$ = mkconstnode(constant_new_undefined());}
 E : '(' COMMA_EXPRESSION ')' { $$=$2;}
@@ -3325,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;
@@ -3389,7 +3525,7 @@ E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
     c = abc_kill(c, result);
     c = abc_kill(c, index);
     
-    c = var_block(c);
+    c = var_block(c, state->vars);
     old_state();
     typedcode_t r;
     r.c = c;
@@ -3399,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);
@@ -3434,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);
@@ -3452,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};
@@ -3459,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);
@@ -3489,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);
@@ -3498,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;
@@ -3506,7 +3670,9 @@ MEMBER : E '.' SUBNODE {
             $$.c = abc_getslot($$.c, f->slot);
         } else {
             if(!f) {
-                as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
+                if(!TYPE_IS_XMLLIST(t)) {
+                    as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
+                }
             }
             MEMBER_MULTINAME(m, f, $3);
             $$.c = abc_getproperty2($$.c, &m);
@@ -3544,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;
@@ -3557,11 +3731,9 @@ 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, name))) {
+        if((v = find_slot(state->method, name))) {
             o.c = abc_getscopeobject(o.c, 1);
             o.c = abc_getslot(o.c, v->index);
             o.t = v->type;
@@ -3570,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);
@@ -3635,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); //?
         }
@@ -3669,9 +3852,7 @@ VAR_READ : T_IDENTIFIER {
        */
 
     if(!find_variable(state, $1)) {
-        if(state->method->inner) {
-            unknown_variable($1);
-        }
+        unknown_variable($1);
         /* 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);
@@ -3717,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);
@@ -3739,12 +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) {
@@ -3757,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;
 }