as3: various bugfixes
[swftools.git] / lib / as3 / parser.y
index d6cf02a..96b9b59 100644 (file)
 #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;
@@ -79,8 +83,6 @@ extern int a3_lex();
 %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"
@@ -101,6 +103,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"
@@ -153,6 +156,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,6 +174,7 @@ extern int a3_lex();
 %token<token> T_USHR ">>>"
 %token<token> T_SHR ">>"
 
+%type <number_int> CONDITIONAL_COMPILATION
 %type <for_start> FOR_START
 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
 %type <namespace_decl>  NAMESPACE_ID
@@ -187,9 +192,10 @@ 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
@@ -203,7 +209,7 @@ 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
@@ -213,11 +219,13 @@ extern int a3_lex();
 
 %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
 
@@ -256,7 +264,7 @@ extern int a3_lex();
 
 // 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 +278,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 +312,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);
@@ -332,6 +346,7 @@ struct _methodstate {
     char uses_parent_function;
     int uses_slots;
     dict_t*slots;
+    int activation_var;
 
     abc_method_t*abc;
     int var_index; // for inner methods
@@ -354,8 +369,9 @@ typedef struct _state {
     import_list_t*wildcard_imports;
     dict_t*import_toplevel_packages;
     dict_t*imports;
-    namespace_list_t*active_namespaces;
-    namespace_decl_list_t*new_namespaces;
+
+    namespace_list_t*active_namespace_urls;
+    
     char has_own_imports;
     char new_vars; // e.g. transition between two functions
   
@@ -367,11 +383,17 @@ typedef struct _state {
     int switch_var;
     
     dict_t*vars;
+    dict_t*allvars; // also contains variables from sublevels
 } state_t;
 
 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;
@@ -381,12 +403,6 @@ 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));
-                    
 #define MEMBER_MULTINAME(m,f,n) \
     multiname_t m;\
     namespace_t m##_ns;\
@@ -426,6 +442,15 @@ 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);
@@ -441,28 +466,14 @@ static void new_state()
     state = s;
     state->level++;
     state->has_own_imports = 0;    
-    state->new_namespaces = 0;
     state->vars = dict_new(); 
     state->old = oldstate;
     state->new_vars = 0;
-}
-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);
+
+    trie_remember(active_namespaces);
+   
+    if(oldstate)
+        state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
 }
 
 static void state_destroy(state_t*state)
@@ -475,34 +486,32 @@ 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;
     }
+    if(state->new_vars && state->allvars) {
+        parserassert(!state->old || state->old->allvars != state->allvars);
+        DICT_ITERATE_DATA(state->allvars, void*, data) {
+            free(data);
+        }
+        dict_destroy(state->allvars);
+    }
+    
+    list_free(state->active_namespace_urls)
+    state->active_namespace_urls = 0;
     
     free(state);
 }
 
 static void old_state()
 {
+    trie_rollback(active_namespaces);
+
     if(!state || !state->old)
         syntaxerror("invalid nesting");
     state_t*leaving = state;
     
     state = state->old;
 
-    namespace_decl_list_t*nl=leaving->new_namespaces;
-    while(nl) {
-        tokenizer_unregister_namespace(nl->namespace_decl->name);
-        nl = nl->next;
-    }
-    
     if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
         free(leaving->method);
         leaving->method=0;
@@ -511,7 +520,7 @@ static void old_state()
         free(leaving->cls);
         leaving->cls=0;
     }
-    
+
     state_destroy(leaving);
 }
 
@@ -526,8 +535,12 @@ void initialize_file(char*filename)
     if(state) {
         syntaxerror("invalid call to initialize_file during parsing of another file");
     }
+    
+    active_namespaces = trie_new();
+
     new_state();
     state->package = internal_filename_package = strdup(filename);
