as3: fixed some reconcile problems
[swftools.git] / lib / as3 / parser.y
index 8342309..4699a90 100644 (file)
@@ -94,6 +94,7 @@ extern int a3_lex();
 %token<token> KW_NAMESPACE "namespace"
 %token<token> KW_PACKAGE "package"
 %token<token> KW_PROTECTED "protected"
+%token<token> KW_ARGUMENTS "arguments"
 %token<token> KW_PUBLIC "public"
 %token<token> KW_PRIVATE "private"
 %token<token> KW_USE "use"
@@ -137,6 +138,7 @@ extern int a3_lex();
 %token<token> KW_NUMBER "Number"
 %token<token> KW_STRING "String"
 %token<token> KW_DEFAULT "default"
+%token<token> KW_DEFAULT_XML "default xml"
 %token<token> KW_DELETE "delete"
 %token<token> KW_IF "if"
 %token<token> KW_ELSE  "else"
@@ -198,7 +200,7 @@ extern int a3_lex();
 %type <node> VAR_READ
 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY 
 %type <value> INNERFUNCTION
-%type <code> USE_NAMESPACE
+%type <code> USE_NAMESPACE DEFAULT_NAMESPACE
 %type <code> FOR_INIT
 %type <code> IMPORT
 %type <classinfo> MAYBETYPE
@@ -215,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
+%type <id> XML XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT XML_ID_OR_EXPR XMLEXPR1 XMLEXPR2
 %type <classinfo> TYPE
 //%type <token> VARIABLE
 %type <value> MEMBER
@@ -257,7 +259,7 @@ extern int a3_lex();
 %left new2
 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
 
-%left T_IDENTIFIER
+%left T_IDENTIFIER "arguments"
 %left above_identifier
 %left below_else
 %nonassoc "else"
@@ -321,11 +323,12 @@ typedef struct _classstate {
     /* class data */
     classinfo_t*info;
     abc_class_t*abc;
-   
+
     methodstate_t*init;
     methodstate_t*static_init;
     //code_t*init;
     //code_t*static_init;
+    parsedclass_t*dependencies;
 
     char has_constructor;
 } classstate_t;
