track variables in first pass
[swftools.git] / lib / as3 / parser.y
index b0083d7..82cd3b5 100644 (file)
@@ -139,6 +139,7 @@ extern int a3_lex();
 %token<token> KW_IN "in"
 %token<token> KW_AS "as"
 
+%token<token> T_DICTSTART "{ (dictionary)"
 %token<token> T_EQEQ "=="
 %token<token> T_EQEQEQ "==="
 %token<token> T_NE "!="
@@ -151,6 +152,7 @@ extern int a3_lex();
 %token<token> T_MULBY "*="
 %token<token> T_PLUSBY "+=" 
 %token<token> T_MINUSBY "-="
+%token<token> T_XORBY "^="
 %token<token> T_SHRBY ">>="
 %token<token> T_SHLBY "<<="
 %token<token> T_USHRBY ">>>="
@@ -239,9 +241,9 @@ extern int a3_lex();
 
 %left '('
 %left new2
-%left '[' ']' "new" '{' '.' ".." "::" '@'
+%left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
 
-%nonassoc T_IDENTIFIER
+%left T_IDENTIFIER
 %left above_identifier
 %left below_else
 %nonassoc "else"
@@ -292,18 +294,23 @@ typedef struct _import {
 
 DECLARE_LIST(import);
 
+DECLARE(methodstate);
+DECLARE_LIST(methodstate);
+
 typedef struct _classstate {
     /* class data */
     classinfo_t*info;
     abc_class_t*abc;
-    code_t*init;
-    code_t*static_init;
+   
+    methodstate_t*init;
+    methodstate_t*static_init;
+    //code_t*init;
+    //code_t*static_init;
+
     char has_constructor;
 } classstate_t;
 
-DECLARE_LIST(methodstate);
-
-typedef struct _methodstate {
+struct _methodstate {
     /* method data */
     methodinfo_t*info;
     char late_binding;
@@ -316,10 +323,11 @@ typedef struct _methodstate {
     abc_method_t*abc;
     int var_index; // for inner methods
 
+    code_t*header;
     abc_exception_list_t*exceptions;
     
     methodstate_list_t*innerfunctions;
-} methodstate_t;
+};
 
 typedef struct _state {
     struct _state*old;
@@ -452,7 +460,7 @@ static void old_state()
         free(leaving->method);
         leaving->method=0;
     }
-    if(leaving->cls && leaving->cls != state->cls) {
+    if(as3_pass>1 && leaving->cls && leaving->cls != state->cls) {
         free(leaving->cls);
         leaving->cls=0;
     }
@@ -460,6 +468,11 @@ static void old_state()
     state_destroy(leaving);
 }
 
+static code_t* method_header(methodstate_t*m);
+static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
+static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
+
+
 static char* internal_filename_package = 0;
 void initialize_file(char*filename)
 {
@@ -469,9 +482,6 @@ void initialize_file(char*filename)
     new_state();
     state->package = internal_filename_package = strdup(filename);
     
-    state->method = rfx_calloc(sizeof(methodstate_t));
-    state->method->variable_count = 1;
-
     global->token2info = dict_lookup(global->file2token2info, 
                                      current_filename // use long version
                                     );
@@ -479,6 +489,16 @@ void initialize_file(char*filename)
         global->token2info = dict_new2(&ptr_type);
         dict_put(global->file2token2info, current_filename, global->token2info);
     }
+  
+    if(as3_pass==1) {
+        state->method = rfx_calloc(sizeof(methodstate_t));
+        dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
+    } else {
+        state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+        function_initvars(state->method, 0, 0, 1);
+        global->init = abc_initscript(global->file);
+        state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
+    }
 }
 
 void finish_file()
@@ -486,10 +506,15 @@ void finish_file()
     if(!state || state->level!=1) {
         syntaxerror("unexpected end of file in pass %d", as3_pass);
     }
-    free(state->method);state->method=0;
 
-    //free(state->package);state->package=0; // used in registry
+    if(as3_pass==2) {
+        code_t*header = method_header(state->method);
+        code_t*c = wrap_function(header, 0, global->init->method->body->code);
+        global->init->method->body->code = c;
+        free(state->method);state->method=0;
+    }
 
+    //free(state->package);state->package=0; // used in registry
     state_destroy(state);state=0;
 }
 
@@ -500,23 +525,10 @@ void initialize_parser()
     global->file->flags &= ~ABCFILE_LAZY;
     global->file2token2info = dict_new();
     global->token2info = 0;