+    state->allvars = dict_new();
     
     global->token2info = dict_lookup(global->file2token2info, 
                                      current_filename // use long version
@@ -543,7 +556,10 @@ void initialize_file(char*filename)
         state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
     } else {
         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+        if(!state->method)
+            syntaxerror("internal error: skewed tokencount");
         function_initvars(state->method, 0, 0, 1);
+        global->classinit = abc_initscript(global->file);
         global->init = abc_initscript(global->file);
     }
 }
@@ -553,8 +569,10 @@ 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;
@@ -577,51 +595,24 @@ void initialize_parser()
 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 is_parameter;
     methodstate_t*is_inner_method;
 } variable_t;
 
 static variable_t* find_variable(state_t*s, char*name)
 {
+    state_t*top = s;
     while(s) {
         variable_t*v = 0;
         v = dict_lookup(s->vars, name);
@@ -629,7 +620,7 @@ static variable_t* find_variable(state_t*s, char*name)
         if(s->new_vars) break;
         s = s->old;
     }
-    return 0;
+    return dict_lookup(top->allvars, name);
 }
 static variable_t* find_slot(state_t*s, const char*name)
 {
@@ -645,11 +636,32 @@ 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)
+{
+    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);
+        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()
 {
@@ -669,8 +681,10 @@ static variable_t* new_variable2(const char*name, classinfo_t*type, char init, c
     v->type = type;
     v->init = init;
  
-    if(name) 
+    if(name) {
         dict_put(state->vars, name, v);
+        dict_put(state->allvars, name, v);
+    }
 
     return v;
 }
@@ -680,15 +694,19 @@ static int new_variable(const char*name, classinfo_t*type, char init, char maybe
 }
 
 #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(TEMPVARNAME, 0, 0, 0);
+    parserassert(i);
+    return i;
 }
 
-code_t* var_block(code_t*body) 
+static code_t* var_block(code_t*body) 
 {
     code_t*c = 0;
     code_t*k = 0;
@@ -732,7 +750,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();
@@ -740,25 +758,26 @@ 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)
+static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
 {
-    syntaxerror("internal error in %s, %s:%d", f, file, line);
-}
-
-   
-static code_t* add_scope_code(code_t*c, methodstate_t*m)
-{
-    if(m->uses_slots || (m->late_binding && !m->inner)) {
+    if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
         c = abc_getlocal_0(c);
         c = abc_pushscope(c);
     }
     if(m->uses_slots) {
-        /* 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;
 }
@@ -767,7 +786,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) {
@@ -794,6 +813,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;
@@ -812,20 +844,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();
 }
 
@@ -844,7 +871,15 @@ static namespace_t modifiers2access(modifiers_t*mod)
         if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
             syntaxerror("invalid combination of access levels and namespaces");
         ns.access = ACCESS_NAMESPACE;
-        ns.name = mod->ns;
+        state_t*s = state;
+        const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
+        if(!url) {
+            /* shouldn't happen- the tokenizer only reports something as a namespace
+               if it was already registered */
+            trie_dump(active_namespaces);
+            syntaxerror("unknown namespace: %s", mod->ns);
+        }
+        ns.name = url;
     } else if(mod->flags&FLAG_PUBLIC)  {
         if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
             syntaxerror("invalid combination of access levels");
@@ -864,6 +899,11 @@ static namespace_t modifiers2access(modifiers_t*mod)
 }
 static slotinfo_t* find_class(const char*name);
 
+static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
+{
+    return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
+}
+
 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
 {
     if(var0) {
@@ -874,8 +914,6 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char
             index = new_variable((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;
         parserassert(!index);
     }
 
@@ -890,15 +928,11 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char
     if(params) {
         param_list_t*p=0;
         for(p=params->list;p;p=p->next) {
-            new_variable(p->param->name, p->param->type, 0, 1);
+            variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
+            v->is_parameter = 1;
         }
     }
 
-    if(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;
@@ -911,14 +945,19 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char
         l = l->next;
     }
     
+    if(as3_pass==2) {
+        m->scope_code = add_scope_code(m->scope_code, m, 0);
+    }
+    
     if(as3_pass==2 && m->slots) {
         /* exchange unresolved identifiers with the actual objects */
         DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
             if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
-                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);
+                classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
+                if(!type || type->kind != INFOTYPE_CLASS) {
+                    syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
                 }
+                v->type = type;
             }
         }
     }