@@ -338,6 +341,7 @@ struct _methodstate {
     char is_constructor;
     char has_super;
     char is_global;
+    char is_static;
     int variable_count;
 
     dict_t*unresolved_variables;
@@ -348,6 +352,8 @@ struct _methodstate {
     dict_t*slots;
     int activation_var;
 
+    int need_arguments;
+
     abc_method_t*abc;
     int var_index; // for inner methods
     int slot_index; // for inner methods
@@ -374,6 +380,7 @@ typedef struct _state {
     
     char has_own_imports;
     char new_vars; // e.g. transition between two functions
+    char xmlfilter; // are we inside a xmlobj..() filter?
   
     classstate_t*cls;   
     methodstate_t*method;
@@ -403,12 +410,19 @@ static state_t* state = 0;
 
 DECLARE_LIST(state);
 
+/* protected handling here is a big hack: we just assume the protectedns
+   is package:class. the correct approach would be to add the proper
+   namespace to all protected members in the registry, even though that
+   would slow down searching */
 #define MEMBER_MULTINAME(m,f,n) \
     multiname_t m;\
     namespace_t m##_ns;\
     if(f) { \
-        if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
+        m##_ns.access = ((slotinfo_t*)(f))->access; \
+        if(m##_ns.access == ACCESS_NAMESPACE) \
             m##_ns.name = ((slotinfo_t*)(f))->package; \
+        else if(m##_ns.access == ACCESS_PROTECTED && (f)->parent) \
+            m##_ns.name = concat3((f)->parent->package,":",(f)->parent->name); \
         else \
             m##_ns.name = ""; \
         m.type = QNAME; \
@@ -435,8 +449,8 @@ DECLARE_LIST(state);
 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
-static namespace_t ns4 = {ACCESS_PACKAGE, ""};
-static namespace_list_t nl4 = {&ns4,0};
+static namespace_t stdns = {ACCESS_PACKAGE, ""};
+static namespace_list_t nl4 = {&stdns,0};
 static namespace_list_t nl3 = {&ns3,&nl4};
 static namespace_list_t nl2 = {&ns2,&nl3};
 static namespace_list_t nl1 = {&ns1,&nl2};
@@ -526,7 +540,7 @@ static void old_state()
 
 static code_t* method_header(methodstate_t*m);
 static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
-static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
+static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0);
 
 
 static char* internal_filename_package = 0;
@@ -558,7 +572,7 @@ void initialize_file(char*filename)
         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
         if(!state->method)
             syntaxerror("internal error: skewed tokencount");
-        function_initvars(state->method, 0, 0, 1);
+        function_initvars(state->method, 0, 0, 0, 1);
         global->init = abc_initscript(global->file);
     }
 }
@@ -651,6 +665,9 @@ static code_t*defaultvalue(code_t*c, classinfo_t*type)
        c = abc_pushnan(c);
     } else if(TYPE_IS_BOOLEAN(type)) {
        c = abc_pushfalse(c);
+    } else if(TYPE_IS_STRING(type)) {
+       c = abc_pushnull(c);
+       c = abc_coerce_s(c);
     } else if(!type) {
        //c = abc_pushundefined(c);
         syntaxerror("internal error: can't generate default value for * type");
@@ -671,8 +688,10 @@ static variable_t* new_variable2(const char*name, classinfo_t*type, char init, c
 {
     if(maybeslot) {
         variable_t*v = find_slot(state, name);
-        if(v)
+        if(v) {
+            alloc_local(); 
             return v;
+        }
     }
 
     NEW(variable_t, v);
@@ -711,17 +730,12 @@ static code_t* var_block(code_t*body)
     code_t*k = 0;
     int t;
     int num=0;
-    for(t=0;t<state->vars->hashsize;t++) {
-        dictentry_t*e = state->vars->slots[t];
-        while(e) {
-            variable_t*v = (variable_t*)e->data;
-            if(v->type && v->init) {
-                c = defaultvalue(c, v->type);
-                c = abc_setlocal(c, v->index);
-                k = abc_kill(k, v->index); 
-                num++;
-            }
-            e = e->next;
+    DICT_ITERATE_DATA(state->vars, variable_t*, v) {
+        if(v->type && v->init) {
+            c = defaultvalue(c, v->type);
+            c = abc_setlocal(c, v->index);
+            k = abc_kill(k, v->index); 
+            num++;
         }
     }
 
@@ -766,8 +780,9 @@ static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
     if(m->uses_slots) {
         /* FIXME: this alloc_local() causes variable indexes to be
            different in pass2 than in pass1 */
-        if(!m->activation_var)
+        if(!m->activation_var) {
             m->activation_var = alloc_local();
+        }
         if(init) {
             c = abc_newactivation(c);
             c = abc_dup(c);
@@ -903,7 +918,22 @@ static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char rec
     return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
 }
 
-static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
+static void innerfunctions2vars(methodstate_t*m)
+{
+    methodstate_list_t*l = m->innerfunctions;
+    while(l) {
+        methodstate_t*m = l->methodstate;
+        
+        variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 0);
+        m->var_index = v->index;
+        if(m->is_a_slot)
+            m->slot_index = m->is_a_slot;
+        v->is_inner_method = m;
+        l = l->next;
+    }
+}
+
+static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
 {
     if(var0) {
         int index = -1;
@@ -916,47 +946,35 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char
         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;
-    }
-
-    if(params) {
+    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);
             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);
+            m->need_arguments = v->index;
+        }
     }
-
-    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;
-    }
+    
+    innerfunctions2vars(m);
     
     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);
+        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);
+                    if(!type || type->kind != INFOTYPE_CLASS) {
+                        syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
+                    }
+                    v->type = type;
                 }
-                v->type = type;
             }
         }
     }