-    
-    global->init = abc_initscript(global->file);
-    code_t*c = global->init->method->body->code;
-    c = abc_getlocal_0(c);
-    c = abc_pushscope(c);
-    global->init->method->body->code = c;
 }
 
 void* finish_parser()
 {
-    code_t*c = global->init->method->body->code;
-    /*c = abc_findpropstrict(c, "[package]::trace");
-      c = abc_pushstring(c, "[leaving global init function]");
-      c = abc_callpropvoid(c, "[package]::trace", 1);*/
-    c = abc_returnvoid(c);
-    global->init->method->body->code = c;
-
     dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
 
     global->token2info=0;
@@ -554,11 +566,11 @@ static void xx_scopetest()
     c = abc_iftrue(c,xx);*/
 }
 
-
 typedef struct _variable {
     int index;
     classinfo_t*type;
     char init;
+    methodstate_t*method;
 } variable_t;
 
 static variable_t* find_variable(char*name)
@@ -595,6 +607,7 @@ static int new_variable(const char*name, classinfo_t*type, char init)
     v->index = state->method->variable_count;
     v->type = type;
     v->init = init;
+    v->method = state->method;
     
     dict_put(state->vars, name, v);
 
@@ -661,23 +674,18 @@ static void parsererror(const char*file, int line, const char*f)
 }
 
    
-code_t* method_header()
+static code_t* method_header(methodstate_t*m)
 {
     code_t*c = 0;
-    if(state->method->late_binding && !state->method->inner) {
+    if(m->late_binding && !m->inner) {
         c = abc_getlocal_0(c);
         c = abc_pushscope(c);
     }
-    /*if(state->method->innerfunctions) {
+    /*if(m->innerfunctions) {
         c = abc_newactivation(c);
         c = abc_pushscope(c);
     }*/
-    if(state->method->is_constructor && !state->method->has_super) {
-        // call default constructor
-        c = abc_getlocal_0(c);
-        c = abc_constructsuper(c, 0);
-    }
-    methodstate_list_t*l = state->method->innerfunctions;
+    methodstate_list_t*l = m->innerfunctions;
     while(l) {
         parserassert(l->methodstate->abc);
         c = abc_newfunction(c, l->methodstate->abc);
@@ -685,8 +693,17 @@ code_t* method_header()
         free(l->methodstate);l->methodstate=0;
         l = l->next;
     }
-    list_free(state->method->innerfunctions);
-    state->method->innerfunctions = 0;
+    if(m->header) {
+        c = code_append(c, m->header);
+        m->header = 0;
+    }
+    if(m->is_constructor && !m->has_super) {
+        // call default constructor
+        c = abc_getlocal_0(c);
+        c = abc_constructsuper(c, 0);
+    }
+    list_free(m->innerfunctions);
+    m->innerfunctions = 0;
     return c;
 }
     
@@ -747,6 +764,37 @@ static int flags2access(int flags)
     return access;
 }
 
+static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
+{
+    if(var0) {
+        int index = -1;
+        if(m->inner)
+            index = new_variable("this", 0, 0);
+        else if(!m->is_global)
+            index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0);
+        else
+            index = new_variable("globalscope", 0, 0);
+        if(index)
+            *(int*)0=0;
+        parserassert(!index);
+    }
+
+    if(params) {
+        param_list_t*p=0;
+        for(p=params->list;p;p=p->next) {
+            new_variable(p->param->name, p->param->type, 0);
+        }
+    }
+    
+    methodstate_list_t*l = m->innerfunctions;
+    while(l) {
+        methodstate_t*m = l->methodstate;
+        m->var_index = new_variable(m->info->name, TYPE_FUNCTION(m->info), 0);
+        l = l->next;
+    }
+}
+
+
 char*as3_globalclass=0;
 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements)
 {
@@ -754,8 +802,6 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
         syntaxerror("inner classes now allowed"); 
     }
     new_state();
-    state->cls = rfx_calloc(sizeof(classstate_t));
-
     token_list_t*t=0;
     classinfo_list_t*mlist=0;
 