@@ -966,6 +1005,7 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
         state->cls = rfx_calloc(sizeof(classstate_t));
         state->cls->init = rfx_calloc(sizeof(methodstate_t));
         state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
+        state->cls->static_init->variable_count=1;
         /* notice: we make no effort to initialize the top variable (local0) here,
            even though it has special meaning. We just rely on the facat
            that pass 1 won't do anything with variables */
@@ -983,6 +1023,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;
@@ -1011,14 +1052,12 @@ 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);
+        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) {
@@ -1032,58 +1071,12 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
             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);
+        NEW(parsedclass_t,p);
+        p->cls = state->cls->info;
+        p->abc = state->cls->abc;
+        list_append(global->classes, p);
 
         /* 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);
@@ -1094,23 +1087,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) {
@@ -1152,6 +1128,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);
@@ -1160,7 +1142,6 @@ void check_code_for_break(code_t*c)
     }
 }
 
-
 static void check_constant_against_type(classinfo_t*t, constant_t*c)
 {
 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
@@ -1216,18 +1197,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);
         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->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;
@@ -1244,7 +1222,7 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c
         // not sure wether to look into superclasses here, too
         minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
         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);
@@ -1265,10 +1243,11 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c
             }*/
         } else {
             minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
-            minfo->kind = INFOTYPE_SLOT; //hack
+            minfo->kind = INFOTYPE_VAR; //hack
             minfo->subtype = gs;
-            minfo->return_type = 0;
+            minfo->return_type = return_type;
         }
+
         /* can't assign a slot as getter and setter might have different slots */
         //minfo->slot = slot;
     }
@@ -1291,6 +1270,7 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
 
     new_state();
     state->new_vars = 1;
+    state->allvars = dict_new();
    
     if(as3_pass == 1) {
         state->method = rfx_calloc(sizeof(methodstate_t));
@@ -1330,7 +1310,8 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
     }
     new_state();
     state->new_vars = 1;
-    
+    state->allvars = dict_new();
+
     if(as3_pass == 1) {
         state->method = rfx_calloc(sizeof(methodstate_t));
         state->method->has_super = 0;
@@ -1365,7 +1346,6 @@ 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);
     } 
 }
@@ -1373,8 +1353,6 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
                           params_t*params, classinfo_t*return_type, code_t*body)
 {
-    int flags = mod?mod->flags:0;
-
     if(as3_pass==1) {
         // store inner methods in variables
         function_initvars(state->method, 0, 0, 0);
@@ -1427,6 +1405,8 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
             }
             state->method->uses_slots = i;
             dict_destroy(state->vars);state->vars = 0;
+            parserassert(state->new_vars);
+            dict_destroy(state->allvars);state->allvars = 0;
         }
         old_state();
         return 0;
@@ -1447,10 +1427,10 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
         } else if(state->method->is_constructor) {
             f = abc_class_getconstructor(state->cls->abc, type2);
         } else if(!state->method->is_global) {
-            namespace_t mname_ns = {state->method->info->access, ""};
+            namespace_t mname_ns = modifiers2access(mod);
             multiname_t mname = {QNAME, &mname_ns, 0, name};
 
-            if(flags&FLAG_STATIC)
+            if(mod->flags&FLAG_STATIC)
                 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
             else
                 f = abc_class_method(state->cls->abc, type2, &mname);
@@ -1466,7 +1446,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
         //flash doesn't seem to allow us to access function slots
         //state->method->info->slot = slot;
 
-        if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
+        if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
         if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
         if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
         if(params->varargs) f->flags |= METHOD_NEED_REST;
@@ -1519,11 +1499,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) {
@@ -1551,29 +1526,8 @@ 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)
@@ -1591,10 +1545,21 @@ 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_BOOLEAN(to))
+        return abc_convert_b(c);
+    if(TYPE_IS_STRING(to))
+        return abc_convert_s(c);
+    if(TYPE_IS_OBJECT(to))
+        return abc_convert_o(c);
 
     classinfo_t*supertype = from;
     while(supertype) {
@@ -1620,30 +1585,12 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*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);
-    return c;
-}
+        from->package, from->package[0]?".":"", from->name, 
+        to->package, to->package[0]?".":"", to->name);
 