@@ -980,6 +998,9 @@ 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_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
+        syntaxerror("protected and static not supported at the same time.");
+    
     //if(!(mod->flags&FLAG_INTERFACE) && !extends) {
     if(!(mod->flags&FLAG_INTERFACE) && !extends) {
         // all classes extend object
@@ -1004,9 +1025,10 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
         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->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 facat
+           even though it has special meaning. We just rely on the fact
            that pass 1 won't do anything with variables */
         
         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
@@ -1033,12 +1055,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);
        
-        function_initvars(state->cls->init, 0, 0, 1);
-        function_initvars(state->cls->static_init, 0, 0, 0);
+        function_initvars(state->cls->init, 0, 0, 0, 1);
+        function_initvars(state->cls->static_init, 0, 0, 0, 0);
 
         if(extends && (extends->flags & FLAG_FINAL))
             syntaxerror("Can't extend final class '%s'", extends->name);
@@ -1067,17 +1089,13 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
             abc_class_interface(state->cls->abc);
         }
 
-        abc_class_protectedNS(state->cls->abc, classname);
-
         for(mlist=implements;mlist;mlist=mlist->next) {
             MULTINAME(m, mlist->classinfo);
             abc_class_add_interface(state->cls->abc, &m);
         }
 
-        NEW(parsedclass_t,p);
-        p->cls = state->cls->info;
-        p->abc = state->cls->abc;
-        list_append(global->classes, p);
+        state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
+        list_append(global->classes, state->cls->dependencies);
 
         /* flash.display.MovieClip handling */
         if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
@@ -1115,6 +1133,21 @@ static void endclass()
             code_t*c = method_header(state->cls->static_init);
             m->body->code = wrap_function(c, 0, m->body->code);
         }
+      
+        trait_list_t*trait = state->cls->abc->traits;
+        /* switch all protected members to the protected ns of this class */
+        while(trait) {
+            trait_t*t = trait->trait;
+            if(t->name->ns->access == ACCESS_PROTECTED) {
+                if(!state->cls->abc->protectedNS) {
+                    char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
+                    state->cls->abc->protectedNS = namespace_new_protected(n);
+                    state->cls->abc->flags |= CLASS_PROTECTED_NS;
+                }
+                t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
+            }
+            trait = trait->next;
+        }
     }
 
     old_state();
@@ -1278,6 +1311,7 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
     if(as3_pass == 1) {
         state->method = rfx_calloc(sizeof(methodstate_t));
         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));
 
@@ -1292,7 +1326,7 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
 
         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
     
-        function_initvars(state->method, params, 0, 1);
+        function_initvars(state->method, 1, params, 0, 1);
     }
 
     if(as3_pass == 2) {
@@ -1301,7 +1335,7 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
         parserassert(state->method);
 
         state->method->info->return_type = return_type;
-        function_initvars(state->method, params, 0, 1);
+        function_initvars(state->method, 1, params, 0, 1);
     }
 }
 
@@ -1318,6 +1352,7 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
     if(as3_pass == 1) {
         state->method = rfx_calloc(sizeof(methodstate_t));
         state->method->has_super = 0;
+        state->method->is_static = mod->flags&FLAG_STATIC;
 
         if(state->cls) {
             state->method->is_constructor = !strcmp(state->cls->info->name,name);
@@ -1330,7 +1365,7 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
 
         state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
        
-        function_initvars(state->method, params, mod->flags, 1);
+        function_initvars(state->method, 1, params, mod->flags, 1);
         
         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
     }
@@ -1349,7 +1384,7 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
             state->cls->has_constructor |= state->method->is_constructor;
         }
         
-        function_initvars(state->method, params, mod->flags, 1);
+        function_initvars(state->method, 1, params, mod->flags, 1);
     } 
 }
 
