implemented asset resolving
[swftools.git] / lib / as3 / parser.y
index a81e4e0..b181866 100644 (file)
@@ -1,4 +1,4 @@
-/* parser.lex
+/* parser.y
 
    Routines for compiling Flash2 AVM2 ABC Actionscript
 
 #include "abc.h"
 #include "pool.h"
 #include "files.h"
+#include "common.h"
 #include "tokenizer.h"
 #include "registry.h"
 #include "code.h"
 #include "opcodes.h"
 #include "compiler.h"
+#include "expr.h"
+#include "initcode.h"
 
 extern int a3_lex();
 
@@ -66,6 +69,7 @@ extern int a3_lex();
     regexp_t regexp;
     modifiers_t flags;
     namespace_decl_t* namespace_decl;
+    node_t*node;
     struct {
         abc_exception_list_t *l;
         code_t*finally;
@@ -73,14 +77,12 @@ 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
 %token<number_int> T_INT
 %token<number_uint> T_UINT
-%token<number_uint> T_BYTE
-%token<number_uint> T_SHORT
 %token<number_float> T_FLOAT
 
 %token<id> T_FOR "for"
@@ -92,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"
@@ -101,6 +104,7 @@ extern int a3_lex();
 %token<token> KW_FUNCTION "function"
 %token<token> KW_FINALLY "finally"
 %token<token> KW_UNDEFINED "undefined"
+%token<token> KW_NAN "NaN"
 %token<token> KW_CONTINUE "continue"
 %token<token> KW_CLASS "class"
 %token<token> KW_CONST "const"
@@ -134,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"
@@ -153,6 +158,7 @@ extern int a3_lex();
 %token<token> T_DIVBY "/=" 
 %token<token> T_MODBY "%="
 %token<token> T_MULBY "*="
+%token<token> T_ANDBY "&="
 %token<token> T_PLUSBY "+=" 
 %token<token> T_MINUSBY "-="
 %token<token> T_XORBY "^="
@@ -170,13 +176,14 @@ extern int a3_lex();
 %token<token> T_USHR ">>>"
 %token<token> T_SHR ">>"
 
+%type <number_int> CONDITIONAL_COMPILATION EMBED_START
 %type <for_start> FOR_START
-%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
+%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
@@ -187,12 +194,13 @@ extern int a3_lex();
 %type <code> INTERFACE_DECLARATION
 %type <code> VOIDEXPRESSION
 %type <value> EXPRESSION NONCOMMAEXPRESSION
-%type <value> MAYBEEXPRESSION
-%type <value> E DELETE
-%type <value> CONSTANT
+%type <node> MAYBEEXPRESSION
+%type <value> DELETE
+%type <node> E COMMA_EXPRESSION
+%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
@@ -203,21 +211,22 @@ extern int a3_lex();
 %type <flags> MAYBE_MODIFIERS
 %type <flags> MODIFIER_LIST
 %type <flags> MODIFIER
-%type <constant> STATICCONSTANT MAYBESTATICCONSTANT
+%type <constant> CONSTANT MAYBECONSTANT
 %type <classinfo_list> IMPLEMENTS_LIST
 %type <classinfo> EXTENDS CLASS_SPEC
 %type <classinfo_list> EXTENDS_LIST
-
 %type <classinfo> CLASS PACKAGEANDCLASS
 %type <classinfo_list> CLASS_SPEC_LIST
-
+%type <node>  XMLEXPR1 XMLEXPR2 XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT XML_ID_OR_EXPR XML
 %type <classinfo> TYPE
 //%type <token> VARIABLE
-%type <value> VAR_READ
+%type <value> MEMBER
 %type <value> NEW
 //%type <token> T_IDENTIFIER
 %type <value> FUNCTIONCALL
-%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST WITH_HEAD
+%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES 
+%type <value_list> MAYBE_DICT_EXPRPAIR_LIST DICT_EXPRPAIR_LIST WITH_HEAD
+%type <code> DICTLH
 
 // precedence: from low to high
 
@@ -236,6 +245,7 @@ extern int a3_lex();
 %nonassoc '&'
 %nonassoc "==" "!=" "===" "!=="
 %nonassoc "is" "as" "in"
+%left below_lt
 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
 %left "<<" ">>" ">>>" 
 %left below_minus
@@ -249,18 +259,17 @@ extern int a3_lex();
 %left new2
 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
 
-%left T_IDENTIFIER
+%left T_IDENTIFIER "arguments"
 %left above_identifier
 %left below_else
 %nonassoc "else"
 
 // needed for "return" precedence:
 %nonassoc T_STRING T_REGEXP
-%nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
+%nonassoc T_INT T_UINT T_FLOAT KW_NAN 
 %nonassoc "false" "true" "null" "undefined" "super" "function"
 %left above_function
 
-
      
 %{
 
@@ -270,6 +279,13 @@ static int a3_error(char*s)
    return 0; //make gcc happy
 }
 
+static void parsererror(const char*file, int line, const char*f)
+{
+    syntaxerror("internal error in %s, %s:%d", f, file, line);
+}
+
+#define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
+
 
 static char* concat2(const char* t1, const char* t2)
 {
@@ -297,7 +313,6 @@ static char* concat3(const char* t1, const char* t2, const char* t3)
 typedef struct _import {
     char*package;
 } import_t;
-
 DECLARE_LIST(import);
 
 DECLARE(methodstate);
@@ -307,11 +322,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;
@@ -324,14 +340,20 @@ struct _methodstate {
     char is_constructor;
     char has_super;
     char is_global;
+    char is_static;
     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;
+
+    int need_arguments;
 
     abc_method_t*abc;
     int var_index; // for inner methods
@@ -346,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;
@@ -354,9 +393,13 @@ typedef struct _state {
     import_list_t*wildcard_imports;
     dict_t*import_toplevel_packages;
     dict_t*imports;
+
+    dict_t*namespaces;
+    namespace_list_t*active_namespace_urls;
     
     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;
@@ -370,7 +413,12 @@ typedef struct _state {
 
 typedef struct _global {
     abc_file_t*file;
-    abc_script_t*init;
+
+    parsedclass_list_t*classes;
+    abc_script_t*classinit;
+
+    abc_script_t*init; //package-level code
+
     dict_t*token2info;
     dict_t*file2token2info;
 } global_t;
@@ -380,18 +428,19 @@ static state_t* state = 0;
 
 DECLARE_LIST(state);
 
-#define MULTINAME(m,x) \
-    multiname_t m;\
-    namespace_t m##_ns;\
-    (x)->package; \
-    registry_fill_multiname(&m, &m##_ns, (slotinfo_t*)(x));
-                    
+/* 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; \
@@ -418,13 +467,22 @@ 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};
 static namespace_set_t nopackage_namespace_set = {&nl1};
 
+static dict_t*definitions=0;
+void as3_set_define(const char*c)
+{
+    if(!definitions) 
+        definitions = dict_new();
+    if(!dict_contains(definitions,c))
+        dict_put(definitions,c,0);
+}
+
 static void new_state()
 {
     NEW(state_t, s);
@@ -444,25 +502,10 @@ static void new_state()
     state->old = oldstate;
     state->new_vars = 0;
 
-    trie_remember(active_namespaces);
-}
-static void state_has_imports()
-{
-    state->wildcard_imports = list_clone(state->wildcard_imports);
-    state->imports = dict_clone(state->imports);
-    state->has_own_imports = 1;
-}
-static void import_toplevel(const char*package)
-{
-    char* s = strdup(package);
-    while(1) {
-        dict_put(state->import_toplevel_packages, s, 0);
-        char*x = strrchr(s, '.');
-        if(!x)
-            break;
-        *x = 0;
-    }
-    free(s);
+    state->namespaces = dict_new();
+   
+    if(oldstate)
+        state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
 }
 
 static void state_destroy(state_t*state)
@@ -475,24 +518,17 @@ static void state_destroy(state_t*state)
         dict_destroy(state->imports);state->imports=0;
     }
     if(state->vars) {
-        int t;
-        for(t=0;t<state->vars->hashsize;t++) {
-            dictentry_t*e =state->vars->slots[t];
-            while(e) {
-                free(e->data);e->data=0;
-                e = e->next;
-            }
-        }
         dict_destroy(state->vars);state->vars=0;
     }
     
+    list_free(state->active_namespace_urls)
+    state->active_namespace_urls = 0;
+    
     free(state);
 }
 
 static void old_state()
 {
-    trie_rollback(active_namespaces);
-
     if(!state || !state->old)
         syntaxerror("invalid nesting");
     state_t*leaving = state;
@@ -500,20 +536,19 @@ 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);
         leaving->cls=0;
     }
-    
+
     state_destroy(leaving);
 }
 
 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;
@@ -523,8 +558,6 @@ 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);
     
@@ -540,10 +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);
-        function_initvars(state->method, 0, 0, 1);
-        global->init = abc_initscript(global->file);
+        state->method->variable_count = 0;
+        if(!state->method)
+            syntaxerror("internal error: skewed tokencount");
+        function_initvars(state->method, 0, 0, 0, 1);
+        global->init = 0;
     }
 }
 
@@ -552,12 +589,16 @@ void finish_file()
     if(!state || state->level!=1) {
         syntaxerror("unexpected end of file in pass %d", as3_pass);
     }
-
+    
     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 = 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
@@ -571,69 +612,48 @@ void initialize_parser()
     global->file->flags &= ~ABCFILE_LAZY;
     global->file2token2info = dict_new();
     global->token2info = 0;
+    global->classinit = abc_initscript(global->file);
 }
 
 void* finish_parser()
 {
     dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
-
     global->token2info=0;
-
-    return global->file;
-}
-
-
-static void xx_scopetest() 
-{
-    /* findpropstrict doesn't just return a scope object- it
-       also makes it "active" somehow. Push local_0 on the
-       scope stack and read it back with findpropstrict, it'll
-       contain properties like "trace". Trying to find the same
-       property on a "vanilla" local_0 yields only a "undefined" */
-    //c = abc_findpropstrict(c, "[package]::trace");
     