-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;
 }
+/* move to ast.c todo end */
 
 char is_pushundefined(code_t*c)
 {
@@ -1755,175 +1702,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)
 {
@@ -1940,7 +1718,6 @@ char is_break_or_jump(code_t*c)
     return 0;
 }
 
-
 #define IS_FINALLY_TARGET(op) \
         ((op) == OPCODE___CONTINUE__ || \
          (op) == OPCODE___BREAK__ || \
@@ -2059,8 +1836,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 }} {{
 
 %}
 
@@ -2080,7 +1858,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
@@ -2092,13 +1870,15 @@ 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;}
               | ';'
 
 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
@@ -2125,7 +1905,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;}
@@ -2141,14 +1929,27 @@ PACKAGE_INITCODE: CODE_STATEMENT {
 
 /* ------------ 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
+    }
+};
+
+MAYBEEXPRESSION : '=' E {$$=$2;}
+                |       {$$=mkdummynode();}
 
 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
@@ -2165,11 +1966,6 @@ PASS1
     new_variable($1, 0, 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;
     if(state->method->uses_slots) {
@@ -2188,21 +1984,25 @@ PASS2
 
     $$ = slot?abc_getscopeobject(0, 1):0;
     
+    typedcode_t v = node_read($3);
+    if(!is_subtype_of(v.t, $2)) {
+        syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
+    }
     if($2) {
-        if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
-            $$ = code_append($$, $3.c);
-            $$ = converttype($$, $3.t, $2);
+        if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
+            $$ = code_append($$, v.c);
+            $$ = converttype($$, v.t, $2);
         } else {
-            code_free($3.c);
+            code_free(v.c);
             $$ = defaultvalue($$, $2);
         }
     } else {
-        if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
-            $$ = code_append($$, $3.c);
+        if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
+            $$ = code_append($$, v.c);
             $$ = abc_coerce_a($$);
         } else {
             // don't do anything
-            code_free($3.c);
+            code_free(v.c);
             code_free($$);
             $$ = 0;
             break;
@@ -2383,7 +2183,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__) {
@@ -2396,7 +2196,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);
 
@@ -2580,6 +2380,7 @@ WITH : WITH_HEAD CODEBLOCK {
 
 X_IDENTIFIER: T_IDENTIFIER
             | "package" {PASS12 $$="package";}
+            | T_NAMESPACE {PASS12 $$=$1;}
 
 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
 PACKAGE: X_IDENTIFIER             {PASS12 $$=strdup($1);}
@@ -2589,14 +2390,32 @@ 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" PACKAGEANDCLASS {
        PASS12
        slotinfo_t*s = registry_find($2->package, $2->name);
        if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
            as3_schedule_class($2->package, $2->name);
        }
-
-       PASS2
        classinfo_t*c = $2;
        if(!c) 
             syntaxerror("Couldn't import class\n");
@@ -2611,7 +2430,6 @@ IMPORT : "import" PACKAGE '.' '*' {
            as3_schedule_package($2);
        }
 
-       PASS2
        NEW(import_t,i);
        i->package = $2;
        state_has_imports();
@@ -2632,7 +2450,6 @@ MODIFIER_LIST : MODIFIER_LIST MODIFIER {
     $$.ns=$1.ns?$1.ns:$2.ns;
 
 }
-
 MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
          | KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
          | KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
@@ -2675,7 +2492,7 @@ 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
 
@@ -2706,81 +2523,119 @@ 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 && flags->flags&FLAG_STATIC) {
+                state->method = state->cls->static_init;
+            } else {
+                state->method = state->cls->init;
+            }
+        } else {
+            parserassert(state->method);
+        }
+    }
+};
+
 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");
-        }
-        info = varinfo_register_global(ns.access, state->package, $1);
-    }
+    if(as3_pass == 1) {
 
-    info->type = $2;
-    info->flags = 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");
+            }
+            info = varinfo_register_global(ns.access, state->package, $1);
+        }
 
-    /* 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);
+        info->type = $2;
+        info->flags = flags;
+        
+        dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
     }
 
-    *code = code_append(*code, c);
+    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;
+       
+        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);
+                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;
@@ -2788,26 +2643,36 @@ 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 {
+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_NAMESPACE {$$ = constant_new_namespace($1);}
+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(""));}
+
+/*
+CONSTANT : T_IDENTIFIER {
     if(!strcmp($1, "NaN")) {
         $$ = constant_new_float(__builtin_nan(""));
     } else {
         as3_warning("Couldn't evaluate constant value of %s", $1);
         $$ = constant_new_null($1);
     }
-}
+}*/
 
 /* ------------ classes and interfaces (body, functions) ------- */
 
@@ -2847,7 +2712,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;
@@ -2855,7 +2720,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;
@@ -2910,7 +2775,7 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
 
 /* ------------- package + class ids --------------- */
 
-CLASS: T_IDENTIFIER {
+CLASS: X_IDENTIFIER {
     PASS1 NEW(unresolvedinfo_t,c);
           memset(c, 0, sizeof(*c));
           c->kind = INFOTYPE_UNRESOLVED;
@@ -2929,7 +2794,7 @@ CLASS: T_IDENTIFIER {
     $$ = (classinfo_t*)s;
 }
 
-PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
+PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
     PASS1 NEW(unresolvedinfo_t,c);
           memset(c, 0, sizeof(*c));
           c->kind = INFOTYPE_UNRESOLVED;
@@ -2950,8 +2815,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_ANY;}
     /*
      |  "String"  {$$=registry_getstringclass();}
      |  "int"     {$$=registry_getintclass();}
@@ -2984,7 +2849,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;
@@ -3007,8 +2873,8 @@ NEW : "new" E XX MAYBE_PARAM_VALUES {
     }
    
     $$.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;
@@ -3020,8 +2886,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);
     }
@@ -3057,8 +2924,11 @@ 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;
@@ -3087,7 +2957,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);
     }
@@ -3101,7 +2972,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;
@@ -3117,532 +2988,206 @@ 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_minus {
+    $$ = 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_minus {
+    $$ = 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_minus {
+    $$ = 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_minus { 
+    $$ = $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);}
+
+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;
-            }
-
-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);
-            }
+// ----------------------- expression evaluation -------------------------------------
 
-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 : 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;}
 
-// 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 : CONSTANT { 
+    $$ = mkconstnode($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;
+    namespace_t ns = {ACCESS_PACKAGE, ""};
+    multiname_t m = {QNAME, &ns, 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;
-           }
+/* 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, $3);}
+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 = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
-
+              memberinfo_t*f = findmember_nsset(t, $3, 1);
               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;
+              $$ = mkdummynode();
               as3_warning("ignored @ operator");
            }
 
 E : E '.' '@' T_IDENTIFIER {
               // child attribute  TODO
-              $$.c = abc_pushundefined(0);
-              $$.t = 0;
+              $$ = mkdummynode();
               as3_warning("ignored .@ operator");
            }
 
 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
               // namespace declaration TODO
-              $$.c = abc_pushundefined(0);
-              $$.t = 0;
+              $$ = mkdummynode();
               as3_warning("ignored :: operator");
            }
 
 E : E ".." T_IDENTIFIER {
               // descendants TODO
-              $$.c = abc_pushundefined(0);
-              $$.t = 0;
+              $$ = mkdummynode();
               as3_warning("ignored .. operator");
            }
 
 E : E '.' '(' E ')' {
               // filter TODO
-              $$.c = abc_pushundefined(0);
-              $$.t = 0;
+              $$ = mkdummynode();
               as3_warning("ignored .() operator");
            }
 
-//VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
-
-
-
-E : E '.' T_IDENTIFIER {
-    $$.c = $1.c;
-    classinfo_t*t = $1.t;
+//E : E "::" '[' E ']' {
+//              // qualified expression TODO
+//              $$.c = abc_pushundefined(0);
+//              $$.t = 0;
+//              as3_warning("ignored ::[] operator");
+//           }
+
+MEMBER : E '.' T_IDENTIFIER {
+    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;
@@ -3652,13 +3197,16 @@ E : E '.' T_IDENTIFIER {
         if(t->subtype==INFOTYPE_UNRESOLVED) {
             syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
         }
-        memberinfo_t*f = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
+        memberinfo_t*f = findmember_nsset(t, $3, 1);
         char noslot = 0;
         if(f && !is_static != !(f->flags&FLAG_STATIC))
            noslot=1;
         if(f && f->slot && !noslot) {
             $$.c = abc_getslot($$.c, f->slot);
         } else {
+            if(!f) {
+                as3_softwarning("Access of undefined property '%s' in %s", $3, t->name);
+            }
             MEMBER_MULTINAME(m, f, $3);
             $$.c = abc_getproperty2($$.c, &m);
         }
@@ -3666,27 +3214,31 @@ 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_warning("Resolving %s on unknown type", $3);
         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
         $$.c = abc_getproperty2($$.c, &m);
         $$.c = abc_coerce_a($$.c);
-        $$.t = registry_getanytype();
+        $$.t = TYPE_ANY;
     }
 }
 
@@ -3703,13 +3255,16 @@ VAR_READ : T_IDENTIFIER {
         unknown_variable($1);
     }
    
-    /* let the compiler know that it might check the current directory/package
+    /* let the compiler know that it might want to check the current directory/package
        for this identifier- maybe there's a file $1.as defining $1. */
     as3_schedule_class_noerror(state->package, $1);
     PASS2
 
-    $$.t = 0;
-    $$.c = 0;
+    typedcode_t o;
+    o.t = 0;
+    o.c = 0;
+    $$ = 0;
+
     slotinfo_t*a = 0;
     memberinfo_t*f = 0;
 
@@ -3717,65 +3272,88 @@ VAR_READ : T_IDENTIFIER {
     /* look at variables */
     if((v = find_variable(state, $1))) {
         // $1 is a local variable
-        $$.c = abc_getlocal($$.c, v->index);
-        $$.t = v->type;
+        o.c = abc_getlocal(o.c, v->index);
+        o.t = v->type;
+        $$ = mkcodenode(o);
         break;
     }
     if((v = find_slot(state, $1))) {
-        $$.c = abc_getscopeobject($$.c, 1);
-        $$.c = abc_getslot($$.c, v->index);
-        $$.t = v->type;
+        o.c = abc_getscopeobject(o.c, 1);
+        o.c = abc_getslot(o.c, v->index);
+        o.t = v->type;
+        $$ = mkcodenode(o);
         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 = registry_findmember_nsset(state->cls->info, state->active_namespaces, $1, 1)) &&
-        (f->flags&FLAG_STATIC) >= i_am_static) {
-        // $1 is a function in this class
+    if(!state->method->inner && 
+        state->cls && 
+        (f = findmember_nsset(state->cls->info, $1, 1)))
+    {
+        // $1 is a member or attribute 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;
+        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) {
+                $$ = mkconstnode(v->value);
+                break;
+            }
+        }
+       
+        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, $1};
+                o.c = abc_findpropstrict2(o.c, &m);
+                o.c = abc_getproperty2(o.c, &m);
+                $$ = mkcodenode(o);
+                break;
+            } else if(f->slot>0) {
+                o.c = abc_getlocal_0(o.c);
+                o.c = abc_getslot(o.c, f->slot);
+                $$ = mkcodenode(o);
+                break;
+            } else {
+                namespace_t ns = {f->access, f->package};
+                multiname_t m = {QNAME, &ns, 0, $1};
+                o.c = abc_getlocal_0(o.c);
+                o.c = abc_getproperty2(o.c, &m);
+                $$ = mkcodenode(o);
+                break;
+            }
         }
     } 
     
     /* look at actual classes, in the current package and imported */
     if((a = find_class($1))) {
-        $$ = push_class(a);
+        o = push_class(a);
+        $$ = mkcodenode(o);
         break;
     }
 
     /* look through package prefixes */