@@ -1357,8 +1392,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
                           params_t*params, classinfo_t*return_type, code_t*body)
 {
     if(as3_pass==1) {
-        // store inner methods in variables
-        function_initvars(state->method, 0, 0, 0);
+        innerfunctions2vars(state->method);
 
         methodstate_list_t*ml = state->method->innerfunctions;
         
@@ -1370,23 +1404,16 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
             if(m->unresolved_variables) {
                 dict_t*d = m->unresolved_variables;
                 int t;
-                for(t=0;t<d->hashsize;t++) {
-                    dictentry_t*l = d->slots[t]; 
-                    while(l) {
-                        /* check parent method's variables */
-                        variable_t*v;
-                        if((v=find_variable(state, l->key))) {
-                            m->uses_parent_function = 1;
-                            state->method->uses_slots = 1;
-                            dict_put(xvars, l->key, 0);
-                        }
-                        l = l->next;
+                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(l) break;
                 }
-
-                dict_destroy(m->unresolved_variables);
-                m->unresolved_variables = 0;
+                dict_destroy(m->unresolved_variables);m->unresolved_variables = 0;
             }
             ml = ml->next;
         }
@@ -1398,11 +1425,11 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
                 if(!name) syntaxerror("internal error");
                 if(v->index && dict_contains(xvars, name)) {
                     v->init = 0;
-                    v->index = i++;
+                    v->index = i;
                     if(v->is_inner_method) {
-                        v->is_inner_method->is_a_slot = 1;
+                        v->is_inner_method->is_a_slot = i;
                     }
-                    //v->type = 0;
+                    i++;
                     dict_put(state->method->slots, name, v);
                 }
             }
@@ -1431,13 +1458,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
             f = abc_class_getconstructor(state->cls->abc, type2);
         } else if(!state->method->is_global) {
             namespace_t ns = modifiers2access(mod);
-          
-            /* deal with protected */
-            if(ns.access == ACCESS_PROTECTED && state->cls)
-                ns.name = state->cls->info->name;
-
             multiname_t mname = {QNAME, &ns, 0, name};
-
             if(mod->flags&FLAG_STATIC)
                 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
             else
@@ -1458,6 +1479,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
         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;
+        if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
 
         char opt=0;
         param_list_t*p=0;
@@ -1471,7 +1493,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
                 check_constant_against_type(p->param->type, p->param->value);
                 opt=1;list_append(f->optional_parameters, p->param->value);
             } else if(opt) {
-                syntaxerror("non-optional parameter not allowed after optional parameters");
+                syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
             }
         }
         if(state->method->slots) {
@@ -1534,8 +1556,6 @@ void continuejumpsto(code_t*c, char*name, code_t*jump)
     }
 }
 
-#define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
-
 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
 {
     if(from==to)
@@ -1562,17 +1582,26 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
         return abc_coerce2(c, &m);
     }
 
+    if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
+        return c;
+
     if(TYPE_IS_BOOLEAN(to))
         return abc_convert_b(c);
     if(TYPE_IS_STRING(to))
         return abc_convert_s(c);
     if(TYPE_IS_OBJECT(to))
-        return abc_convert_o(c);
+        return abc_coerce2(c, &m);
+    if(TYPE_IS_OBJECT(from) && TYPE_IS_XMLLIST(to))
+        return abc_coerce2(c, &m);
+    if(TYPE_IS_OBJECT(from) && TYPE_IS_ARRAY(to))
+        return abc_coerce2(c, &m);
 
     classinfo_t*supertype = from;
     while(supertype) {
         if(supertype == to) {
-             // target type is one of from's superclasses
+             /* target type is one of from's superclasses.
+                (not sure we need this coerce - as far as the verifier
+                 is concerned, object==object (i think) */
              return abc_coerce2(c, &m);
         }
         int t=0;
@@ -1598,7 +1627,17 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
 
     return c;
 }