@@ -780,9 +826,18 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     }
 
     if(as3_pass==1) {
-        state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
-        state->method->variable_count = 1;
-        dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
+        state->cls = rfx_calloc(sizeof(classstate_t));
+        state->cls->init = rfx_calloc(sizeof(methodstate_t));
+        state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
+        /* 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 */
+        
+        dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
+
+        /* set current method to constructor- all code within the class-level (except
+           static variable initializations) will be executed during construction time */
+        state->method = state->cls->init;
 
         if(registry_find(package, classname)) {
             syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
@@ -794,10 +849,13 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     }
     
     if(as3_pass == 2) {
-        state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
-
-        state->cls->info = (classinfo_t*)registry_find(package, classname);
-        parserassert((int)state->cls->info);
+        state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+        
+        state->method = state->cls->init;
+        parserassert(state->cls && state->cls->info);
+       
+        function_initvars(state->cls->init, 0, 0, 1);
+        function_initvars(state->cls->static_init, 0, 0, 0);
 
         if(extends && (extends->flags & FLAG_FINAL))
             syntaxerror("Can't extend final class '%s'", extends->name);
@@ -892,6 +950,19 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     }
 }
 
+static void setstaticfunction(int x)
+{
+    if(state->cls) {
+        if(x&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) {
@@ -899,23 +970,23 @@ static void endclass()
             code_t*c = 0;
             c = abc_getlocal_0(c);
             c = abc_constructsuper(c, 0);
-            state->cls->init = code_append(state->cls->init, c);
+            state->cls->init->header = code_append(state->cls->init->header, c);
+            state->cls->has_constructor=1;
         }
-        if(!state->method->late_binding) {
-            // class initialization code uses late binding
-            code_t*c = 0;
-            c = abc_getlocal_0(c);
-            c = abc_pushscope(c);
-            state->cls->static_init = code_append(c, state->cls->static_init);
-        }
-
         if(state->cls->init) {
-            abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
-            m->body->code = wrap_function(0, state->cls->init, m->body->code);
+            if(state->cls->info->flags&FLAG_INTERFACE) {
+                if(state->cls->init->header) 
+                    syntaxerror("interface can not have class-level code");
+            } else {
+                abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
+                code_t*c = method_header(state->cls->init);
+                m->body->code = wrap_function(c, 0, m->body->code);
+            }
         }
         if(state->cls->static_init) {
             abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
-            m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
+            code_t*c = method_header(state->cls->static_init);
+            m->body->code = wrap_function(c, 0, m->body->code);
         }
     }
 
@@ -947,7 +1018,7 @@ static void check_constant_against_type(classinfo_t*t, constant_t*c)
              || c->type == CONSTANT_UINT);
    } else if(TYPE_IS_UINT(t)) {
         xassert(c->type == CONSTANT_UINT ||
-               (c->type == CONSTANT_INT && c->i>0));
+               (c->type == CONSTANT_INT && c->i>=0));
    } else if(TYPE_IS_INT(t)) {
         xassert(c->type == CONSTANT_INT);
    } else if(TYPE_IS_BOOLEAN(t)) {
@@ -1042,31 +1113,9 @@ static methodinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
     return minfo;
 }
 
-static void function_initvars(params_t*params, int flags)
-{
-    if(state->method->inner)
-        new_variable("this", 0, 0);
-    else if(!state->method->is_global)
-        new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
-    else
-        new_variable("globalscope", 0, 0);
-
-    param_list_t*p=0;
-    for(p=params->list;p;p=p->next) {
-        new_variable(p->param->name, p->param->type, 0);
-    }
-    
-    methodstate_list_t*l = state->method->innerfunctions;
-    while(l) {
-        methodstate_t*m = l->methodstate;
-        m->var_index = new_variable(m->info->name, TYPE_FUNCTION(m->info), 0);
-        l = l->next;
-    }
-}
-
 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
 {
-    parserassert(state->method && state->method->info);
+    //parserassert(state->method && state->method->info);
 
     methodstate_t*parent_method = state->method;
 
@@ -1086,20 +1135,26 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
         state->method->abc = rfx_calloc(sizeof(abc_method_t));
 
         NEW(methodinfo_t,minfo);
+        minfo->kind = INFOTYPE_METHOD;
+        minfo->access = ACCESS_PACKAGEINTERNAL;
         minfo->name = name;
         state->method->info = minfo;
 
-        list_append(parent_method->innerfunctions, state->method);
+        if(parent_method)
+            list_append(parent_method->innerfunctions, state->method);
 
         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
+        
+        function_initvars(state->method, params, 0, 1);
     }
 
     if(as3_pass == 2) {
         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+        state->method->variable_count = 0;
         parserassert(state->method);
 
         state->method->info->return_type = return_type;
-        function_initvars(params, 0);
+        function_initvars(state->method, params, 0, 1);
     }
 }
 