-    /*c = abc_getlocal_0(c);
-    c = abc_findpropstrict(c, "[package]::trace");
-    c = abc_coerce_a(c);
-    c = abc_setlocal_1(c);
+    initcode_add_classlist(global->classinit, global->classes);
 
-    c = abc_pushbyte(c, 0);
-    c = abc_setlocal_2(c);
-   
-    code_t*xx = c = abc_label(c);
-    c = abc_findpropstrict(c, "[package]::trace");
-    c = abc_pushstring(c, "prop:");
-    c = abc_hasnext2(c, 1, 2);
-    c = abc_dup(c);
-    c = abc_setlocal_3(c);
-    c = abc_callpropvoid(c, "[package]::trace", 2);
-    c = abc_getlocal_3(c);
-    c = abc_kill(c, 3);
-    c = abc_iftrue(c,xx);*/
+    return global->file;
 }
 
 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)
 {
-    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 0;
 }
-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;
 }
 
@@ -644,66 +664,110 @@ static variable_t* find_variable_safe(state_t*s, char*name)
         syntaxerror("undefined variable: %s", name);
     return v;
 }
+
 static char variable_exists(char*name) 
 {
     return dict_contains(state->vars, name);
 }
-code_t*defaultvalue(code_t*c, classinfo_t*type);
+
+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)) {
+       c = abc_pushuint(c, 0);
+    } else if(TYPE_IS_FLOAT(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");
+    } else {
+       c = abc_pushnull(c);
+       MULTINAME(m, type);
+       c = abc_coerce2(c, &m);
+    }
+    return c;
+}
 
 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);
-        if(v)
+        variable_t*v = find_slot(method, name);
+        if(v) {
+            alloc_local(); 
             return v;
+        }
     }
 
     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);
+    if(name) {
+        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__"
-static int gettempvar()
+int gettempvar()
 {
     variable_t*v = find_variable(state, TEMPVARNAME);
+    int i;
     if(v) 
-        return v->index;
-    return new_variable(TEMPVARNAME, 0, 0, 0);
+        i = v->index;
+    else
+        i = new_variable(state->method, TEMPVARNAME, 0, 0, 0);
+    parserassert(i);
+    return i;
 }
 
-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;
-    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(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); 
         }
     }
 
@@ -731,7 +795,7 @@ code_t* var_block(code_t*body)
     return c;
 }
 
-void unknown_variable(char*name) 
+static void unknown_variable(char*name) 
 {
     if(!state->method->unresolved_variables)
         state->method->unresolved_variables = dict_new();
@@ -739,25 +803,27 @@ void unknown_variable(char*name)
         dict_put(state->method->unresolved_variables, name, 0);
 }
 
-#define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
-
-static void parsererror(const char*file, int line, const char*f)
-{
-    syntaxerror("internal error in %s, %s:%d", f, file, line);
-}
-
-   
-static code_t* add_scope_code(code_t*c, methodstate_t*m)
+static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
 {
-    if(m->uses_slots || (m->late_binding && !m->inner)) {
+    if(m->uses_slots || m->innerfunctions || (m->late_binding && !m->inner)) {
         c = abc_getlocal_0(c);
         c = abc_pushscope(c);
     }
     if(m->uses_slots) {
-        /* FIXME: does this need to be the same activation object as
-                  in the function header? */
-        c = abc_newactivation(c);
-        c = abc_pushscope(c);
+        /* FIXME: this alloc_local() causes variable indexes to be
+           different in pass2 than in pass1 */
+        if(!m->activation_var) {
+            m->activation_var = alloc_local();
+        }
+        if(init) {
+            c = abc_newactivation(c);
+            c = abc_dup(c);
+            c = abc_pushscope(c);
+            c = abc_setlocal(c, m->activation_var);
+        } else {
+            c = abc_getlocal(c, m->activation_var);
+            c = abc_pushscope(c);
+        }
     }
     return c;
 }
@@ -766,7 +832,7 @@ static code_t* method_header(methodstate_t*m)
 {
     code_t*c = 0;
 
-    c = add_scope_code(c, m);
+    c = add_scope_code(c, m, 1);
 
     methodstate_list_t*l = m->innerfunctions;
     while(l) {
@@ -793,6 +859,19 @@ static code_t* method_header(methodstate_t*m)
         c = abc_getlocal_0(c);
         c = abc_constructsuper(c, 0);
     }
+
+    if(m->slots) {
+        /* all parameters that are used by inner functions
+           need to be copied from local to slot */
+        parserassert(m->activation_var);
+        DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
+            if(v->is_parameter) {
+                c = abc_getlocal(c, m->activation_var); 
+                c = abc_getlocal(c, v->index); 
+                c = abc_setslot(c, v->index); 
+            }
+        }
+    }
     list_free(m->innerfunctions);
     m->innerfunctions = 0;
     return c;
@@ -802,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)) {
@@ -811,20 +890,15 @@ static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
     return c;
 }
 
-
 static void startpackage(char*name)
 {
     new_state();
-    /*printf("entering package \"%s\"\n", name);*/
     state->package = strdup(name);
 }
 static void endpackage()
 {
-    /*printf("leaving package \"%s\"\n", state->package);*/
-
     //used e.g. in classinfo_register:
     //free(state->package);state->package=0;
-
     old_state();
 }
 
@@ -834,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;
@@ -843,13 +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 */
-            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)) 
@@ -868,70 +966,86 @@ static namespace_t modifiers2access(modifiers_t*mod)
     }
     return ns;
 }
-static slotinfo_t* find_class(const char*name);
 
-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, is_static);
+}
+
+static void innerfunctions2vars(methodstate_t*m)
 {
-    /* FIXME- we need to loop through namespaces here */
-    return registry_findmember(cls, "", name, recurse);
+    methodstate_list_t*l = m->innerfunctions;
+    while(l) {
+        methodstate_t*m = l->methodstate;
+        
+        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;
+        v->is_inner_method = m;
+        l = l->next;
+    }
 }
 
-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)
 {
     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);
-        if(index)
-            *(int*)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(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) {
-            new_variable(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(m, "arguments", TYPE_ARRAY, 0, 0);
+            m->need_arguments = v->index;
         }
     }
-
-    if(as3_pass==2) {
-        m->scope_code = add_scope_code(m->scope_code, m);
-    }
-
     
-    methodstate_list_t*l = m->innerfunctions;
-    while(l) {
-        methodstate_t*m = l->methodstate;
-        
-        variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
-        m->var_index = v->index;
-        m->slot_index = v->index;
-        v->is_inner_method = m;
-
-        l = l->next;
-    }
+    innerfunctions2vars(m);
     
-    if(as3_pass==2 && m->slots) {
-        /* exchange unresolved identifiers with the actual objects */
-        DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
-            if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
-                v->type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
-                if(!v->type || v->type->kind != INFOTYPE_CLASS) {
-                    syntaxerror("Couldn't find class %s", v->type->name);
+    if(as3_pass==2) {
+        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*, 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)", v1->type->package, v1->type->name, name);
+                    }
+                    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;
+                }
+           }
         }
     }
 }
@@ -954,6 +1068,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
@@ -976,10 +1093,11 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
 
     if(as3_pass==1) {
         state->cls = rfx_calloc(sizeof(classstate_t));
-        state->cls->init = rfx_calloc(sizeof(methodstate_t));
-        state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
+        state->cls->init = methodstate_new();
+        state->cls->static_init = methodstate_new();
+        state->cls->static_init->is_static=FLAG_STATIC;
         /* notice: we make no effort to initialize the top variable (local0) here,
-           even though it has special meaning. We just rely on the 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);
@@ -995,6 +1113,7 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
         int num_interfaces = (list_length(implements));
         state->cls->info = classinfo_register(access, package, classname, num_interfaces);
         state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
+        state->cls->info->superclass = extends;
         
         int pos = 0;
         classinfo_list_t*l = implements;
@@ -1005,12 +1124,14 @@ 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);
+        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))
             syntaxerror("Can't extend final class '%s'", extends->name);
@@ -1023,79 +1144,31 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
             pos++;
         }
 
-        /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
-        state->cls->info->superclass = extends;
-
         /* generate the abc code for this class */
         MULTINAME(classname2,state->cls->info);
         multiname_t*extends2 = sig2mname(extends);
 
-        state->cls->abc = abc_class_new(global->file, &classname2, extends2);
+        /* don't add the class to the class index just yet- that will be done later
+           by initscript */
+        state->cls->abc = abc_class_new(0, &classname2, extends2);
+        state->cls->abc->file = global->file;
+
+        multiname_destroy(extends2);
         if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
         if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
         if(state->cls->info->flags&FLAG_INTERFACE) {
             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);
         }
 
-        /* write the construction code for this class to the global init
-           function */
-        int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
-
-        abc_method_body_t*m = global->init->method->body;
-        __ getglobalscope(m);
-        classinfo_t*s = extends;
-
-        int count=0;
-        
-        while(s) {
-            //TODO: take a look at the current scope stack, maybe 
-            //      we can re-use something
-            s = s->superclass;
-            if(!s) 
-            break;
-           
-            multiname_t*s2 = sig2mname(s);
-            __ getlex2(m, s2);
-            multiname_destroy(s2);
-
-            __ pushscope(m); count++;
-            m->code = m->code->prev->prev; // invert
-        }
-        /* continue appending after last op end */
-        while(m->code && m->code->next) m->code = m->code->next; 
-
-        /* TODO: if this is one of *our* classes, we can also 
-                 do a getglobalscope/getslot <nr> (which references
-                 the init function's slots) */
-        if(extends2) {
-            __ getlex2(m, extends2);
-            __ dup(m);
-            /* notice: we get a Verify Error #1107 if the top elemnt on the scope
-               stack is not the superclass */
-            __ pushscope(m);count++;
-        } else {
-            __ pushnull(m);
-            /* notice: we get a verify error #1107 if the top element on the scope 
-               stack is not the global object */
-            __ getlocal_0(m);
-            __ pushscope(m);count++;
-        }
-        __ newclass(m,state->cls->abc);
-        while(count--) {
-            __ popscope(m);
-        }
-        __ setslot(m, slotindex);
-        multiname_destroy(extends2);
+        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)) {
             if(state->package && state->package[0]) {
                 as3_globalclass = concat3(state->package, ".", classname);
@@ -1106,23 +1179,6 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
     }
 }
 