-/* move to ast.c todo end */
+code_t* coerce_to_type(code_t*c, classinfo_t*t)
+{
+    if(!t) {
+        return abc_coerce_a(c);
+    } else if(TYPE_IS_STRING(t)) {
+        return abc_coerce_s(c);
+    } else {
+        MULTINAME(m, t);
+        return abc_coerce2(c, &m);
+    }
+}
 
 char is_pushundefined(code_t*c)
 {
@@ -1685,6 +1724,7 @@ typedcode_t push_class(slotinfo_t*a)
             infotypename(a), a->name, a->package, state->package);
     }
 
+
     if(a->kind != INFOTYPE_CLASS) {
         MULTINAME(m, a);
         x.c = abc_findpropstrict2(x.c, &m);
@@ -1696,9 +1736,16 @@ typedcode_t push_class(slotinfo_t*a)
             varinfo_t*v = (varinfo_t*)a;
             x.t = v->type;
         }
+        return x;
     } else {
+        if(state->cls && state->method == state->cls->static_init) {
+            /* we're in the static initializer. 
+               record the fact that we're using this class here */
+            parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
+        }
         classinfo_t*c = (classinfo_t*)a;
-        if(c->slot) {
+        //if(c->slot) {
+        if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
             x.c = abc_getglobalscope(x.c);
             x.c = abc_getslot(x.c, c->slot);
         } else {
@@ -1890,6 +1937,7 @@ CODE: CODE CODEPIECE {
 CODE: CODEPIECE {$$=$1;}
 
 // code which may appear outside of methods
+CODE_STATEMENT: DEFAULT_NAMESPACE 
 CODE_STATEMENT: IMPORT 
 CODE_STATEMENT: FOR 
 CODE_STATEMENT: FOR_IN 
@@ -1905,7 +1953,7 @@ CODE_STATEMENT: NAMESPACE_DECLARATION
 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
 CODE_STATEMENT: '{' '}' {$$=0;}
 
-// code which may appear in methods
+// code which may appear in methods (includes the above)
 CODEPIECE: ';' {$$=0;}
 CODEPIECE: CODE_STATEMENT
 CODEPIECE: VARIABLE_DECLARATION
@@ -2388,6 +2436,7 @@ WITH : WITH_HEAD CODEBLOCK {
 
 X_IDENTIFIER: T_IDENTIFIER
             | "package" {PASS12 $$="package";}
+            | "namespace" {PASS12 $$="namespace";}
             | T_NAMESPACE {PASS12 $$=$1;}
 
 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
@@ -2539,10 +2588,15 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI
         slotstate_varconst = varconst;
         slotstate_flags = flags;
         if(state->cls) {
-            if(flags && flags->flags&FLAG_STATIC) {
-                state->method = state->cls->static_init;
+            if(flags) {
+                if(flags->flags&FLAG_STATIC) {
+                    state->method = state->cls->static_init;
+                } else {
+                    state->method = state->cls->init;
+                }
             } else {
-                state->method = state->cls->init;
+                // reset to "default" state (all in class code is static by default) */
+                state->method = state->cls->static_init;
             }
         } else {
             parserassert(state->method);
@@ -2552,9 +2606,6 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI
     {
         int flags = modifiers->flags;
         namespace_t ns = modifiers2access(modifiers);
-        /* deal with protected */
-        if(ns.access == ACCESS_PROTECTED && state->cls)
-            ns.name = state->cls->info->name;
 
         /* slot name */
         multiname_t mname = {QNAME, &ns, 0, name};
@@ -2574,11 +2625,15 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI
             // instance variable
             traits = &state->cls->abc->traits;
             code = &state->cls->init->header;
+            
+            if(ns.access == ACCESS_PROTECTED) {
+                ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
+            }
         }
         if(c)
             *c = code;
         if(m) 
-            memcpy(m, &mname, sizeof(multiname_t));
+            *m = *multiname_clone(&mname);
             
         return trait_new_member(traits, 0, multiname_clone(&mname), 0);
     }
@@ -2656,7 +2711,7 @@ PASS12
                 c = code_append(c, v.c);
                 c = converttype(c, v.t, $2);
                 if(!t->slot_id) {
-                    c = abc_setproperty2(c, &mname);
+                    c = abc_initproperty2(c, &mname);
                 } else {
                     c = abc_setslot(c, t->slot_id);
                 }
@@ -2715,36 +2770,64 @@ CONSTANT : T_IDENTIFIER {
 
 XML: XMLNODE
 
-OPEN : '<' {PASS_ALWAYS tokenizer_begin_xml();xml_level++;}
+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");
+}
+XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
+    $$=strdup("{...}");
+    as3_warning("xml string substitution not yet supported");
+}
 XMLTEXT : {$$="";}
+XMLTEXT : XMLTEXT XMLEXPR1 {
+    $$ = concat2($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);}
 
-XMLNODE : OPEN T_IDENTIFIER MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' T_IDENTIFIER CLOSE2 '>' {
+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);
 }
-XMLNODE : OPEN T_IDENTIFIER MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
+XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
     $$ = allocprintf("<%s%s/>", $2, $3);
 }
-XMLNODE : OPEN T_IDENTIFIER MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' T_IDENTIFIER CLOSE2 '>' {
+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($6);free($9);
+    free($2);free($3);free($5);free($6);free($9);
 }
 
 MAYBE_XMLATTRIBUTES:                      {$$=strdup("");}
 MAYBE_XMLATTRIBUTES: XMLATTRIBUTES        {$$=concat2(" ",$1);}
 XMLATTRIBUTES: XMLATTRIBUTE               {$$=$1;}
 XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {$$=concat3($1," ",$2);free($1);free($2);}