@@ -1114,7 +1169,6 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
     if(as3_pass == 1) {
         state->method = rfx_calloc(sizeof(methodstate_t));
         state->method->has_super = 0;
-        state->method->variable_count = 0;
 
         if(state->cls) {
             state->method->is_constructor = !strcmp(state->cls->info->name,name);
@@ -1127,12 +1181,15 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
 
         return_type = 0;
         state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
+       
+        function_initvars(state->method, params, flags, 1);
         
         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
     }
 
     if(as3_pass == 2) {
         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+        state->method->variable_count = 0;
         parserassert(state->method);
 
         if(state->cls) {
@@ -1145,7 +1202,7 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
         }
         
         state->method->info->return_type = return_type;
-        function_initvars(params, flags);
+        function_initvars(state->method, params, flags, 1);
     } 
 }
 
@@ -1153,7 +1210,6 @@ static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset,
                           params_t*params, classinfo_t*return_type, code_t*body)
 {
     if(as3_pass==1) {
-        old_state();
         return 0;
     }
 
@@ -1216,7 +1272,6 @@ static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset,
             syntaxerror("interface methods can't have a method body");
     }
        
-    old_state();
     return f;
 }
 
@@ -1319,8 +1374,11 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
         return c;
     if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to))
         return c;
-    syntaxerror("can't convert type %s to %s", from->name, to->name);
-    return 0; // make gcc happy
+
+    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;
 }
 
 code_t*defaultvalue(code_t*c, classinfo_t*type)
@@ -1740,6 +1798,8 @@ CODE_STATEMENT: WITH
 CODE_STATEMENT: TRY
 CODE_STATEMENT: VOIDEXPRESSION 
 CODE_STATEMENT: USE_NAMESPACE
+CODE_STATEMENT: '{' CODE '}' {$$=$2;}
+CODE_STATEMENT: '{' '}' {$$=0;}
 
 // code which may appear anywhere
 CODEPIECE: ';' {$$=0;}
@@ -1753,8 +1813,8 @@ CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
 
 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
 
-CODEBLOCK :  '{' CODE '}' {$$=$2;}
-CODEBLOCK :  '{' '}'      {$$=0;}
+//CODEBLOCK :  '{' CODE '}' {$$=$2;}
+//CODEBLOCK :  '{' '}'      {$$=0;}
 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
 
@@ -1784,14 +1844,17 @@ VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
 
 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
 {
+PASS12
     if(variable_exists($1))
         syntaxerror("Variable %s already defined", $1);
+PASS1
+    new_variable($1, $2, 1);
+PASS2
    
     if(!is_subtype_of($3.t, $2)) {
         syntaxerror("Can't convert %s to %s", $3.t->name, 
                                               $2->name);
     }
-
     int index = new_variable($1, $2, 1);
     
     if($2) {
@@ -1829,7 +1892,7 @@ MAYBEELSE:  %prec below_else {$$ = code_new();}
 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
 
-IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
+IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
      
     $$ = code_new();
     $$ = code_append($$, $4.c);
@@ -1845,7 +1908,7 @@ IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
         myjmp->branch = $$ = abc_nop($$);
     }
     $$ = var_block($$);
-    old_state();
+    PASS12 old_state();
 }
 
 FOR_INIT : {$$=code_new();}
@@ -1853,15 +1916,19 @@ FOR_INIT : VARIABLE_DECLARATION
 FOR_INIT : VOIDEXPRESSION
 
 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
+//       (I don't see any easy way to revolve this conflict otherwise, as we
+//        can't touch VAR_READ without upsetting the precedence about "return")
 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
+    PASS12
     $$=$2;new_variable($2,$3,1);
 }
 FOR_IN_INIT : T_IDENTIFIER {
+    PASS12
     $$=$1;
 }
 
-FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
-FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
+FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;}
+FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;}
 
 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
@@ -1880,7 +1947,7 @@ FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
     myif->branch = out;
 
     $$ = var_block($$);
-    old_state();
+    PASS12 old_state();
 }
 
 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
@@ -1920,13 +1987,14 @@ FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
     myif->branch = out;
 
     $$ = var_block($$);
-    old_state();
 
     free(tmp1name);
     free(tmp2name);
+
+    PASS12 old_state();
 }
 
-WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
+WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK {
 
     $$ = code_new();
 
@@ -1942,10 +2010,10 @@ WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
     continuejumpsto($$, $1, cont);
 
     $$ = var_block($$);
-    old_state();
+    PASS12 old_state();
 }
 
-DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
+DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
     $$ = code_new();
     code_t*loopstart = $$ = abc_label($$);
     $$ = code_append($$, $3);
@@ -1957,7 +2025,7 @@ DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
     continuejumpsto($$, $1, cont);
     
     $$ = var_block($$);
-    old_state();
+    PASS12 old_state();
 }
 
 BREAK : "break" %prec prec_none {
@@ -1994,7 +2062,7 @@ CASE: "case" E ':' MAYBECODE {
 DEFAULT: "default" ':' MAYBECODE {
     $$ = $3;
 }
-SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
+SWITCH : T_SWITCH '(' {PASS12 new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
     $$=$4.c;
     $$ = code_append($$, $7);
     code_t*out = $$ = abc_pop($$);
@@ -2018,12 +2086,12 @@ SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
     }
    
     $$ = var_block($$);
-    old_state();
+    PASS12 old_state();
 }
 
 /* ------------ try / catch /finally ---------------- */
 
-CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);} 
+CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();state->exception_name=$3;new_variable($3, $4, 0);} 
         '{' MAYBECODE '}' {
     namespace_t name_ns = {ACCESS_PACKAGE, ""};
     multiname_t name = {QNAME, &name_ns, 0, $3};
@@ -2041,13 +2109,12 @@ CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name
     c = abc_kill(c, i);
 
     c = var_block(c);
-    old_state();
+    PASS12 old_state();
 }
-FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
+FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' {
     $4 = var_block($4);
     if(!$4) {
         $$=0;
-        old_state();
     } else {
         NEW(abc_exception_t, e)
         e->exc_type = 0; //all exceptions
@@ -2055,9 +2122,9 @@ FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
         e->target = 0;
         e->to = abc_nop(0);
         e->to = code_append(e->to, $4);
-        old_state();
         $$ = e;
     }
+    PASS12 old_state();
 }
 
 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
@@ -2080,7 +2147,7 @@ CATCH_FINALLY_LIST: FINALLY {
     }
 }
 
-TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
+TRY : "try" '{' {PASS12 new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
     code_t*out = abc_nop(0);
 
     code_t*start = abc_nop(0);
@@ -2120,7 +2187,7 @@ TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
     list_concat(state->method->exceptions, $6.l);
    
     $$ = var_block($$);
-    old_state();
+    PASS12 old_state();
 }
 
 /* ------------ throw ------------------------------- */
@@ -2161,8 +2228,9 @@ PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
                                 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
 
 IMPORT : "import" PACKAGEANDCLASS {
-       PASS1 
-       if(!registry_find($2->package, $2->name)) {
+       PASS12
+       slotinfo_t*s = registry_find($2->package, $2->name);
+       if(!s) {// || !(s->flags&FLAG_BUILTIN)) {
            as3_schedule_class($2->package, $2->name);
        }
 
@@ -2175,7 +2243,7 @@ IMPORT : "import" PACKAGEANDCLASS {
        $$=0;
 }
 IMPORT : "import" PACKAGE '.' '*' {
-       PASS1 
+       PASS12
        if(strncmp("flash.", $2, 6)) {
            as3_schedule_package($2);
        }
@@ -2239,9 +2307,9 @@ CLASS_BODY_ITEM : SLOT_DECLARATION
 CLASS_BODY_ITEM : FUNCTION_DECLARATION
 
 CLASS_BODY_ITEM : CODE_STATEMENT {
-    code_t*c = state->cls->static_init;
+    code_t*c = state->cls->static_init->header;
     c = code_append(c, $1);  
-    state->cls->static_init = c;
+    state->cls->static_init->header = c;
 }
 
 MAYBE_INTERFACE_BODY : 
@@ -2260,14 +2328,15 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI
     }
     startfunction(0,$1,$3,$4,&$6,$8);
     endfunction(0,$1,$3,$4,&$6,$8, 0);
-    list_deep_free($6.list);
+
+    old_state();list_deep_free($6.list);
 }
 
 /* ------------ classes and interfaces (body, slots ) ------- */
 
 VARCONST: "var" | "const"
 
-SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1);} MAYBETYPE MAYBEEXPRESSION {
     int flags = $1;
     U8 access = flags2access($1);
 
@@ -2277,7 +2346,6 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSIO
         if(i) {
             check_override(i, flags);
         }
-
         info = varinfo_register_onclass(state->cls->info, access, $3);
     } else {
         slotinfo_t*i = registry_find(state->package, $3);
@@ -2287,7 +2355,7 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSIO
         info = varinfo_register_global(access, state->package, $3);
     }
 