-static int slotstate_varconst = 0;
-static modifiers_t*slotstate_flags = 0;
-static void setslotstate(modifiers_t* flags, int varconst)
-{
-    slotstate_varconst = varconst;
-    slotstate_flags = flags;
-    if(state->cls) {
-        if(flags && flags->flags&FLAG_STATIC) {
-            state->method = state->cls->static_init;
-        } else {
-            state->method = state->cls->init;
-        }
-    } else {
-        parserassert(state->method);
-    }
-}
-
 static void endclass()
 {
     if(as3_pass == 2) {
@@ -1148,6 +1204,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();
@@ -1164,6 +1235,12 @@ void check_code_for_break(code_t*c)
             char*name = string_cstr(c->data[0]);
             syntaxerror("Unresolved \"continue %s\"", name);
         }
+        if(c->opcode == OPCODE___RETHROW__) {
+            syntaxerror("Unresolved \"rethrow\"");
+        }
+        if(c->opcode == OPCODE___FALLTHROUGH__) {
+            syntaxerror("Unresolved \"fallthrough\"");
+        }
         if(c->opcode == OPCODE___PUSHPACKAGE__) {
             char*name = string_cstr(c->data[0]);
             syntaxerror("Can't reference a package (%s) as such", name);
@@ -1172,10 +1249,8 @@ void check_code_for_break(code_t*c)
     }
 }
 
-
 static void check_constant_against_type(classinfo_t*t, constant_t*c)
 {
-    return;
 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
    if(TYPE_IS_NUMBER(t)) {
         xassert(c->type == CONSTANT_FLOAT
@@ -1196,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);
@@ -1229,18 +1304,15 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c
     if(!state->cls) {
         //package method
         minfo = methodinfo_register_global(ns.access, state->package, name);
-        minfo->return_type = 0; // save this for pass 2
+        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) {
-            printf("%s.%s | %s.%s\n", 
-                m->package, m->name,
-                ns.name, name);
             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->return_type = 0; // save this for pass 2 
+        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
         //state->minfo->slot = state->method->abc->method->trait->slot_id;
@@ -1255,9 +1327,9 @@ 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_SLOT)
+            if(minfo->kind!=INFOTYPE_VAR)
                 syntaxerror("class already contains a method called '%s'", name);
             if(!(minfo->subtype & (SUBTYPE_GETSET)))
                 syntaxerror("class already contains a field called '%s'", name);
@@ -1277,11 +1349,12 @@ 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->kind = INFOTYPE_SLOT; //hack
+            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 = 0;
+            minfo->return_type = type;
         }
+
         /* can't assign a slot as getter and setter might have different slots */
         //minfo->slot = slot;
     }
@@ -1297,19 +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;
    
     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;
@@ -1322,7 +1403,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) {
@@ -1331,7 +1412,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);
     }
 }
 
@@ -1343,10 +1424,11 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
     }
     new_state();
     state->new_vars = 1;
-    
+
     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;
 
         if(state->cls) {
             state->method->is_constructor = !strcmp(state->cls->info->name,name);
@@ -1359,7 +1441,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);
     }
@@ -1370,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);
         }
             
@@ -1378,66 +1460,75 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
             state->cls->has_constructor |= state->method->is_constructor;
         }
         
-        state->method->info->return_type = return_type;
-        function_initvars(state->method, params, mod->flags, 1);
+        function_initvars(state->method, 1, params, mod->flags, 1);
     } 
 }
 
+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) {
-        // store inner methods in variables
-        function_initvars(state->method, 0, 0, 0);
-
-        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;
-                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;
+        
+        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);
                     }
-                    if(l) break;
                 }
-
-                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->index = i++;
+                    v->init = v->kill = 0;
+                    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);
                 }
             }
             state->method->uses_slots = i;
             dict_destroy(state->vars);state->vars = 0;
+            parserassert(state->new_vars);
         }
         old_state();
         return 0;
@@ -1458,9 +1549,8 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
         } else if(state->method->is_constructor) {
             f = abc_class_getconstructor(state->cls->abc, type2);
         } else if(!state->method->is_global) {
-            namespace_t mname_ns = modifiers2access(mod);
-            multiname_t mname = {QNAME, &mname_ns, 0, name};
-
+            namespace_t ns = modifiers2access(mod);
+            multiname_t mname = {QNAME, &ns, 0, name};
             if(mod->flags&FLAG_STATIC)
                 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
             else
@@ -1471,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;
         }
@@ -1481,6 +1572,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;
@@ -1494,7 +1586,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) {
@@ -1530,11 +1622,6 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
     return 0;
 }
 
-char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
-{
-    return 1; // FIXME
-}
-
 void breakjumpsto(code_t*c, char*name, code_t*jump) 
 {
     while(c) {
@@ -1562,29 +1649,6 @@ void continuejumpsto(code_t*c, char*name, code_t*jump)
     }
 }
 
-#define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
-#define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
-#define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
-
-classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
-{
-    if(!type1 || !type2) 
-        return registry_getanytype();
-    if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
-        return registry_getanytype();
-
-    if(op=='+') {
-        if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
-            return TYPE_NUMBER;
-        } else {
-            return TYPE_ANY;
-        }
-    }
-
-    if(type1 == type2)
-        return type1;
-    return registry_getanytype();
-}
 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
 {
     if(from==to)
@@ -1602,15 +1666,35 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
     if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
        (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
         // allow conversion between number types
+        if(TYPE_IS_UINT(to))
+            return abc_convert_u(c);
+        else if(TYPE_IS_INT(to))
+            return abc_convert_i(c);
+        else if(TYPE_IS_NUMBER(to))
+            return abc_convert_d(c);
         return abc_coerce2(c, &m);
     }
-    //printf("%s.%s\n", from.package, from.name);
-    //printf("%s.%s\n", to.package, to.name);
+
+    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_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;
@@ -1630,33 +1714,26 @@ 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?".":"", from->name, 
-        to->package, to->package?".":"", to->name);
+        from->package, from->package[0]?".":"", from->name, 
+        to->package, to->package[0]?".":"", to->name);
+
     return c;
 }
+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);
+    }
+}
 
-code_t*defaultvalue(code_t*c, classinfo_t*type)
-{
-    if(TYPE_IS_INT(type)) {
-       c = abc_pushbyte(c, 0);
-    } else if(TYPE_IS_UINT(type)) {
-       c = abc_pushuint(c, 0);
-    } else if(TYPE_IS_FLOAT(type)) {
-       c = abc_pushnan(c);
-    } else if(TYPE_IS_BOOLEAN(type)) {
-       c = abc_pushfalse(c);
-    } else if(!type) {
-       //c = abc_pushundefined(c);
-    } else {
-       c = abc_pushnull(c);
-       MULTINAME(m, type);
-       c = abc_coerce2(c, &m);
-    }
-    return c;
-}
-
-char is_pushundefined(code_t*c)
+char is_pushundefined(code_t*c)
 {
     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
 }
@@ -1741,6 +1818,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);
@@ -1752,9 +1830,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 {
@@ -1766,175 +1851,6 @@ typedcode_t push_class(slotinfo_t*a)
     return x;
 }
 
-static char is_getlocal(code_t*c)
-{
-    if(!c || c->prev || c->next)
-        return 0;
-    return(c->opcode == OPCODE_GETLOCAL
-        || c->opcode == OPCODE_GETLOCAL_0
-        || c->opcode == OPCODE_GETLOCAL_1
-        || c->opcode == OPCODE_GETLOCAL_2
-        || c->opcode == OPCODE_GETLOCAL_3);
-}
-static int getlocalnr(code_t*c)
-{
-    if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
-    else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
-    else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
-    else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
-    else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
-    else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
-    return 0;
-}
-
-static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
-{
-    /* converts this:
-
-       [prefix code] [read instruction]
-
-       to this:
-
-       [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
-    */
-    if(in && in->opcode == OPCODE_COERCE_A) {
-        in = code_cutlast(in);
-    }
-    if(in->next)
-        syntaxerror("internal error");
-
-    /* chop off read instruction */
-    code_t*prefix = in;
-    code_t*r = in;
-    if(r->prev) {
-        prefix = r->prev;r->prev = 0;
-        prefix->next=0;
-    } else {
-        prefix = 0;
-    }
-        
-    char use_temp_var = readbefore;
-
-    /* generate the write instruction, and maybe append a dup to the prefix code */
-    code_t* write = abc_nop(0);
-    if(r->opcode == OPCODE_GETPROPERTY) {
-        write->opcode = OPCODE_SETPROPERTY;
-        multiname_t*m = (multiname_t*)r->data[0];
-        write->data[0] = multiname_clone(m);
-        if(m->type == QNAME || m->type == MULTINAME) {
-            if(!justassign) {
-                prefix = abc_dup(prefix); // we need the object, too
-            }
-            use_temp_var = 1;
-        } else if(m->type == MULTINAMEL) {
-            if(!justassign) {
-                /* dupping two values on the stack requires 5 operations and one register- 
-                   couldn't adobe just have given us a dup2? */
-                int temp = gettempvar();
-                prefix = abc_setlocal(prefix, temp);
-                prefix = abc_dup(prefix);
-                prefix = abc_getlocal(prefix, temp);
-                prefix = abc_swap(prefix);
-                prefix = abc_getlocal(prefix, temp);
-                if(!use_temp_var);
-                    prefix = abc_kill(prefix, temp);
-            }
-            use_temp_var = 1;
-        } else {
-            syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
-        }
-    } else if(r->opcode == OPCODE_GETSLOT) {
-        write->opcode = OPCODE_SETSLOT;
-        write->data[0] = r->data[0];
-        if(!justassign) {
-            prefix = abc_dup(prefix); // we need the object, too
-        }
-        use_temp_var = 1;
-    } else if(r->opcode == OPCODE_GETLOCAL) { 
-        write->opcode = OPCODE_SETLOCAL;
-        write->data[0] = r->data[0];
-    } else if(r->opcode == OPCODE_GETLOCAL_0) { 
-        write->opcode = OPCODE_SETLOCAL_0;
-    } else if(r->opcode == OPCODE_GETLOCAL_1) { 
-        write->opcode = OPCODE_SETLOCAL_1;
-    } else if(r->opcode == OPCODE_GETLOCAL_2) { 
-        write->opcode = OPCODE_SETLOCAL_2;
-    } else if(r->opcode == OPCODE_GETLOCAL_3) { 
-        write->opcode = OPCODE_SETLOCAL_3;
-    } else if(r->opcode == OPCODE_GETSUPER) { 
-        write->opcode = OPCODE_SETSUPER;
-        multiname_t*m = (multiname_t*)r->data[0];
-        write->data[0] = multiname_clone(m);
-    } else {
-        code_dump(r);
-        syntaxerror("illegal lvalue: can't assign a value to this expression");
-    }
-    code_t* c = 0;
-    
-    int temp = -1;
-    if(!justassign) {
-        if(use_temp_var) {
-            /* with getproperty/getslot, we have to be extra careful not
-               to execute the read code twice, as it might have side-effects
-               (e.g. if the property is in fact a setter/getter combination)
-
-               So read the value, modify it, and write it again,
-               using prefix only once and making sure (by using a temporary
-               register) that the return value is what we just wrote */
-            temp = gettempvar();
-            c = code_append(c, prefix);
-            c = code_append(c, r);
-            if(readbefore) {
-                c = abc_dup(c);
-                c = abc_setlocal(c, temp);
-            }
-            c = code_append(c, middlepart);
-            if(!readbefore) {
-                c = abc_dup(c);
-                c = abc_setlocal(c, temp);
-            }
-            c = code_append(c, write);
-            c = abc_getlocal(c, temp);
-            c = abc_kill(c, temp);
-        } else {
-            /* if we're allowed to execute the read code twice *and*
-               the middlepart doesn't modify the code, things are easier.
-            */
-            code_t* r2 = code_dup(r);
-            //c = code_append(c, prefix);
-            parserassert(!prefix);
-            c = code_append(c, r);
-            c = code_append(c, middlepart);
-            c = code_append(c, write);
-            c = code_append(c, r2);
-        }
-    } else {
-        /* even smaller version: overwrite the value without reading
-           it out first */
-        if(!use_temp_var) {
-            if(prefix) {
-                c = code_append(c, prefix);
-                c = abc_dup(c);
-            }
-            c = code_append(c, middlepart);
-            c = code_append(c, write);
-            c = code_append(c, r);
-        } else {
-            code_free(r);r=0;
-            temp = gettempvar();
-            if(prefix) {
-                c = code_append(c, prefix);
-            }
-            c = code_append(c, middlepart);
-            c = abc_dup(c);
-            c = abc_setlocal(c, temp);
-            c = code_append(c, write);
-            c = abc_getlocal(c, temp);
-            c = abc_kill(c, temp);
-        }
-    }
-    return c;
-}
 
 char is_break_or_jump(code_t*c)
 {
@@ -2069,8 +1985,9 @@ code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
 #define PASS1 }} if(as3_pass == 1) {{
 #define PASS1END }} if(as3_pass == 2) {{
 #define PASS2 }} if(as3_pass == 2) {{
-#define PASS12 }} {{
+#define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
 #define PASS12END }} if(as3_pass == 2) {{
+#define PASS_ALWAYS }} {{
 
 %}
 