+
+XMLATTRIBUTE: XMLEXPR2 {
+    $$ = strdup("{...}");
+}
+XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
+    char* str = string_cstr(&$3);
+    $$ = concat2("{...}=",str);
+}
+XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
+    $$ = strdup("{...}={...}");
+}
+XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
+    $$ = concat2($1,"={...}");
+}
 XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
     char* str = string_cstr(&$3);
-    $$=allocprintf("%s=\"%s\"", $1,str);
+    $$=allocprintf("%s=%s", $1,str);
     free(str);
     free($1);free((char*)$3.str);
 }
@@ -2935,13 +3018,20 @@ NEW : "new" E XX MAYBE_PARAM_VALUES {
         $$.c = code_append($$.c, paramcode);
         $$.c = abc_constructprop2($$.c, name, $4.number);
         multiname_destroy(name);
-    } else if($$.c->opcode == OPCODE_GETSLOT) {
+    } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
+        code_free($$.c);
+        classinfo_t*c = v.t->data;
+        MULTINAME(m, c);
+        $$.c = abc_findpropstrict2(0, &m);
+        $$.c = code_append($$.c, paramcode);
+        $$.c = abc_constructprop2($$.c, &m, $4.number);
+    /*} else if($$.c->opcode == OPCODE_GETSLOT) {
         int slot = (int)(ptroff_t)$$.c->data[0];
         trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
         multiname_t*name = t->name;
         $$.c = code_cutlast($$.c);
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_constructprop2($$.c, name, $4.number);
+        $$.c = abc_constructprop2($$.c, name, $4.number);*/
     } else {
         $$.c = code_append($$.c, paramcode);
         $$.c = abc_construct($$.c, $4.number);
@@ -2976,7 +3066,7 @@ FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
         $$.c = code_append($$.c, paramcode);
         $$.c = abc_callproperty2($$.c, name, $3.number);
         multiname_destroy(name);
-    } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
+/*    } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
         int slot = (int)(ptroff_t)$$.c->data[0];
         trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
         if(t->kind!=TRAIT_METHOD) {
@@ -2986,7 +3076,7 @@ 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.number);
+        $$.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);
@@ -3005,8 +3095,8 @@ FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
         // calling a class is like a typecast
         $$.t = (classinfo_t*)v.t->data;
     } else {
-        $$.c = abc_coerce_a($$.c);
         $$.t = TYPE_ANY;
+        $$.c = abc_coerce_a($$.c);
     }
 }
 
@@ -3088,6 +3178,9 @@ MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
 
 DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
 DICTLH: T_STRING     {$$=abc_pushstring2(0,&$1);}
+DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
+DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
+DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
 
 DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
     $$.cc = 0;
@@ -3118,8 +3211,7 @@ E : CONSTANT {
 E : XML {
     typedcode_t v;
     v.c = 0;
-    namespace_t ns = {ACCESS_PACKAGE, ""};
-    multiname_t m = {QNAME, &ns, 0, "XML"};
+    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);
@@ -3131,8 +3223,7 @@ E : XML {
 E : T_REGEXP {
     typedcode_t v;
     v.c = 0;
-    namespace_t ns = {ACCESS_PACKAGE, ""};
-    multiname_t m = {QNAME, &ns, 0, "RegExp"};
+    multiname_t m = {QNAME, &stdns, 0, "RegExp"};
     if(!$1.options) {
         v.c = abc_getlex2(v.c, &m);
         v.c = abc_pushstring(v.c, $1.pattern);
@@ -3147,6 +3238,16 @@ E : T_REGEXP {
     $$ = mkcodenode(v);
 }
 
+E : KW_ARGUMENTS {
+    PASS1
+    state->method->need_arguments = 1;
+    PASS2
+    typedcode_t v;
+    v.c = abc_getlocal(0, state->method->need_arguments);
+    v.t = TYPE_ARRAY;
+    $$ = mkcodenode(v);
+}
+
 /* array */
 E : '[' MAYBE_EXPRESSION_LIST ']' {
     typedcode_t v;
@@ -3235,24 +3336,79 @@ E : "super" '.' T_IDENTIFIER
            }
 
 E : '@' T_IDENTIFIER {
-    // attribute occuring in .() loops 
-    // TODO
-    $$ = mkdummynode();
-    as3_warning("ignored @ operator");
+    typedcode_t v;
+    multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
+    v.c = abc_getlex2(0, &m);
+    v.t = TYPE_STRING;
+    $$ = mkcodenode(v);
 }
 