-    if(dict_contains(state->import_toplevel_packages, $1)) {
-        $$.c = abc___pushpackage__($$.c, $1);
-        $$.t = 0;
+    if(dict_contains(state->import_toplevel_packages, $1) || 
+       registry_ispackage($1)) {
+        o.c = abc___pushpackage__(o.c, $1);
+        o.t = 0;
+        $$ = mkcodenode(o); //?
         break;
     }
 
@@ -3787,9 +3365,11 @@ VAR_READ : T_IDENTIFIER {
                 
         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
 
-        $$.t = 0;
-        $$.c = abc_findpropstrict2($$.c, &m);
-        $$.c = abc_getproperty2($$.c, &m);
+        o.t = 0;
+        o.c = abc_findpropstrict2(o.c, &m);
+        o.c = abc_getproperty2(o.c, &m);
+        $$ = mkcodenode(o);
+        break;
     }
 }
 
@@ -3799,7 +3379,7 @@ NAMESPACE_ID : "namespace" T_IDENTIFIER {
     PASS12
     NEW(namespace_decl_t,n);
     n->name = $2;
-    n->url = 0;
+    n->url = $2;
     $$=n;
 }
 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
@@ -3818,20 +3398,47 @@ NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
 }
 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
     PASS12
-    list_append(state->new_namespaces, $2);
-    tokenizer_register_namespace($2->name);
+    trie_put(active_namespaces, $2->name, (void*)$2->url);
+
+    namespace_t access = modifiers2access(&$1);
+    varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
+    var->type = TYPE_NAMESPACE;
+    namespace_t ns;
+    ns.access = ACCESS_NAMESPACE;
+    ns.name = $2->url;
+    var->value = constant_new_namespace(&ns);
+
     $$=0;
 }
 
+%code {
+    void add_active_url(const char*url)
+    {
+        NEW(namespace_t,n);
+        n->name = url;
+        list_append(state->active_namespace_urls, n);
+    }
+};
+
 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
     PASS12
-    NEW(namespace_decl_t,n);
-    n->name = $3->name;
-    n->url = 0;
-    /* FIXME: for pass2, we should now try to figure out what the URL of 
-              this thing is */
-    list_append(state->new_namespaces, n);
-    tokenizer_register_namespace($3->name);
+    const char*url = $3->name;
+
+    varinfo_t*s = (varinfo_t*)$3;
+    if(s->kind == INFOTYPE_UNRESOLVED) {
+        s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
+        if(!s)
+            syntaxerror("Couldn't resolve namespace %s", $3->name);
+    }
+
+    if(!s || s->kind != INFOTYPE_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);
+    url = s->value->ns->name;
+
+    trie_put(active_namespaces, $3->name, (void*)url);
+    add_active_url(url);
     $$=0;
 }