@@ -2090,7 +2007,7 @@ PROGRAM_CODE: PACKAGE_DECLARATION
             | FUNCTION_DECLARATION
             | SLOT_DECLARATION
             | PACKAGE_INITCODE
-            | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' // conditional compilation
+            | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
             | ';'
 
 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
@@ -2102,16 +2019,20 @@ INPACKAGE_CODE: INTERFACE_DECLARATION
               | FUNCTION_DECLARATION
               | SLOT_DECLARATION
               | PACKAGE_INITCODE
-              | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' // conditional compilation
+              | 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;}
 MAYBECODE: {$$=code_new();}
 
-CODE: CODE CODEPIECE {$$=code_append($1,$2);}
+CODE: CODE CODEPIECE {
+    $$=code_append($1,$2);
+}
 CODE: CODEPIECE {$$=$1;}
 
 // code which may appear outside of methods
+CODE_STATEMENT: DEFAULT_NAMESPACE 
 CODE_STATEMENT: IMPORT 
 CODE_STATEMENT: FOR 
 CODE_STATEMENT: FOR_IN 
@@ -2127,7 +2048,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
@@ -2135,7 +2056,15 @@ CODEPIECE: BREAK
 CODEPIECE: CONTINUE
 CODEPIECE: RETURN
 CODEPIECE: THROW
-CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
+CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {
+    PASS_ALWAYS 
+    if(as3_pass) {
+        $$ = $3;
+    } else {
+        $$ = 0;
+    }
+    as3_pass=$1;
+}
 
 //CODEBLOCK :  '{' CODE '}' {$$=$2;}
 //CODEBLOCK :  '{' '}'      {$$=0;}
@@ -2145,20 +2074,53 @@ 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 ------------- */
 
-CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER 
+CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
+    PASS12
+    $$=as3_pass;
+    char*key = concat3($1,"::",$3);
+    if(!definitions || !dict_contains(definitions, key)) {
+        as3_pass=0;
+    }
+    free(key);
+}
 
 /* ------------ variables --------------------------- */
 
-MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
-                |                {$$.c=abc_pushundefined(0);
-                                  $$.t=TYPE_ANY;
-                                 }
+%code {
+    char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
+    {
+        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;}
+                |       {$$=mkdummynode();}
 
 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
@@ -2169,85 +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
    
-    if(!is_subtype_of($3.t, $2)) {
-        syntaxerror("Can't convert %s to %s", $3.t->name, 
-                                              $2->name);
-    }
-
     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 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($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
-            $$ = code_append($$, $3.c);
-            $$ = converttype($$, $3.t, $2);
+        if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
+            $$ = code_append($$, val.c);
+            $$ = converttype($$, val.t, $2);
         } else {
-            code_free($3.c);
+            code_free(val.c);
             $$ = defaultvalue($$, $2);
         }
     } else {
-        if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
-            $$ = code_append($$, $3.c);
+        if(val.c->prev || val.c->opcode != OPCODE_PUSHUNDEFINED) {
+            $$ = code_append($$, val.c);
             $$ = abc_coerce_a($$);
         } else {
             // don't do anything
-            code_free($3.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();}
@@ -2258,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
@@ -2269,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);
@@ -2285,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);
@@ -2317,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);
@@ -2329,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 {
@@ -2393,7 +2346,7 @@ CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
 
 CASE: "case" E ':' MAYBECODE {
     $$ = abc_getlocal(0, state->switch_var);
-    $$ = code_append($$, $2.c);
+    $$ = code_append($$, node_read($2).c);
     code_t*j = $$ = abc_ifne($$, 0);
     $$ = code_append($$, $4);
     if($$->opcode != OPCODE___BREAK__) {
@@ -2406,7 +2359,7 @@ DEFAULT: "default" ':' MAYBECODE {
     $$ = $3;
 }
 SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
-    $$=$4.c;
+    $$ = node_read($4).c;
     $$ = abc_setlocal($$, state->switch_var);
     $$ = code_append($$, $7);
 
@@ -2430,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();
 }
 
@@ -2438,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, ""};
@@ -2458,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 {
@@ -2512,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;
@@ -2540,7 +2493,7 @@ TRY : "try" '{' {PASS12 new_state();
         
     list_concat(state->method->exceptions, $6.l);
    
-    $$ = var_block($$);
+    $$ = var_block($$, state->vars);
     PASS12 old_state();
 }
 
@@ -2590,7 +2543,8 @@ WITH : WITH_HEAD CODEBLOCK {
 
 X_IDENTIFIER: T_IDENTIFIER
             | "package" {PASS12 $$="package";}
-            | T_NAMESPACE {PASS12 $$=$1;}
+            | "namespace" {PASS12 $$="namespace";}
+            | "NaN" {PASS12 $$="NaN";}
 
 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
 PACKAGE: X_IDENTIFIER             {PASS12 $$=strdup($1);}
@@ -2600,20 +2554,47 @@ PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2
 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");} 
                                 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
 
+%code {
+    static void state_has_imports()
+    {
+        state->wildcard_imports = list_clone(state->wildcard_imports);
+        state->imports = dict_clone(state->imports);
+        state->has_own_imports = 1;
+    }
+    static void import_toplevel(const char*package)
+    {
+        char* s = strdup(package);
+        while(1) {
+            dict_put(state->import_toplevel_packages, s, 0);
+            char*x = strrchr(s, '.');
+            if(!x)
+                break;
+            *x = 0;
+        }
+        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);
        }
-
-       PASS2
-       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 '.' '*' {
@@ -2622,7 +2603,6 @@ IMPORT : "import" PACKAGE '.' '*' {
            as3_schedule_package($2);
        }
 
-       PASS2
        NEW(import_t,i);
        i->package = $2;
        state_has_imports();
@@ -2652,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;
                        }
 
@@ -2685,9 +2665,10 @@ MAYBE_CLASS_BODY : CLASS_BODY
 CLASS_BODY : CLASS_BODY_ITEM
 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
 CLASS_BODY_ITEM : ';'
-CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}'
+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;
@@ -2716,81 +2697,150 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI
 
 /* ------------ classes and interfaces (body, slots ) ------- */
 
+%code {
+    static int slotstate_varconst = 0;
+    static modifiers_t*slotstate_flags = 0;
+    static void setslotstate(modifiers_t* flags, int varconst)
+    {
+        slotstate_varconst = varconst;
+        slotstate_flags = flags;
+        if(state->cls) {
+            if(flags) {
+                if(flags->flags&FLAG_STATIC) {
+                    state->method = state->cls->static_init;
+                } else {
+                    state->method = state->cls->init;
+                }
+            } else {
+                // reset to "default" state (all in class code is static by default) */
+                state->method = state->cls->static_init;
+            }
+        } else {
+            parserassert(state->method);
+        }
+    }
+    static trait_t* add_abc_slot(modifiers_t* modifiers, const char*name, multiname_t*m, code_t***c)
+    {
+        int flags = modifiers->flags;
+        namespace_t ns = modifiers2access(modifiers);
+
+        /* slot name */
+        multiname_t mname = {QNAME, &ns, 0, name};
+      
+        trait_list_t**traits;
+        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;
+        } else if(flags&FLAG_STATIC) {
+            // static variable
+            traits = &state->cls->abc->static_traits;
+            code = &state->cls->static_init->header;
+        } else {
+            // 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) 
+            *m = *multiname_clone(&mname);
+            
+        return trait_new_member(traits, 0, multiname_clone(&mname), 0);
+    }
+};
+
 VARCONST: "var" | "const"
 
-SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {setslotstate(&$1,$2);} SLOT_LIST {$$=$4;setslotstate(0, 0);}
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
 
-SLOT_LIST: ONE_SLOT               {$$ = $1;}
-SLOT_LIST: SLOT_LIST ',' ONE_SLOT {$$ = code_append($1, $3);}
+SLOT_LIST: ONE_SLOT               {PASS12 $$=0;}
+SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
 
 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
 {
+PASS12
     int flags = slotstate_flags->flags;
     namespace_t ns = modifiers2access(slotstate_flags);
 
-    varinfo_t* info = 0;
-    if(state->cls) {
-        memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
-        if(i) {
-            check_override(i, flags);
-        }
-        info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
-    } else {
-        slotinfo_t*i = registry_find(state->package, $1);
-        if(i) {
-            syntaxerror("package %s already contains '%s'", state->package, $1);
-        }
-        if(ns.name && ns.name[0]) {
-            syntaxerror("namespaces not allowed on package-level variables");
+    if(as3_pass == 1) {
+
+        varinfo_t* info = 0;
+        if(state->cls) {
+            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, slotstate_flags->flags&FLAG_STATIC);
+        } else {
+            slotinfo_t*i = registry_find(state->package, $1);
+            if(i) {
+                syntaxerror("package %s already contains '%s'", state->package, $1);
+            }
+            if(ns.name && ns.name[0]) {
+                syntaxerror("namespaces not allowed on package-level variables");
+            }
+            info = varinfo_register_global(ns.access, state->package, $1);
         }
-        info = varinfo_register_global(ns.access, state->package, $1);
+
+        info->type = $2;
+        info->flags = flags;
+        
+        dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
     }
 
-    info->type = $2;
-    info->flags = flags;
+    if(as3_pass == 2) {
+        varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
 
-    /* slot name */
-    multiname_t mname = {QNAME, &ns, 0, $1};
-  
-    trait_list_t**traits;
-    code_t**code;
-    if(!state->cls) {
-        // global variable
-        ns.name = state->package;
-        traits = &global->init->traits;
-        code = &global->init->method->body->code;
-    } else if(flags&FLAG_STATIC) {
-        // static variable
-        traits = &state->cls->abc->static_traits;
-        code = &state->cls->static_init->header;
-    } else {
-        // instance variable
-        traits = &state->cls->abc->traits;
-        code = &state->cls->init->header;
-    }
-    
-    trait_t*t=0;
-    if($2) {
-        MULTINAME(m, $2);
-        t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
-    } else {
-        t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
-    }
-    info->slot = t->slot_id;
-    
-    /* initalization code (if needed) */
-    code_t*c = 0;
-    if($3.c && !is_pushundefined($3.c)) {
-        c = abc_getlocal_0(c);
-        c = code_append(c, $3.c);
-        c = converttype(c, $3.t, $2);
-        c = abc_setslot(c, t->slot_id);
-    }
+        multiname_t mname;
+        code_t**code;
+        trait_t*t = add_abc_slot(slotstate_flags, $1, &mname, &code);
 
-    *code = code_append(*code, c);
+        if($2) {
+            MULTINAME(m, $2);
+            t->type_name = multiname_clone(&m);
+        }
+        info->slot = t->slot_id;
+        
+        /* workaround for "VerifyError: Error #1053: Illegal override of ::test2 in C1" 
+           FIXME: is there a way to use slots and still don't have conflicting overrides?
+        */
+        info->slot = t->slot_id = 0;
+       
+        constant_t cval = $3->type->eval($3);
+        if(cval.type!=CONSTANT_UNKNOWN) {
+            /* compile time constant */
+            t->value = malloc(sizeof(constant_t));
+            memcpy(t->value, &cval, sizeof(constant_t));
+            info->value = constant_clone(t->value);
+        } else {
+            typedcode_t v = node_read($3);
+            /* initalization code (if needed) */
+            code_t*c = 0;
+            if(v.c && !is_pushundefined(v.c)) {
+                c = abc_getlocal_0(c);
+                c = code_append(c, v.c);
+                c = converttype(c, v.t, $2);
+                if(!t->slot_id) {
+                    c = abc_initproperty2(c, &mname);
+                } else {
+                    c = abc_setslot(c, t->slot_id);
+                }
+            }
+            *code = code_append(*code, c);
+        }
 
-    if(slotstate_varconst==KW_CONST) {
-        t->kind= TRAIT_CONST;
+        if(slotstate_varconst==KW_CONST) {
+            t->kind= TRAIT_CONST;
+            info->flags |= FLAG_CONST;
+        }
     }
 
     $$=0;
@@ -2798,25 +2848,126 @@ ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
 
 /* ------------ constants -------------------------------------- */
 
-MAYBESTATICCONSTANT: {$$=0;}
-MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
-
-STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
-STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
-STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
-STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
-STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
-//STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
-STATICCONSTANT : "true" {$$ = constant_new_true($1);}
-STATICCONSTANT : "false" {$$ = constant_new_false($1);}
-STATICCONSTANT : "null" {$$ = constant_new_null($1);}
-STATICCONSTANT : 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);
-    }
+MAYBECONSTANT: {$$=0;}
+MAYBECONSTANT: '=' E {
+  $$ = malloc(sizeof(constant_t));
+  *$$ = node_eval($2);
+  if($$->type == CONSTANT_UNKNOWN) {
+    syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
+  }
+}
+
+CONSTANT : T_INT {$$ = constant_new_int($1);}
+CONSTANT : T_UINT {
+    $$ = constant_new_uint($1);
+}
+CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
+CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
+CONSTANT : "true" {$$ = constant_new_true($1);}
+CONSTANT : "false" {$$ = constant_new_false($1);}
+CONSTANT : "null" {$$ = constant_new_null($1);}
+CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
+CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
+
+/* ---------------------------xml ------------------------------ */
+
+%code {
+    static int xml_level = 0;
+};
+
+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();} '}' {
+    $$ = $2;
+}
+XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
+    $$ = $2;
+}
+XMLTEXT : {$$=mkstringnode("");}
+XMLTEXT : XMLTEXT XMLEXPR1 {
+    $$ = 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;
+}
+
+MAYBE_XMLATTRIBUTES: {
+    $$ = mkstringnode("");
+}
+MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {
+    $$ = mkaddnode(mkstringnode(" "),$1);
+}
+
+XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
+    //$$ = 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);
+    $$ = mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(mkaddnode(
+         mkstringnode("<"),$2),$3),mkstringnode(">")),$5),$6),mkstringnode("</")),$9),mkstringnode(">"));
+}
+
+XMLATTRIBUTES: XMLATTRIBUTE {
+    $$ = $1;
+}
+XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {
+    $$ = mkaddnode($1, mkaddnode(mkstringnode(" "),$2));
+}
+XMLATTRIBUTE: XMLEXPR2 {
+    $$ = $1;
+}
+XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
+    char* str = string_cstr(&$3);
+    $$ = mkaddnode($1, mkstringnode(concat2("=",str)));
+    free(str);
+}
+XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
+    $$ = mkaddnode($1, mkaddnode(mkstringnode("=\""), mkaddnode($3, mkstringnode("\""))));
+}
+XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
+    $$ = mkaddnode(mkaddnode(mkstringnode(concat2($1,"=\"")), $3), mkstringnode("\""));
+}
+XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
+    char* str = string_cstr(&$3);
+    $$=mkstringnode(allocprintf("%s=%s", $1,str));
+    free(str);
+    free($1);free((char*)$3.str);
 }
 
 /* ------------ classes and interfaces (body, functions) ------- */
@@ -2857,7 +3008,7 @@ PARAM_LIST: PARAM {
     list_append($$.list, $1);
 }
 
-PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
+PARAM:  T_IDENTIFIER ':' TYPE MAYBECONSTANT {
      PASS12
      $$ = rfx_calloc(sizeof(param_t));
      $$->name=$1;
@@ -2865,7 +3016,7 @@ PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
      PASS2
      $$->value = $4;
 }
-PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
+PARAM:  T_IDENTIFIER MAYBECONSTANT {
      PASS12
      $$ = rfx_calloc(sizeof(param_t));
      $$->name=$1;
@@ -2937,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 {
@@ -2951,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
@@ -2960,8 +3113,8 @@ CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
 
 TYPE : CLASS_SPEC {PASS12 $$=$1;}
-     | '*'        {PASS12 $$=registry_getanytype();}
-     | "void"     {PASS12 $$=registry_getanytype();}
+     | '*'        {PASS12 $$=TYPE_ANY;}
+     | "void"     {PASS12 $$=TYPE_VOID;}
     /*
      |  "String"  {$$=registry_getstringclass();}
      |  "int"     {$$=registry_getintclass();}
@@ -2994,7 +3147,8 @@ EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
                
 XX : %prec new2
 NEW : "new" E XX MAYBE_PARAM_VALUES {
-    $$.c = $2.c;
+    typedcode_t v = node_read($2);
+    $$.c = v.c;
     if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
     
     code_t*paramcode = $4.cc;
@@ -3004,21 +3158,31 @@ 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(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;
+        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);
     }
    
     $$.t = TYPE_ANY;
-    if(TYPE_IS_CLASS($2.t) && $2.t->data) {
-        $$.t = $2.t->data;
+    if(TYPE_IS_CLASS(v.t) && v.t->data) {
+        $$.t = v.t->data;
     } else {
         $$.c = abc_coerce_a($$.c);
         $$.t = TYPE_ANY;
@@ -3030,8 +3194,9 @@ NEW : "new" E XX MAYBE_PARAM_VALUES {
          call (for closures)
 */
 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
-    
-    $$.c = $1.c;
+   
+    typedcode_t v = node_read($1);
+    $$.c = v.c;
     if($$.c->opcode == OPCODE_COERCE_A) {
         $$.c = code_cutlast($$.c);
     }
@@ -3044,7 +3209,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) {
@@ -3054,7 +3219,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);
@@ -3067,11 +3232,14 @@ FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
         $$.c = abc_call($$.c, $3.number);
     }
    
-    if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
-        $$.t = ((methodinfo_t*)($1.t->data))->return_type;
+    if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
+        $$.t = ((methodinfo_t*)(v.t->data))->return_type;
+    } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
+        // 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);
     }
 }
 