-E : E '.' '(' E ')' {
-    // filter 
-    // TODO: this needs to be implemented using a loop
-    $$ = mkdummynode();
-    as3_warning("ignored .() operator");
+E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
+    PASS1 old_state();
+    PASS2
+    typedcode_t v = node_read($1);
+    typedcode_t w = node_read($5);
+    code_t*c = 0;
+    int index = alloc_local();
+    int result = alloc_local();
+    int tmp = alloc_local();
+    int xml = alloc_local();
+    
+    c = code_append(c, v.c);
+    c = abc_checkfilter(c);
+    c = abc_coerce_a(c); //hasnext2 converts to *
+    c = abc_setlocal(c, xml);
+    multiname_t m = {QNAME, &stdns, 0, "XMLList"};
+    c = abc_getlex2(c, &m);
+    c = abc_construct(c, 0);
+    c = abc_setlocal(c, result);
+    c = abc_pushbyte(c, 0);
+    c = abc_setlocal(c, index);
+    code_t*jmp = c = abc_jump(c, 0);
+    code_t*loop = c = abc_label(c);
+    c = abc_getlocal(c, xml);
+    c = abc_getlocal(c, index);
+    c = abc_nextvalue(c);
+    c = abc_dup(c);
+    c = abc_setlocal(c, tmp);
+    c = abc_pushwith(c);
+    c = code_append(c, w.c);
+    c = abc_popscope(c);
+    code_t*b = c = abc_iffalse(c, 0);
+    c = abc_getlocal(c, result);
+    c = abc_getlocal(c, index);
+    c = abc_getlocal(c, tmp);
+    multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
+    c = abc_setproperty2(c, &m2);
+    c = b->branch = jmp->branch = abc_nop(c);
+    c = abc_kill(c, tmp);
+    c = abc_hasnext2(c, xml, index);
+    c = abc_iftrue(c, loop);
+    c = abc_getlocal(c, result);
+    c = abc_kill(c, xml);
+    c = abc_kill(c, result);
+    c = abc_kill(c, index);
+    
+    c = var_block(c);
+    old_state();
+    typedcode_t r;
+    r.c = c;
+    r.t = TYPE_XMLLIST;
+    $$ = mkcodenode(r);
 }
 
 ID_OR_NS : T_IDENTIFIER {$$=$1;}