-    info->type = $4;
+    info->type = $5;
     info->flags = flags;
 
     /* slot name */
@@ -2304,16 +2372,16 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSIO
     } else if(flags&FLAG_STATIC) {
         // static variable
         traits = &state->cls->abc->static_traits;
-        code = &state->cls->static_init;
+        code = &state->cls->static_init->header;
     } else {
         // instance variable
         traits = &state->cls->abc->traits;
-        code = &state->cls->init;
+        code = &state->cls->init->header;
     }
     
     trait_t*t=0;
-    if($4) {
-        MULTINAME(m, $4);
+    if($5) {
+        MULTINAME(m, $5);
         t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
     } else {
         t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
@@ -2322,10 +2390,10 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSIO
     
     /* initalization code (if needed) */
     code_t*c = 0;
-    if($5.c && !is_pushundefined($5.c)) {
+    if($6.c && !is_pushundefined($6.c)) {
         c = abc_getlocal_0(c);
-        c = code_append(c, $5.c);
-        c = converttype(c, $5.t, $4);
+        c = code_append(c, $6.c);
+        c = converttype(c, $6.t, $5);
         c = abc_setslot(c, t->slot_id);
     }
 
@@ -2336,6 +2404,7 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSIO
     }
 
     $$=0;
+    setstaticfunction(0);
 }
 
 /* ------------ constants -------------------------------------- */
@@ -2397,19 +2466,19 @@ PARAM_LIST: PARAM {
 }
 
 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
-     PASS1 $$=0;
-     PASS2
-     $$ = malloc(sizeof(param_t));
+     PASS12
+     $$ = rfx_calloc(sizeof(param_t));
      $$->name=$1;
      $$->type = $3;
+     PASS2
      $$->value = $4;
 }
 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
-     PASS1 $$=0;
-     PASS2
-     $$ = malloc(sizeof(param_t));
+     PASS12
+     $$ = rfx_calloc(sizeof(param_t));
      $$->name=$1;
      $$->type = TYPE_ANY;
+     PASS2
      $$->value = $2;
 }
 GETSET : "get" {$$=$1;}
@@ -2419,16 +2488,14 @@ GETSET : "get" {$$=$1;}
 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
                       MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}' 
 {
-    PASS1 old_state();list_deep_free($6.list);
-    PASS2
     if(!state->method->info) syntaxerror("internal error");
     
-    code_t*c = method_header();
+    code_t*c = method_header(state->method);
     c = wrap_function(c, 0, $11);
 
     endfunction(0,$1,$3,$4,&$6,$8,c);
-    list_deep_free($6.list);
     $$=0;
+    PASS12 old_state();list_deep_free($6.list);
 }
 
 MAYBE_IDENTIFIER: T_IDENTIFIER
@@ -2436,20 +2503,18 @@ MAYBE_IDENTIFIER: {PASS12 $$=0;}
 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE 
                '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
 {
-    PASS1 old_state();list_deep_free($4.list);
-    PASS2
     methodinfo_t*f = state->method->info;
-    if(!f) syntaxerror("internal error");
+    if(!f || !f->kind) syntaxerror("internal error");
     
-    code_t*c = method_header();
+    code_t*c = method_header(state->method);
     c = wrap_function(c, 0, $9);
 
     int index = state->method->var_index;
     endfunction(0,0,0,$2,&$4,$6,c);
-    list_deep_free($4.list);
     
     $$.c = abc_getlocal(0, index);
     $$.t = TYPE_FUNCTION(f);
+    PASS12 old_state();list_deep_free($4.list);
 }
 
 
@@ -2458,9 +2523,8 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
 CLASS: T_IDENTIFIER {
     PASS1 $$=0;
     PASS2
-    /* try current package */
     slotinfo_t*s = find_class($1);
-    if(!s) syntaxerror("Could not find class/method %s\n", $1);
+    if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
     $$ = (classinfo_t*)s;
 }
 
@@ -2946,7 +3010,7 @@ EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
 //MAYBECOMMA: ','
 //MAYBECOMMA:
 
-E : '{' MAYBE_EXPRPAIR_LIST '}' {
+E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
     $$.c = code_new();
     $$.c = code_append($$.c, $2.cc);
     $$.c = abc_newobject($$.c, $2.len/2);
@@ -3001,6 +3065,12 @@ E : E "|=" E {
                $$.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;