@@ -3097,7 +3265,8 @@ FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
 }
 
 DELETE: "delete" E {
-    $$.c = $2.c;
+    typedcode_t v = node_read($2);
+    $$.c = v.c;
     if($$.c->opcode == OPCODE_COERCE_A) {
         $$.c = code_cutlast($$.c);
     }
@@ -3111,7 +3280,7 @@ DELETE: "delete" E {
         $$.c = abc_deleteproperty2($$.c, name);
     } else {
         $$.c = abc_getlocal_0($$.c);
-        MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
+        MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
         $$.c = abc_deleteproperty2($$.c, &m);
     }
     $$.t = TYPE_BOOLEAN;
@@ -3127,548 +3296,384 @@ RETURN: "return" EXPRESSION {
 
 // ----------------------- expression types -------------------------------------
 
-NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
-EXPRESSION : E                %prec below_minus {$$ = $1;}
-EXPRESSION : EXPRESSION ',' E %prec below_minus {
-    $$.c = $1.c;
-    $$.c = cut_last_push($$.c);
-    $$.c = code_append($$.c,$3.c);
-    $$.t = $3.t;
+NONCOMMAEXPRESSION : E %prec below_lt {
+    $$ = node_read($1);
 }
-VOIDEXPRESSION : EXPRESSION %prec below_minus {
-    $$=cut_last_push($1.c);
+EXPRESSION : COMMA_EXPRESSION {
+    $$ = node_read($1);
 }
-
-// ----------------------- expression evaluation -------------------------------------
-
-E : INNERFUNCTION %prec prec_none {$$ = $1;}
-//V : CONSTANT                    {$$ = 0;}
-E : CONSTANT
-//V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
-E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
-//V : NEW                         {$$ = $1.c;}
-E : NEW                         {$$ = $1;}
-//V : DELETE                      {$$ = $1.c;}
-E : DELETE                      {$$ = $1;}
-
-E : FUNCTIONCALL
-
-E : T_REGEXP {
-    $$.c = 0;
-    namespace_t ns = {ACCESS_PACKAGE, ""};
-    multiname_t m = {QNAME, &ns, 0, "RegExp"};
-    if(!$1.options) {
-        $$.c = abc_getlex2($$.c, &m);
-        $$.c = abc_pushstring($$.c, $1.pattern);
-        $$.c = abc_construct($$.c, 1);
-    } else {
-        $$.c = abc_getlex2($$.c, &m);
-        $$.c = abc_pushstring($$.c, $1.pattern);
-        $$.c = abc_pushstring($$.c, $1.options);
-        $$.c = abc_construct($$.c, 2);
-    }
-    $$.t = TYPE_REGEXP;
-}
-
-CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
-                   //MULTINAME(m, registry_getintclass());
-                   //$$.c = abc_coerce2($$.c, &m); // FIXME
-                   $$.t = TYPE_INT;
-                  }
-CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
-                    $$.t = TYPE_INT;
-                   }
-CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
-                  $$.t = TYPE_INT;
-                 }
-CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
-                   $$.t = TYPE_UINT;
-                  }
-CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
-                    $$.t = TYPE_FLOAT;
-                   }
-CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
-                     $$.t = TYPE_STRING;
-                    }
-CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
-                    $$.t = TYPE_ANY;
-                   }
-CONSTANT : "true" {$$.c = abc_pushtrue(0);
-                    $$.t = TYPE_BOOLEAN;
-                   }
-CONSTANT : "false" {$$.c = abc_pushfalse(0);
-                     $$.t = TYPE_BOOLEAN;
-                    }
-CONSTANT : "null" {$$.c = abc_pushnull(0);
-                    $$.t = TYPE_NULL;
-                   }
-
-E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
-             $$.t = TYPE_BOOLEAN;
-            }
-E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
-             $$.t = TYPE_BOOLEAN;
-            }
-E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
-              $$.t = TYPE_BOOLEAN;
-             }
-E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
-              $$.t = TYPE_BOOLEAN;
-             }
-E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
-              $$.t = TYPE_BOOLEAN;
-             }
-E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
-              $$.t = TYPE_BOOLEAN;
-              }
-E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
-              $$.t = TYPE_BOOLEAN;
-             }
-E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
-              $$.t = TYPE_BOOLEAN;
-             }
-
-E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
-              $$.c = $1.c;
-              $$.c = converttype($$.c, $1.t, $$.t);
-              $$.c = abc_dup($$.c);
-              code_t*jmp = $$.c = abc_iftrue($$.c, 0);
-              $$.c = cut_last_push($$.c);
-              $$.c = code_append($$.c,$3.c);
-              $$.c = converttype($$.c, $3.t, $$.t);
-              code_t*label = $$.c = abc_label($$.c);
-              jmp->branch = label;
-             }
-E : E "&&" E {
-              $$.t = join_types($1.t, $3.t, 'A');
-              /*printf("%08x:\n",$1.t);
-              code_dump($1.c, 0, 0, "", stdout);
-              printf("%08x:\n",$3.t);
-              code_dump($3.c, 0, 0, "", stdout);
-              printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
-              $$.c = $1.c;
-              $$.c = converttype($$.c, $1.t, $$.t);
-              $$.c = abc_dup($$.c);
-              code_t*jmp = $$.c = abc_iffalse($$.c, 0);
-              $$.c = cut_last_push($$.c);
-              $$.c = code_append($$.c,$3.c);
-              $$.c = converttype($$.c, $3.t, $$.t);
-              code_t*label = $$.c = abc_label($$.c);
-              jmp->branch = label;              
-             }
-
-E : '!' E    {$$.c=$2.c;
-              $$.c = abc_not($$.c);
-              $$.t = TYPE_BOOLEAN;
-             }
-
-E : '~' E    {$$.c=$2.c;
-              $$.c = abc_bitnot($$.c);
-              $$.t = TYPE_INT;
-             }
-
-E : E '&' E {$$.c = code_append($1.c,$3.c);
-             $$.c = abc_bitand($$.c);
-             $$.t = TYPE_INT;
-            }
-
-E : E '^' E {$$.c = code_append($1.c,$3.c);
-             $$.c = abc_bitxor($$.c);
-             $$.t = TYPE_INT;
-            }
-
-E : E '|' E {$$.c = code_append($1.c,$3.c);
-             $$.c = abc_bitor($$.c);
-             $$.t = TYPE_INT;
-            }
-
-E : E ">>" E {$$.c = code_append($1.c,$3.c);
-             $$.c = abc_rshift($$.c);
-             $$.t = TYPE_INT;
-            }
-E : E ">>>" E {$$.c = code_append($1.c,$3.c);
-             $$.c = abc_urshift($$.c);
-             $$.t = TYPE_INT;
-            }
-E : E "<<" E {$$.c = code_append($1.c,$3.c);
-             $$.c = abc_lshift($$.c);
-             $$.t = TYPE_INT;
-            }
-
-E : E '/' E {$$.c = code_append($1.c,$3.c);
-             $$.c = abc_divide($$.c);
-             $$.t = TYPE_NUMBER;
-            }
-E : E '%' E {$$.c = code_append($1.c,$3.c);
-             $$.c = abc_modulo($$.c);
-             $$.t = TYPE_NUMBER;
-            }
-E : E '+' E {$$.c = code_append($1.c,$3.c);
-             if(BOTH_INT($1.t, $3.t)) {
-                $$.c = abc_add_i($$.c);
-                $$.t = TYPE_INT;
-             } else {
-                $$.c = abc_add($$.c);
-                $$.t = join_types($1.t,$3.t,'+');
-             }
-            }
-E : E '-' E {$$.c = code_append($1.c,$3.c);
-             if(BOTH_INT($1.t,$3.t)) {
-                $$.c = abc_subtract_i($$.c);
-                $$.t = TYPE_INT;
-             } else {
-                $$.c = abc_subtract($$.c);
-                $$.t = TYPE_NUMBER;
-             }
-            }
-E : E '*' E {$$.c = code_append($1.c,$3.c);
-             if(BOTH_INT($1.t,$3.t)) {
-                $$.c = abc_multiply_i($$.c);
-                $$.t = TYPE_INT;
-             } else {
-                $$.c = abc_multiply($$.c);
-                $$.t = TYPE_NUMBER;
-             }
-            }
-
-E : E "in" E {$$.c = code_append($1.c,$3.c);
-              $$.c = abc_in($$.c);
-              $$.t = TYPE_BOOLEAN;
-             }
-
-E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
-              if(use_astype && TYPE_IS_CLASS($3.t) && $3.t->data) {
-                MULTINAME(m, (classinfo_t*)($3.t->data));
-                $$.c = abc_astype2($1.c, &m);
-                $$.t = $3.t->data;
-              } else {
-                $$.c = code_append($1.c, $3.c);
-                $$.c = abc_astypelate($$.c);
-                $$.t = TYPE_ANY;
-              }
-             }
-
-E : E "instanceof" E 
-             {$$.c = code_append($1.c, $3.c);
-              $$.c = abc_instanceof($$.c);
-              $$.t = TYPE_BOOLEAN;
-             }
-
-E : E "is" E {$$.c = code_append($1.c, $3.c);
-              $$.c = abc_istypelate($$.c);
-              $$.t = TYPE_BOOLEAN;
-             }
-
-E : "typeof" '(' E ')' {
-              $$.c = $3.c;
-              $$.c = abc_typeof($$.c);
-              $$.t = TYPE_STRING;
-             }
-
-E : "void" E {
-              $$.c = cut_last_push($2.c);
-              $$.c = abc_pushundefined($$.c);
-              $$.t = TYPE_ANY;
-             }
-
-E : "void" { $$.c = abc_pushundefined(0);
-             $$.t = TYPE_ANY;
-           }
-
-E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
-
-E : '-' E {
-  $$=$2;
-  if(IS_INT($2.t)) {
-   $$.c=abc_negate_i($$.c);
-   $$.t = TYPE_INT;
-  } else {
-   $$.c=abc_negate($$.c);
-   $$.t = TYPE_NUMBER;
-  }
+COMMA_EXPRESSION : E %prec below_lt {
+    $$ = mkmultinode(&node_comma, $1);
 }
-
-E : E '[' E ']' {
-  $$.c = $1.c;
-  $$.c = code_append($$.c, $3.c);
-
-  MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
-  $$.c = abc_getproperty2($$.c, &m);
-  $$.t = 0; // array elements have unknown type
+COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_lt {
+    $$ = multinode_extend($1, $3);
 }
-
-E : '[' MAYBE_EXPRESSION_LIST ']' {
-    $$.c = code_new();
-    $$.c = code_append($$.c, $2.cc);
-    $$.c = abc_newarray($$.c, $2.number);
-    $$.t = registry_getarrayclass();
+VOIDEXPRESSION : E %prec below_minus { 
+    $$ = node_exec($1); 
+}
+VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_lt { 
+    $$ = $1;
+    $$ = code_append($$, node_exec($3)); 
 }
 
-MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
-MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
+MAYBE_DICT_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
+MAYBE_DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST {$$=$1;}
 
-EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+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;
-    $$.cc = code_append($$.cc, $1.c);
+    $$.cc = code_append($$.cc, $1);
     $$.cc = code_append($$.cc, $3.c);
     $$.number = 2;
 }
-EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+DICT_EXPRPAIR_LIST : DICT_EXPRPAIR_LIST ',' DICTLH ':' NONCOMMAEXPRESSION {
     $$.cc = $1.cc;
     $$.number = $1.number+2;
-    $$.cc = code_append($$.cc, $3.c);
+    $$.cc = code_append($$.cc, $3);
     $$.cc = code_append($$.cc, $5.c);
 }
-//MAYBECOMMA: ','
-//MAYBECOMMA:
 
-E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
-    $$.c = code_new();
-    $$.c = code_append($$.c, $2.cc);
-    $$.c = abc_newobject($$.c, $2.number/2);
-    $$.t = registry_getobjectclass();
-}
-
-E : E "*=" E { 
-               code_t*c = $3.c;
-               if(BOTH_INT($1.t,$3.t)) {
-                c=abc_multiply_i(c);
-               } else {
-                c=abc_multiply(c);
-               }
-               c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-              }
-
-E : E "%=" E { 
-               code_t*c = abc_modulo($3.c);
-               c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-              }
-E : E "<<=" E { 
-               code_t*c = abc_lshift($3.c);
-               c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-              }
-E : E ">>=" E { 
-               code_t*c = abc_rshift($3.c);
-               c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-              }
-E : E ">>>=" E { 
-               code_t*c = abc_urshift($3.c);
-               c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-              }
-E : E "/=" E { 
-               code_t*c = abc_divide($3.c);
-               c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-              }
-E : E "|=" E { 
-               code_t*c = abc_bitor($3.c);
-               c=converttype(c, TYPE_INT, $1.t);
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-              }
-E : E "^=" E { 
-               code_t*c = abc_bitxor($3.c);
-               c=converttype(c, TYPE_INT, $1.t);
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-              }
-E : E "+=" E { 
-               code_t*c = $3.c;
-
-               if(TYPE_IS_INT($1.t)) {
-                c=abc_add_i(c);
-               } else {
-                c=abc_add(c);
-                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
-               }
-               
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-              }
-E : E "-=" E { code_t*c = $3.c; 
-               if(TYPE_IS_INT($1.t)) {
-                c=abc_subtract_i(c);
-               } else {
-                c=abc_subtract(c);
-                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
-               }
-               
-               $$.c = toreadwrite($1.c, c, 0, 0);
-               $$.t = $1.t;
-             }
-E : E '=' E { code_t*c = 0;
-              c = code_append(c, $3.c);
-              c = converttype(c, $3.t, $1.t);
-              $$.c = toreadwrite($1.c, c, 1, 0);
-              $$.t = $1.t;
-            }
+// ----------------------- expression evaluation -------------------------------------
 
-E : E '?' E ':' E %prec below_assignment { 
-              $$.t = join_types($3.t,$5.t,'?');
-              $$.c = $1.c;
-              code_t*j1 = $$.c = abc_iffalse($$.c, 0);
-              $$.c = code_append($$.c, $3.c);
-              $$.c = converttype($$.c, $3.t, $$.t);
-              code_t*j2 = $$.c = abc_jump($$.c, 0);
-              $$.c = j1->branch = abc_label($$.c);
-              $$.c = code_append($$.c, $5.c);
-              $$.c = converttype($$.c, $5.t, $$.t);
-              $$.c = j2->branch = abc_label($$.c);
-            }
+E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
+E : MEMBER %prec '.'              {$$ = mkcodenode($1);}
+E : NEW                           {$$ = mkcodenode($1);}
+E : DELETE                        {$$ = mkcodenode($1);}
+E : FUNCTIONCALL                  {$$ = mkcodenode($1);}
+E : VAR_READ %prec T_IDENTIFIER   {$$ = $1;}
 
-E : E "++" { code_t*c = 0;
-             classinfo_t*type = $1.t;
-             if(is_getlocal($1.c) && (TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t))) {
-                 int nr = getlocalnr($1.c);
-                 code_free($1.c);$1.c=0;
-                 if(TYPE_IS_INT($1.t)) {
-                    $$.c = abc_getlocal(0, nr);
-                    $$.c = abc_inclocal_i($$.c, nr);
-                 } else if(TYPE_IS_NUMBER($1.t)) {
-                    $$.c = abc_getlocal(0, nr);
-                    $$.c = abc_inclocal($$.c, nr);
-                 } else syntaxerror("internal error");
-             } else {
-                 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
-                     c=abc_increment_i(c);
-                     type = TYPE_INT;
-                 } else {
-                     c=abc_increment(c);
-                     type = TYPE_NUMBER;
-                 }
-                 c=converttype(c, type, $1.t);
-                 $$.c = toreadwrite($1.c, c, 0, 1);
-                 $$.t = $1.t;
-             }
-           }
+E : CONSTANT { 
+    $$ = mkconstnode($1);
+}
 
-// TODO: use inclocal, like with ++
-E : E "--" { code_t*c = 0;
-             classinfo_t*type = $1.t;
-             if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
-                 c=abc_decrement_i(c);
-                 type = TYPE_INT;
-             } else {
-                 c=abc_decrement(c);
-                 type = TYPE_NUMBER;
-             }
-             c=converttype(c, type, $1.t);
-             $$.c = toreadwrite($1.c, c, 0, 1);
-             $$.t = $1.t;
-            }
+E : XML {
+    $$ = $1;
+}
 
-E : "++" %prec plusplus_prefix E { code_t*c = 0;
-             classinfo_t*type = $2.t;
-             if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
-                 c=abc_increment_i(c);
-                 type = TYPE_INT;
-             } else {
-                 c=abc_increment(c);
-                 type = TYPE_NUMBER;
-             }
-             c=converttype(c, type, $2.t);
-             $$.c = toreadwrite($2.c, c, 0, 0);
-             $$.t = $2.t;
-           }
+/* regexp */
+E : T_REGEXP {
+    typedcode_t v;
+    v.c = 0;
+    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);
+        v.c = abc_construct(v.c, 1);
+    } else {
+        v.c = abc_getlex2(v.c, &m);
+        v.c = abc_pushstring(v.c, $1.pattern);
+        v.c = abc_pushstring(v.c, $1.options);
+        v.c = abc_construct(v.c, 2);
+    }
+    v.t = TYPE_REGEXP;
+    $$ = mkcodenode(v);
+}
 