+ID_OR_NS : '*' {$$="*";}
 ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
-SUBNODE: T_IDENTIFIER
+SUBNODE: X_IDENTIFIER
        | '*' {$$="*";}
 
+/*
+MAYBE_NS: T_IDENTIFIER "::" {$$=$1;}
+        | T_NAMESPACE "::" {$$=(char*)$1;}
+        | '*' "::" {$$="*";}
+        | {$$=0;}*/
+
 E : E '.' ID_OR_NS "::" SUBNODE {
     typedcode_t v = node_read($1);
     typedcode_t w = node_read(resolve_identifier($3));
@@ -3379,7 +3535,7 @@ MEMBER : E '.' SUBNODE {
         /* 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);
+        as3_softwarning("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);
@@ -3412,10 +3568,11 @@ MEMBER : E '.' SUBNODE {
             return mkcodenode(o);
         }
 
-        int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
+        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)))
         {
@@ -3455,8 +3612,7 @@ MEMBER : E '.' SUBNODE {
                     o.c = abc_getslot(o.c, f->slot);
                     return mkcodenode(o);
                 } else {
-                    namespace_t ns = {f->access, f->package};
-                    multiname_t m = {QNAME, &ns, 0, name};
+                    MEMBER_MULTINAME(m, f, name);
                     o.c = abc_getlocal_0(o.c);
                     o.c = abc_getproperty2(o.c, &m);
                     return mkcodenode(o);
@@ -3465,14 +3621,20 @@ MEMBER : E '.' SUBNODE {
         } 
         
         /* look at actual classes, in the current package and imported */
-        if((a = find_class(name))) {
-            o = push_class(a);
+        if(!state->xmlfilter && (a = find_class(name))) {
+            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);
+            } else {
+                o = push_class(a);
+            }
             return mkcodenode(o);
         }
 
         /* look through package prefixes */
-        if(dict_contains(state->import_toplevel_packages, name) || 
-           registry_ispackage(name)) {
+        if(!state->xmlfilter && 
+           (dict_contains(state->import_toplevel_packages, name) || 
+            registry_ispackage(name))) {
             o.c = abc___pushpackage__(o.c, name);
             o.t = 0;
             return mkcodenode(o); //?
@@ -3480,8 +3642,10 @@ MEMBER : E '.' SUBNODE {
 
         /* unknown object, let the avm2 resolve it */
         if(1) {
-            //as3_softwarning("Couldn't resolve '%s', doing late binding", name);
-            as3_warning("Couldn't resolve '%s', doing late binding", name);
+            if(!state->method->inner && !state->xmlfilter) {
+                /* we really should make inner functions aware of the class context */
+                as3_warning("Couldn't resolve '%s', doing late binding", name);
+            }
             state->method->late_binding = 1;
                     
             multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
@@ -3503,6 +3667,7 @@ VAR_READ : T_IDENTIFIER {
        etc. which is *correct* because local variables of the parent function
        would shadow those.
        */
+
     if(!find_variable(state, $1)) {
         if(state->method->inner) {
             unknown_variable($1);
@@ -3572,6 +3737,11 @@ NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
     $$=0;
 }
 
+DEFAULT_NAMESPACE : "default xml" "namespace" '=' E 
+{
+    as3_warning("default xml namespaces not supported yet");
+}
+
 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
     PASS12
     const char*url = $3->name;