-E : "--" %prec minusminus_prefix E { code_t*c = 0;
-             classinfo_t*type = $2.t;
-             if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
-                 c=abc_decrement_i(c);
-                 type = TYPE_INT;
-             } else {
-                 c=abc_decrement(c);
-                 type = TYPE_NUMBER;
-             }
-             c=converttype(c, type, $2.t);
-             $$.c = toreadwrite($2.c, c, 0, 0);
-             $$.t = $2.t;
-           }
+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;
+    v.c = code_new();
+    v.c = code_append(v.c, $2.cc);
+    v.c = abc_newarray(v.c, $2.number);
+    v.t = registry_getarrayclass();
+    $$ = mkcodenode(v);
+}
+
+/* dictionary */
+E : "{ (dictionary)" MAYBE_DICT_EXPRPAIR_LIST '}' {
+    typedcode_t v;
+    v.c = code_new();
+    v.c = code_append(v.c, $2.cc);
+    v.c = abc_newobject(v.c, $2.number/2);
+    v.t = registry_getobjectclass();
+    $$ =  mkcodenode(v);
+}
+
+E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
+E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
+E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
+E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
+E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
+E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
+E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
+E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
+E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
+E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
+E : '!' E    {$$ = mknode1(&node_not, $2);}
+E : '~' E    {$$ = mknode1(&node_bitnot, $2);}
+E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
+E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
+E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
+E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
+E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
+E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
+E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
+E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
+E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
+E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
+E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
+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, $2);}
+E : "void" E {$$ = mknode1(&node_void, $2);}
+E : "void" { $$ = mkconstnode(constant_new_undefined());}
+E : '(' COMMA_EXPRESSION ')' { $$=$2;}
+E : '-' E {$$ = mknode1(&node_neg, $2);}
+E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
+E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
+E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
+E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
+E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
+E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
+E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
+E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
+E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
+E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
+E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
+E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
+E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
+E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
+
+E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
+E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
+E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
+E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
 
 E : "super" '.' T_IDENTIFIER 
            { if(!state->cls->info)
                   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);
-              $$.c = 0;
-              $$.c = abc_getlocal_0($$.c);
-              $$.c = abc_getsuper2($$.c, &m);
-              $$.t = slotinfo_gettype((slotinfo_t*)f);
+              typedcode_t v;
+              v.c = 0;
+              v.c = abc_getlocal_0(v.c);
+              v.c = abc_getsuper2(v.c, &m);
+              v.t = slotinfo_gettype((slotinfo_t*)f);
+              $$ = mkcodenode(v);
            }
 
 E : '@' T_IDENTIFIER {
-              // attribute TODO
-              $$.c = abc_pushundefined(0);
-              $$.t = 0;
-              as3_warning("ignored @ operator");
-           }
-
-E : E '.' '@' T_IDENTIFIER {
-              // child attribute  TODO
-              $$.c = abc_pushundefined(0);
-              $$.t = 0;
-              as3_warning("ignored .@ operator");
-           }
-
-E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
-              // namespace declaration TODO
-              $$.c = abc_pushundefined(0);
-              $$.t = 0;
-              as3_warning("ignored :: operator");
-           }
-
-E : E ".." T_IDENTIFIER {
-              // descendants TODO
-              $$.c = abc_pushundefined(0);
-              $$.t = 0;
-              as3_warning("ignored .. operator");
-           }
-
-E : E '.' '(' E ')' {
-              // filter TODO
-              $$.c = abc_pushundefined(0);
-              $$.t = 0;
-              as3_warning("ignored .() operator");
-           }
-
-//VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
-
+    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 '.' '(' {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, state->vars);
+    old_state();
+    typedcode_t r;
+    r.c = c;
+    r.t = TYPE_XMLLIST;
+    $$ = mkcodenode(r);
+}
+
+ID_OR_NS : T_IDENTIFIER {$$=$1;}
+ID_OR_NS : '*' {$$="*";}
+SUBNODE: X_IDENTIFIER
+       | '*' {$$="*";}
+
+%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 '.' T_IDENTIFIER {
-    $$.c = $1.c;
-    classinfo_t*t = $1.t;
+E : E '.' ID_OR_NS "::" SUBNODE {
+    $$ = get_descendants($1, $3, $5, 0, 0);
+}
+E : E ".." SUBNODE {
+    typedcode_t v = node_read($1);
+    multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
+    v.c = abc_getdescendants2(v.c, &m);
+    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);
+    multiname_t m = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
+    v.c = code_append(v.c, w.c);
+    v.c = converttype(w.c, w.t, TYPE_STRING);
+    v.c = abc_getproperty2(v.c, &m);
+    v.t = TYPE_XMLLIST;
+    $$ = mkcodenode(v);
+}
+
+E : E '.' '@' SUBNODE {
+    typedcode_t v = node_read($1);
+    multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $4};
+    v.c = abc_getproperty2(v.c, &m);
+    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};
+    v.c = abc_getdescendants2(v.c, &m);
+    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);
+    multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
+    v.c = code_append(v.c, w.c);
+    v.c = converttype(w.c, w.t, TYPE_STRING);
+    v.c = abc_getproperty2(v.c, &m);
+    v.t = TYPE_STRING;
+    $$ = mkcodenode(v);
+}
+E : E ".." '@' '[' E ']' {
+    typedcode_t v = node_read($1);
+    typedcode_t w = node_read($5);
+    multiname_t m = {MULTINAMELA, 0, &nopackage_namespace_set, 0};
+    v.c = code_append(v.c, w.c);
+    v.c = converttype(w.c, w.t, TYPE_STRING);
+    v.c = abc_getdescendants2(v.c, &m);
+    v.t = TYPE_STRING;
+    $$ = mkcodenode(v);
+}
+
+MEMBER : E '.' SUBNODE {
+    typedcode_t v1 = node_read($1);
+    $$.c = v1.c;
+    classinfo_t*t = v1.t;
     char is_static = 0;
     if(TYPE_IS_CLASS(t) && t->data) {
         t = t->data;
         is_static = 1;
     }
-    if(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);
+        $$.t = TYPE_XMLLIST;
+    } else if(t) {
         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;
         if(f && f->slot && !noslot) {
             $$.c = abc_getslot($$.c, f->slot);
         } else {
+            if(!f) {
+                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);
         }
@@ -3676,30 +3681,166 @@ E : E '.' T_IDENTIFIER {
         $$.t = slotinfo_gettype((slotinfo_t*)f);
         if(!$$.t)
            $$.c = abc_coerce_a($$.c);
-    } else if($1.c && $1.c->opcode == OPCODE___PUSHPACKAGE__) {
-        string_t*package = $1.c->data[0];
+        
+    } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
+        string_t*package = v1.c->data[0];
         char*package2 = concat3(package->str, ".", $3);
-        if(dict_contains(state->import_toplevel_packages, package2)) {
-            $$.c = $1.c;
+
+        slotinfo_t*a = registry_find(package->str, $3);
+        if(a) {
+            $$ = push_class(a);
+        } else if(dict_contains(state->import_toplevel_packages, package2) ||
+                  registry_ispackage(package2)) {
+            $$.c = v1.c;
             $$.c->data[0] = string_new4(package2);
             $$.t = 0;
         } else {
-            slotinfo_t*a = registry_find(package->str, $3);
-            if(!a) 
-                syntaxerror("couldn't resolve %s", package2);
-            $$ = push_class(a);
+            syntaxerror("couldn't resolve %s", package2);
         }
     } else {
         /* when resolving a property on an unknown type, we do know the
            name of the property (and don't seem to need the package), but
            we need to make avm2 try out all access modes */
+        as3_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);
-        $$.t = registry_getanytype();
+        $$.t = TYPE_ANY;
     }
 }
 
+%code {
+    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;
+        o.c = 0;
+
+        slotinfo_t*a = 0;
+        memberinfo_t*f = 0;
+
+        variable_t*v;
+        /* look at variables */
+        if((v = find_variable(state, name))) {
+            // name is a local variable
+           return var_read(v);
+        }
+        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;
+            return mkcodenode(o);
+        }
+
+        int i_am_static = state->method->is_static;
+
+        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);
+            } else {
+                o = push_class(a);
+            }
+            return mkcodenode(o);
+        }
+
+        /* look through package prefixes */
+        if(!state->xmlfilter && 
+           (dict_contains(state->import_toplevel_packages, name) || 
+            registry_ispackage(name))) {
+            o.c = abc___pushpackage__(o.c, (char*)name);
+            o.t = 0;
+            return mkcodenode(o); //?
+        }
+
+        /* unknown object, let the avm2 resolve it */
+        if(1) {
+            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};
+
+            o.t = 0;
+            o.c = abc_findpropstrict2(o.c, &m);
+            o.c = abc_getproperty2(o.c, &m);
+            return mkcodenode(o);
+        }
+    }
+};
+
 VAR_READ : T_IDENTIFIER {
     PASS1
     /* Queue unresolved identifiers for checking against the parent
@@ -3709,102 +3850,31 @@ VAR_READ : T_IDENTIFIER {
        etc. which is *correct* because local variables of the parent function
        would shadow those.
        */
-    if(state->method->inner && !find_variable(state, $1)) {
+
+    if(!find_variable(state, $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);
     }
    
-    /* let the compiler know that it might check the current directory/package
-       for this identifier- maybe there's a file $1.as defining $1. */
-    as3_schedule_class_noerror(state->package, $1);
+    $$ = 0;
     PASS2
 
-    $$.t = 0;
-    $$.c = 0;
-    slotinfo_t*a = 0;
-    memberinfo_t*f = 0;
-
-    variable_t*v;
-    /* look at variables */
-    if((v = find_variable(state, $1))) {
-        // $1 is a local variable
-        $$.c = abc_getlocal($$.c, v->index);
-        $$.t = v->type;
-        break;
-    }
-    if((v = find_slot(state, $1))) {
-        $$.c = abc_getscopeobject($$.c, 1);
-        $$.c = abc_getslot($$.c, v->index);
-        $$.t = v->type;
-        break;
-    }
-
-    int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
-
-    /* look at current class' members */
-    if(state->cls && (f = findmember_nsset(state->cls->info, $1, 1)) &&
-        (f->flags&FLAG_STATIC) >= i_am_static) {
-        // $1 is a function in this class
-        int var_is_static = (f->flags&FLAG_STATIC);
-
-        if(f->kind == INFOTYPE_METHOD) {
-            $$.t = TYPE_FUNCTION(f);
-        } else {
-            $$.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;
-            $$.t = f->type;
-            namespace_t ns = {f->access, ""};
-            multiname_t m = {QNAME, &ns, 0, $1};
-            $$.c = abc_findpropstrict2($$.c, &m);
-            $$.c = abc_getproperty2($$.c, &m);
-            break;
-        } else if(f->slot>0) {
-            $$.c = abc_getlocal_0($$.c);
-            $$.c = abc_getslot($$.c, f->slot);
-            break;
-        } else {
-            namespace_t ns = {f->access, ""};
-            multiname_t m = {QNAME, &ns, 0, $1};
-            $$.c = abc_getlocal_0($$.c);
-            $$.c = abc_getproperty2($$.c, &m);
-            break;
-        }
-    } 
-    
-    /* look at actual classes, in the current package and imported */
-    if((a = find_class($1))) {
-        $$ = push_class(a);
-        break;
-    }
-
-    /* look through package prefixes */
-    if(dict_contains(state->import_toplevel_packages, $1)) {
-        $$.c = abc___pushpackage__($$.c, $1);
-        $$.t = 0;
-        break;
-    }
-
-    /* unknown object, let the avm2 resolve it */
-    if(1) {
-        //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
-        as3_warning("Couldn't resolve '%s', doing late binding", $1);
-        state->method->late_binding = 1;
-                
-        multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
-
-        $$.t = 0;
-        $$.c = abc_findpropstrict2($$.c, &m);
-        $$.c = abc_getproperty2($$.c, &m);
-    }
+    $$ = resolve_identifier($1);
 }
 
 // ----------------- namespaces -------------------------------------------------
 
+%code {
+    void add_active_url(const char*url)
+    {
+        NEW(namespace_t,n);
+        n->name = url;
+        list_append(state->active_namespace_urls, n);
+    }
+};
+
 NAMESPACE_ID : "namespace" T_IDENTIFIER {
     PASS12
     NEW(namespace_decl_t,n);
@@ -3828,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);
@@ -3837,14 +3907,42 @@ NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
     ns.access = ACCESS_NAMESPACE;
     ns.name = $2->url;
     var->value = constant_new_namespace(&ns);
+      
+    if(as3_pass==2) {
+        MULTINAME(m, TYPE_NAMESPACE);
+        trait_t*t = add_abc_slot(&$1, $2->name, 0, 0);
+        t->value = var->value;
+        t->type_name = multiname_clone(&m);
+    }
 
     $$=0;
 }
 
+DEFAULT_NAMESPACE : "default xml" "namespace" '=' E 
+{
+    $$ = 0;
+    $$ = code_append($$, node_read($4).c);
+    $$ = abc_dxnslate($$);
+}
+
 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
     PASS12
-    char*url = 0;
-    trie_put(active_namespaces, $3->name, url);
+
+    varinfo_t*s = (varinfo_t*)$3;
+    if(s->kind == INFOTYPE_UNRESOLVED) {
+        s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
+        if(!s)
+            syntaxerror("Couldn't resolve namespace %s", $3->name);
+    }
+
+    if(!s || s->kind != INFOTYPE_VAR)
+        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);
+
+    const char*url = s->value->ns->name;
+    dict_put(state->namespaces, (unsigned char*)$3->name, (void*)url);
+    add_active_url(url);
     $$=0;
 }