fixed vertical alignment bug
[swftools.git] / lib / as3 / parser.y
index 8c99eca..d2188ef 100644 (file)
     double number_float;
     code_t*code;
     typedcode_t value;
-    typedcode_list_t*value_list;
+    //typedcode_list_t*value_list;
+    codeandnumber_t value_list;
     param_t* param;
     params_t params;
     string_t str;
     char*id;
     constant_t*constant;
+    for_start_t for_start;
+    abc_exception_t *exception;
+    abc_exception_list_t *exception_list;
 }
 
 
 %token<id> T_DO "do"
 %token<id> T_SWITCH "switch"
 
-%token<token> KW_IMPLEMENTS
+%token<token> KW_IMPLEMENTS "implements"
 %token<token> KW_NAMESPACE "namespace"
 %token<token> KW_PACKAGE "package"
-%token<token> KW_PROTECTED
-%token<token> KW_PUBLIC
-%token<token> KW_PRIVATE
+%token<token> KW_PROTECTED "protected"
+%token<token> KW_PUBLIC "public"
+%token<token> KW_PRIVATE "private"
 %token<token> KW_USE "use"
-%token<token> KW_INTERNAL
+%token<token> KW_INTERNAL "internal"
 %token<token> KW_NEW "new"
-%token<token> KW_NATIVE
+%token<token> KW_NATIVE "native"
 %token<token> KW_FUNCTION "function"
 %token<token> KW_UNDEFINED "undefined"
 %token<token> KW_CONTINUE "continue"
@@ -93,7 +97,9 @@
 %token<token> KW_CASE "case"
 %token<token> KW_SET "set"
 %token<token> KW_VOID "void"
-%token<token> KW_STATIC
+%token<token> KW_THROW "throw"
+%token<token> KW_STATIC "static"
+%token<token> KW_WITH "with"
 %token<token> KW_INSTANCEOF "instanceof"
 %token<token> KW_IMPORT "import"
 %token<token> KW_RETURN "return"
 %token<token> KW_NULL "null"
 %token<token> KW_VAR "var"
 %token<token> KW_DYNAMIC "dynamic"
-%token<token> KW_OVERRIDE
-%token<token> KW_FINAL
+%token<token> KW_OVERRIDE "override"
+%token<token> KW_FINAL "final"
+%token<token> KW_EACH "each"
 %token<token> KW_GET "get"
 %token<token> KW_TRY "try"
 %token<token> KW_SUPER "super"
-%token<token> KW_EXTENDS
+%token<token> KW_EXTENDS "extends"
 %token<token> KW_FALSE "false"
 %token<token> KW_TRUE "true"
 %token<token> KW_BOOLEAN "Boolean"
 %token<token> KW_ELSE  "else"
 %token<token> KW_BREAK   "break"
 %token<token> KW_IS "is"
+%token<token> KW_IN "in"
 %token<token> KW_AS "as"
 
 %token<token> T_EQEQ "=="
 %token<token> T_USHR ">>>"
 %token<token> T_SHR ">>"
 
-%type <id> X_IDENTIFIER PACKAGE
+%type <for_start> FOR_START
+%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
 %type <token> VARCONST
 %type <code> CODE
-%type <code> CODEPIECE
-%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
-%type <token> PACKAGE_DECLARATION
-%type <token> FUNCTION_DECLARATION
-%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
-%type <token> CLASS_DECLARATION
-%type <token> NAMESPACE_DECLARATION
-%type <token> INTERFACE_DECLARATION
+%type <code> CODEPIECE CODE_STATEMENT
+%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
+%type <code> PACKAGE_DECLARATION SLOT_DECLARATION
+%type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
+%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW 
+%type <exception> CATCH
+%type <exception_list> CATCH_LIST
+%type <code> CLASS_DECLARATION
+%type <code> NAMESPACE_DECLARATION
+%type <code> INTERFACE_DECLARATION
 %type <code> VOIDEXPRESSION
 %type <value> EXPRESSION NONCOMMAEXPRESSION
 %type <value> MAYBEEXPRESSION
 %type <value> E DELETE
 %type <value> CONSTANT
-%type <code> FOR IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
+%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
 %type <token> USE_NAMESPACE
 %type <code> FOR_INIT
-%type <token> IMPORT
+%type <code> IMPORT
 %type <classinfo> MAYBETYPE
 %type <token> GETSET
 %type <param> PARAM
 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
 %type <classinfo_list> QNAME_LIST
 %type <classinfo> TYPE
-%type <token> VAR
 //%type <token> VARIABLE
 %type <value> VAR_READ
 %type <value> NEW
 %nonassoc '^'
 %nonassoc '&'
 %nonassoc "==" "!=" "===" "!=="
-%nonassoc "is" "as"
+%nonassoc "is" "as" "in"
 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
 %left "<<" ">>" ">>>" 
 %left below_minus
 %nonassoc below_curly
 %left '[' ']' '{' "new" '.' ".." "::"
 %nonassoc T_IDENTIFIER
+%left above_identifier
 %left below_else
 %nonassoc "else"
 %left '('
@@ -235,7 +246,18 @@ static int yyerror(char*s)
 {
    syntaxerror("%s", s); 
 }
-static char* concat3str(const char* t1, const char* t2, const char* t3)
+
+static char* concat2(const char* t1, const char* t2)
+{
+    int l1 = strlen(t1);
+    int l2 = strlen(t2);
+    char*text = malloc(l1+l2+1);
+    memcpy(text   , t1, l1);
+    memcpy(text+l1, t2, l2);
+    text[l1+l2] = 0;
+    return text;
+}
+static char* concat3(const char* t1, const char* t2, const char* t3)
 {
     int l1 = strlen(t1);
     int l2 = strlen(t2);
@@ -272,9 +294,12 @@ typedef struct _methodstate {
     code_t*initcode;
     char is_constructor;
     char has_super;
+    char is_global;
+    abc_exception_list_t*exceptions;
 } methodstate_t;
 
 typedef struct _state {
+    struct _state*old;
     int level;
 
     char*package;     
@@ -284,6 +309,8 @@ typedef struct _state {
   
     classstate_t*cls;   
     methodstate_t*method;
+
+    char*exception_name;
     
     dict_t*vars;
 } state_t;
@@ -342,31 +369,20 @@ static namespace_list_t nl2 = {&ns2,&nl3};
 static namespace_list_t nl1 = {&ns1,&nl2};
 static namespace_set_t nopackage_namespace_set = {&nl1};
 
-static state_list_t*state_stack=0;
-    
-static void init_globals()
-{
-    global = rfx_calloc(sizeof(global_t));
-}
-
 static void new_state()
 {
     NEW(state_t, s);
-    NEW(state_list_t, sl);
-
     state_t*oldstate = state;
     if(state)
         memcpy(s, state, sizeof(state_t)); //shallow copy
-    sl->next = state_stack;
-    sl->state = s;
     if(!s->imports) {
         s->imports = dict_new();
     }
-    state_stack = sl;
     state = s;
     state->level++;
     state->has_own_imports = 0;    
-    state->vars = dict_new();
+    state->vars = dict_new(); 
+    state->old = oldstate;
 }
 static void state_has_imports()
 {
@@ -375,31 +391,52 @@ static void state_has_imports()
     state->has_own_imports = 1;
 }
 
+static void state_destroy(state_t*state)
+{
+    if(state->has_own_imports) {
+        list_free(state->wildcard_imports);
+        dict_destroy(state->imports);state->imports=0;
+    }
+    if(state->imports && (!state->old || state->old->imports!=state->imports)) {
+        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;
+    }
+    
+    free(state);
+}
+
 static void old_state()
 {
-    if(!state_stack || !state_stack->next)
+    if(!state || !state->old)
         syntaxerror("invalid nesting");
-    state_t*oldstate = state;
-    state_list_t*old = state_stack;
-    state_stack = state_stack->next;
-    free(old);
-    state = state_stack->state;
+    state_t*leaving = state;
+    state = state->old;
     /*if(state->method->initcode) {
         printf("residual initcode\n");
         code_dump(state->method->initcode, 0, 0, "", stdout);
     }*/
-    if(oldstate->has_own_imports) {
-        list_free(oldstate->wildcard_imports);
-        dict_destroy(oldstate->imports);oldstate->imports=0;
-    }
+    state_destroy(leaving);
 }
 void initialize_state()
 {
-    init_globals();
+    global = rfx_calloc(sizeof(global_t));
     new_state();
 
+    state->package = current_filename;
+
     global->file = abc_file_new();
     global->file->flags &= ~ABCFILE_LAZY;
+    global->variable_count = 1;
     
     global->init = abc_initscript(global->file, 0);
     code_t*c = global->init->method->body->code;
@@ -451,22 +488,27 @@ void* finalize_state()
     __ pushstring(m, "[leaving global init function]");
     __ callpropvoid(m, "[package]::trace", 1);
     __ returnvoid(m);
+
+    state_destroy(state);
+
     return global->file;
 }
 
 
 static void startpackage(char*name)
 {
-    if(state->package) {
-        syntaxerror("Packages can not be nested."); 
-    } 
     new_state();
     /*printf("entering package \"%s\"\n", name);*/
-    state->package = name;
+    state->package = strdup(name);
+    global->variable_count = 1;
 }
 static void endpackage()
 {
     /*printf("leaving package \"%s\"\n", state->package);*/
+
+    //used e.g. in classinfo_register:
+    //free(state->package);state->package=0;
+
     old_state();
 }
 
@@ -477,6 +519,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
         syntaxerror("inner classes now allowed"); 
     }
     new_state();
+    global->variable_count = 1;
     state->cls = rfx_calloc(sizeof(classstate_t));
 
     token_list_t*t=0;
@@ -602,7 +645,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     /* flash.display.MovieClip handling */
     if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
         if(state->package && state->package[0]) {
-            globalclass = concat3str(state->package, ".", classname);
+            globalclass = concat3(state->package, ".", classname);
         } else {
             globalclass = strdup(classname);
         }
@@ -646,6 +689,7 @@ static void endclass()
         abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
     }
 
+    free(state->cls);state->cls=0;
     old_state();
 }
 
@@ -654,50 +698,57 @@ typedef struct _variable {
     classinfo_t*type;
 } variable_t;
 
-static int find_variable(char*name, classinfo_t**m)
+static variable_t* find_variable(char*name)
 {
-    state_list_t* s = state_stack;
+    state_t* s = state;
     while(s) {
         variable_t*v = 0;
-        if(s->state->method)
-            v = dict_lookup(s->state->vars, name);
+        if(s->method)
+            v = dict_lookup(s->vars, name);
         if(v) {
-            if(m) {
-                *m = v->type;
-            }
-            return v->index;
+            return v;
         }
-        s = s->next;
+        s = s->old;
     }
-    return -1;
+    return 0;
 } 
-static int find_variable_safe(char*name, classinfo_t**m)
+static variable_t* find_variable_safe(char*name)
 {
-    int i = find_variable(name, m);
-    if(i<0)
+    variable_t* v = find_variable(name);
+    if(!v)
         syntaxerror("undefined variable: %s", name);
-    return i;
+    return v;
 }
 static char variable_exists(char*name) 
 {
     return dict_lookup(state->vars, name)!=0;
 }
-static int new_variable(char*name, classinfo_t*type)
+code_t*defaultvalue(code_t*c, classinfo_t*type);
+static int new_variable(char*name, classinfo_t*type, char init)
 {
     NEW(variable_t, v);
     v->index = global->variable_count;
     v->type = type;
+    
     dict_put(state->vars, name, v);
+
+    if(init && state->method && type) {
+        /* if this is a typed variable:
+           push default value for type on stack at the very beginning of the
+           method, so that it always has that type regardless of the control
+           path */
+        state->method->initcode = defaultvalue(state->method->initcode, type);
+        state->method->initcode = abc_setlocal(state->method->initcode, v->index);
+    }
     return global->variable_count++;
 }
 #define TEMPVARNAME "__as3_temp__"
 static int gettempvar()
 {
-    int i = find_variable(TEMPVARNAME, 0);
-    if(i<0) {
-        i = new_variable(TEMPVARNAME, 0);
-    }
-    return i;
+    variable_t*v = find_variable(TEMPVARNAME);
+    if(v) 
+        return v->index;
+    return new_variable(TEMPVARNAME, 0, 0);
 }
 
 code_t* killvars(code_t*c) 
@@ -710,7 +761,7 @@ code_t* killvars(code_t*c)
             //do this always, otherwise register types don't match
             //in the verifier when doing nested loops
             //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
-            c = abc_kill(c, v->index);
+            c = abc_kill(c, v->index); 
             e = e->next;
         }
     }
@@ -751,12 +802,42 @@ static void check_constant_against_type(classinfo_t*t, constant_t*c)
    }
 }
 
+static int flags2access(int flags)
+{
+    int access = 0;
+    if(flags&FLAG_PUBLIC)  {
+        if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
+        access = ACCESS_PACKAGE;
+    } else if(flags&FLAG_PRIVATE) {
+        if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
+        access = ACCESS_PRIVATE;
+    } else if(flags&FLAG_PROTECTED) {
+        if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
+        access = ACCESS_PROTECTED;
+    } else {
+        access = ACCESS_PACKAGEINTERNAL;
+    }
+    return access;
+}
+
 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
 {
     memberinfo_t*minfo = 0;
-    if(getset != KW_GET && getset != KW_SET) {
-        if(registry_findmember(state->cls->info, name)) {
-            syntaxerror("class already contains a member/method called '%s'", name);
+    if(!state->cls) {
+        //package method
+        minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
+        minfo->return_type = return_type;
+    } else if(getset != KW_GET && getset != KW_SET) {
+        //class method
+        if((minfo = registry_findmember(state->cls->info, name, 0))) {
+            if(minfo->parent == state->cls->info) {
+                syntaxerror("class already contains a member/method called '%s'", name);
+            } else if(!minfo->parent) {
+                syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
+            } else {
+                if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
+                    syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
+            }
         }
         minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
         minfo->return_type = return_type;
@@ -764,13 +845,15 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
         // to actually store these
         //state->minfo->slot = state->method->abc->method->trait->slot_id;
     } else {
+        //class getter/setter
         int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
         classinfo_t*type=0;
         if(getset == KW_GET)
             type = return_type;
         else if(params->list)
             type = params->list->param->type;
-        if((minfo=registry_findmember(state->cls->info, name))) {
+        // not sure wether to look into superclasses here, too
+        if((minfo=registry_findmember(state->cls->info, name, 0))) {
             if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
                 syntaxerror("class already contains a member or method called '%s'", name);
             if(minfo->kind & gs)
@@ -794,27 +877,10 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
     if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
     if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
     if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
+    if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
     return minfo;
 }
 
-static int flags2access(int flags)
-{
-    int access = 0;
-    if(flags&FLAG_PUBLIC)  {
-        if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
-        access = ACCESS_PACKAGE;
-    } else if(flags&FLAG_PRIVATE) {
-        if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
-        access = ACCESS_PRIVATE;
-    } else if(flags&FLAG_PROTECTED) {
-        if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
-        access = ACCESS_PROTECTED;
-    } else {
-        access = ACCESS_PACKAGEINTERNAL;
-    }
-    return access;
-}
-
 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
                           params_t*params, classinfo_t*return_type)
 {
@@ -822,20 +888,27 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
         syntaxerror("not able to start another method scope");
     }
     new_state();
+    global->variable_count = 0;
     state->method = rfx_calloc(sizeof(methodstate_t));
     state->method->initcode = 0;
-    state->method->is_constructor = !strcmp(state->cls->info->name,name);
     state->method->has_super = 0;
-    
-    state->cls->has_constructor |= state->method->is_constructor;
+    if(state->cls) {
+        state->method->is_constructor = !strcmp(state->cls->info->name,name);
+        state->cls->has_constructor |= state->method->is_constructor;
+        
+        new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
+    } else {
+        state->method->is_global = 1;
+        state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
 
-    global->variable_count = 0;
+        new_variable("globalscope", 0, 0);
+    }
 
     /* state->vars is initialized by state_new */
-    if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
+
     param_list_t*p=0;
     for(p=params->list;p;p=p->next) {
-        new_variable(p->param->name, p->param->type);
+        new_variable(p->param->name, p->param->type, 0);
     }
     if(state->method->is_constructor)
         name = "__as3_constructor__";
@@ -845,25 +918,33 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
                           params_t*params, classinfo_t*return_type, code_t*body)
 {
-    namespace_t mname_ns = {flags2access(flags), ""};
-    multiname_t mname = {QNAME, &mname_ns, 0, name};
-
     abc_method_t*f = 0;
 
     multiname_t*type2 = sig2mname(return_type);
     int slot = 0;
     if(state->method->is_constructor) {
         f = abc_class_getconstructor(state->cls->abc, type2);
-    } else {
+    } else if(!state->method->is_global) {
+        namespace_t mname_ns = {flags2access(flags), ""};
+        multiname_t mname = {QNAME, &mname_ns, 0, name};
+
         if(flags&FLAG_STATIC)
             f = abc_class_staticmethod(state->cls->abc, type2, &mname);
         else
             f = abc_class_method(state->cls->abc, type2, &mname);
         slot = f->trait->slot_id;
+    } else {
+        namespace_t mname_ns = {flags2access(flags), state->package};
+        multiname_t mname = {QNAME, &mname_ns, 0, name};
+
+        f = abc_method_new(global->file, type2, 1);
+        trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
+        //abc_code_t*c = global->init->method->body->code;
     }
     //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(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;
@@ -885,12 +966,15 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam
     }
     check_code_for_break(body);
 
-    if(f->body)
+    if(f->body) {
         f->body->code = body;
-    else //interface
+        f->body->exceptions = state->method->exceptions;
+    } else { //interface
         if(body)
             syntaxerror("interface methods can't have a method body");
-        
+    }
+       
+    free(state->method);state->method=0;
     old_state();
 }
 
@@ -1014,14 +1098,15 @@ static classinfo_t* find_class(char*name)
     classinfo_t*c=0;
 
     c = registry_findclass(state->package, name);
+    if(c) return c;
 
     /* try explicit imports */
     dictentry_t* e = dict_get_slot(state->imports, name);
+    if(c) return c;
     while(e) {
-        if(c)
-            break;
         if(!strcmp(e->key, name)) {
             c = (classinfo_t*)e->data;
+            if(c) return c;
         }
         e = e->next;
     }
@@ -1029,18 +1114,21 @@ static classinfo_t* find_class(char*name)
     /* try package.* imports */
     import_list_t*l = state->wildcard_imports;
     while(l) {
-        if(c)
-            break;
         //printf("does package %s contain a class %s?\n", l->import->package, name);
         c = registry_findclass(l->import->package, name);
+        if(c) return c;
         l = l->next;
     }
 
     /* try global package */
-    if(!c) {
-        c = registry_findclass("", name);
-    }
-    return c;
+    c = registry_findclass("", name);
+    if(c) return c;
+   
+    /* try local "filename" package */
+    c = registry_findclass(current_filename, name);
+    if(c) return c;
+
+    return 0;
 }
 
 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
@@ -1093,6 +1181,8 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
                 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 {
@@ -1174,13 +1264,13 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
             temp = gettempvar();
             if(prefix) {
                 c = code_append(c, prefix);
-                c = abc_dup(c);
             }
             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);
         }
     }
 
@@ -1197,46 +1287,72 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
 
 /* ------------ code blocks / statements ---------------- */
 
-PROGRAM: MAYBECODE {
-    /* todo: do something with this code if we're outside a function */
-    if($1)
-        warning("ignored code");
-}
+PROGRAM: MAYBE_PROGRAM_CODE_LIST
+
+MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST 
+PROGRAM_CODE_LIST: PROGRAM_CODE 
+                 | PROGRAM_CODE_LIST PROGRAM_CODE
+
+PROGRAM_CODE: PACKAGE_DECLARATION 
+            | INTERFACE_DECLARATION 
+            | CLASS_DECLARATION
+            | FUNCTION_DECLARATION
+            | SLOT_DECLARATION
+            | PACKAGE_INITCODE
+            | ';'
+
+MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
+INPACKAGE_CODE_LIST: INPACKAGE_CODE 
+                   | INPACKAGE_CODE_LIST INPACKAGE_CODE
+
+INPACKAGE_CODE: INTERFACE_DECLARATION 
+              | CLASS_DECLARATION
+              | FUNCTION_DECLARATION
+              | SLOT_DECLARATION
+              | PACKAGE_INITCODE
+              | ';'
 
 MAYBECODE: CODE {$$=$1;}
 MAYBECODE: {$$=code_new();}
 
-CODE: CODE CODEPIECE {
-    $$=code_append($1,$2);
-}
-CODE: CODEPIECE {
-    $$=$1;
-}
-
-CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
-CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
-CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
-CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
-CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
-CODEPIECE: ';'                   {$$=code_new();}
-CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
-CODEPIECE: VOIDEXPRESSION        {$$=$1}
-CODEPIECE: FOR                   {$$=$1}
-CODEPIECE: WHILE                 {$$=$1}
-CODEPIECE: DO_WHILE              {$$=$1}
-CODEPIECE: SWITCH                {$$=$1}
-CODEPIECE: BREAK                 {$$=$1}
-CODEPIECE: CONTINUE              {$$=$1}
-CODEPIECE: RETURN                {$$=$1}
-CODEPIECE: IF                    {$$=$1}
-CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
-CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
+CODE: CODE CODEPIECE {$$=code_append($1,$2);}
+CODE: CODEPIECE {$$=$1;}
+
+// code which also may appear outside a method
+CODE_STATEMENT: IMPORT 
+CODE_STATEMENT: VOIDEXPRESSION 
+CODE_STATEMENT: FOR 
+CODE_STATEMENT: FOR_IN 
+CODE_STATEMENT: WHILE 
+CODE_STATEMENT: DO_WHILE 
+CODE_STATEMENT: SWITCH 
+CODE_STATEMENT: IF
+CODE_STATEMENT: WITH
+CODE_STATEMENT: TRY
+
+// code which may appear anywhere
+CODEPIECE: ';' {$$=0;}
+CODEPIECE: VARIABLE_DECLARATION
+CODEPIECE: CODE_STATEMENT
+CODEPIECE: BREAK
+CODEPIECE: CONTINUE
+CODEPIECE: RETURN
+CODEPIECE: THROW
+
+CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
+CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=0;}
 
 CODEBLOCK :  '{' CODE '}' {$$=$2;}
 CODEBLOCK :  '{' '}'      {$$=0;}
 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
 
+/* ------------ package init code ------------------- */
+
+PACKAGE_INITCODE: CODE_STATEMENT {
+    if($1) warning("code ignored");
+}
+
 /* ------------ variables --------------------------- */
 
 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
@@ -1244,43 +1360,36 @@ MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
                                   $$.t=TYPE_ANY;
                                  }
 
-VAR : "const" | "var"
-VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
+VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
+VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
 
 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
 
-ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
+ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
 {
-    if(variable_exists($2))
-        syntaxerror("Variable %s already defined", $2);
+    if(variable_exists($1))
+        syntaxerror("Variable %s already defined", $1);
    
-    if(!is_subtype_of($4.t, $3)) {
-        syntaxerror("Can't convert %s to %s", $4.t->name, 
-                                              $3->name);
+    if(!is_subtype_of($3.t, $2)) {
+        syntaxerror("Can't convert %s to %s", $3.t->name, 
+                                              $2->name);
     }
 
-    int index = new_variable($2, $3);
+    int index = new_variable($1, $2, 1);
     
-    if($3) {
-        if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
-            $$ = $4.c;
-            $$ = converttype($$, $4.t, $3);
+    if($2) {
+        if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
+            $$ = $3.c;
+            $$ = converttype($$, $3.t, $2);
             $$ = abc_setlocal($$, index);
         } else {
-            $$ = defaultvalue(0, $3);
+            $$ = defaultvalue(0, $2);
             $$ = abc_setlocal($$, index);
         }
-
-        /* if this is a typed variable:
-           push default value for type on stack */
-        if($3) {
-            state->method->initcode = defaultvalue(state->method->initcode, $3);
-            state->method->initcode = abc_setlocal(state->method->initcode, index);
-        }
     } else {
-        if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
-            $$ = $4.c;
+        if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
+            $$ = $3.c;
             $$ = abc_coerce_a($$);
             $$ = abc_setlocal($$, index);
         } else {
@@ -1323,25 +1432,78 @@ IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
 FOR_INIT : {$$=code_new();}
 FOR_INIT : VARIABLE_DECLARATION
 FOR_INIT : VOIDEXPRESSION
+FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
+    $$=$2;new_variable($2,$3,1);
+}
+FOR_IN_INIT : T_IDENTIFIER {
+    $$=$1;
+}
+
+FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
+FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
 
-FOR : T_FOR '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
+FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
+    if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
     $$ = code_new();
-    $$ = code_append($$, $4);
+    $$ = code_append($$, $2);
     code_t*loopstart = $$ = abc_label($$);
-    $$ = code_append($$, $6.c);
+    $$ = code_append($$, $4.c);
     code_t*myif = $$ = abc_iffalse($$, 0);
-    $$ = code_append($$, $10);
-    code_t*cont = $$ = abc_nop($$);
     $$ = code_append($$, $8);
+    code_t*cont = $$ = abc_nop($$);
+    $$ = code_append($$, $6);
     $$ = abc_jump($$, loopstart);
     code_t*out = $$ = abc_nop($$);
-    breakjumpsto($$, $1, out);
-    continuejumpsto($$, $1, cont);
+    breakjumpsto($$, $1.name, out);
+    continuejumpsto($$, $1.name, cont);
     myif->branch = out;
 
     $$ = killvars($$);old_state();
 }
 
+FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
+    variable_t*var = find_variable($2);
+    char*tmp1name = concat2($2, "__tmp1__");
+    int it = new_variable(tmp1name, TYPE_INT, 0);
+    char*tmp2name = concat2($2, "__array__");
+    int array = new_variable(tmp1name, 0, 0);
+
+    $$ = code_new();
+    $$ = code_append($$, $4.c);
+    $$ = abc_coerce_a($$);
+    $$ = abc_setlocal($$, array);
+    $$ = abc_pushbyte($$, 0);
+    $$ = abc_setlocal($$, it);
+
+    code_t*loopstart = $$ = abc_label($$);
+    
+    $$ = abc_hasnext2($$, array, it);
+    code_t*myif = $$ = abc_iffalse($$, 0);
+    $$ = abc_getlocal($$, array);
+    $$ = abc_getlocal($$, it);
+    if(!$1.each)
+        $$ = abc_nextname($$);
+    else
+        $$ = abc_nextvalue($$);
+    $$ = converttype($$, 0, var->type);
+    $$ = abc_setlocal($$, var->index);
+
+    $$ = code_append($$, $6);
+    $$ = abc_jump($$, loopstart);
+    
+    code_t*out = $$ = abc_nop($$);
+    breakjumpsto($$, $1.name, out);
+    continuejumpsto($$, $1.name, loopstart);
+    
+    $$ = killvars($$);
+    
+    myif->branch = out;
+
+    old_state();
+    free(tmp1name);
+    free(tmp2name);
+}
+
 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
     $$ = code_new();
 
@@ -1394,12 +1556,14 @@ MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
 CASE_LIST: CASE             {$$=$1}
 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
 
-CASE: "case" CONSTANT ':' MAYBECODE {
+CASE: "case" E ':' MAYBECODE {
     $$ = abc_dup(0);
     $$ = code_append($$, $2.c);
     code_t*j = $$ = abc_ifne($$, 0);
     $$ = code_append($$, $4);
-    $$ = abc___continue__($$, "");
+    if($$->opcode != OPCODE___BREAK__) {
+        $$ = abc___fallthrough__($$, "");
+    }
     code_t*e = $$ = abc_nop($$);
     j->branch = e;
 }
@@ -1415,8 +1579,9 @@ SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
     code_t*c = $$,*lastblock=0;
     while(c) {
         if(c->opcode == OPCODE_IFNE) {
+            if(!c->next) syntaxerror("internal error in fallthrough handling");
             lastblock=c->next;
-        } else if(c->opcode == OPCODE___CONTINUE__) {
+        } else if(c->opcode == OPCODE___FALLTHROUGH__) {
             if(lastblock) {
                 c->opcode = OPCODE_JUMP;
                 c->branch = lastblock;
@@ -1430,16 +1595,89 @@ SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
     old_state();
 }
 
+/* ------------ try / catch /finally ---------------- */
+
+FINALLY: "finally" '{' CODE '}'
+MAYBE_FINALLY: | FINALLY 
+
+CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);} 
+        '{' CODE '}' {
+    code_t*c = 0;
+    int i = find_variable_safe($3)->index;
+    c = abc_setlocal(c, i);
+    c = code_append(c, $8);
+    c = abc_kill(c, i);
+    
+    namespace_t name_ns = {ACCESS_PACKAGE, ""};
+    multiname_t name = {QNAME, &name_ns, 0, $3};
+
+    NEW(abc_exception_t, e)
+    e->exc_type = sig2mname($4);
+    e->var_name = multiname_clone(&name);
+    e->target = code_start(c);
+    $$ = e;
+    old_state();
+}
+
+CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
+CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
+
+TRY : "try" '{' CODE '}' CATCH_LIST MAYBE_FINALLY {
+    code_t*start = code_start($3);
+    $$=$3;
+
+    code_t*out = abc_nop(0);
+    code_t*jmp = $$ = abc_jump($$, out);
+
+    abc_exception_list_t*l = $5;
+    while(l) {
+        abc_exception_t*e = l->abc_exception;
+        e->from = start;
+        e->to = jmp;
+        $$ = code_append($$, e->target);
+        $$ = abc_jump($$, out);
+        l = l->next;
+    }
+    $$ = code_append($$, out);
+    jmp->branch = out;
+        
+    list_concat(state->method->exceptions, $5);
+}
+
+/* ------------ throw ------------------------------- */
+
+THROW : "throw" EXPRESSION {
+    $$=$2.c;
+    $$=abc_throw($$);
+}
+THROW : "throw" %prec prec_none {
+    if(!state->exception_name)
+        syntaxerror("re-throw only possible within a catch block");
+    variable_t*v = find_variable(state->exception_name);
+    $$=code_new();
+    $$=abc_getlocal($$, v->index);
+    $$=abc_throw($$);
+}
+
+/* ------------ with -------------------------------- */
+
+WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
+     $$ = $3.c;
+     $$ = abc_pushscope($$);
+     $$ = code_append($$, $5);
+     $$ = abc_popscope($$);
+}
+
 /* ------------ packages and imports ---------------- */
 
 X_IDENTIFIER: T_IDENTIFIER
             | "package" {$$="package";}
 
-PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
-PACKAGE: X_IDENTIFIER             {$$=$1;}
+PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
+PACKAGE: X_IDENTIFIER             {$$=strdup($1);}
 
-PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
-PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
+PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
+PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
 
 IMPORT : "import" QNAME {
        classinfo_t*c = $2;
@@ -1486,29 +1724,35 @@ IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
                               EXTENDS IMPLEMENTS_LIST 
                               '{' {startclass($1,$3,$4,$5, 0);} 
-                              MAYBE_DECLARATION_LIST 
-                              '}' {endclass();}
+                              MAYBE_CLASS_BODY 
+                              '}' {endclass();$$=0;}
 
 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
                               EXTENDS_LIST 
                               '{' {startclass($1,$3,0,$4,1);}
-                              MAYBE_IDECLARATION_LIST 
-                              '}' {endclass();}
+                              MAYBE_INTERFACE_BODY 
+                              '}' {endclass();$$=0;}
 
 /* ------------ classes and interfaces (body) -------------- */
 
-MAYBE_DECLARATION_LIST : 
-MAYBE_DECLARATION_LIST : DECLARATION_LIST
-DECLARATION_LIST : DECLARATION
-DECLARATION_LIST : DECLARATION_LIST DECLARATION
-DECLARATION : ';'
-DECLARATION : SLOT_DECLARATION
-DECLARATION : FUNCTION_DECLARATION
-
-MAYBE_IDECLARATION_LIST : 
-MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
-IDECLARATION_LIST : IDECLARATION
-IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
+MAYBE_CLASS_BODY : 
+MAYBE_CLASS_BODY : CLASS_BODY
+CLASS_BODY : CLASS_BODY_ITEM
+CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
+CLASS_BODY_ITEM : ';'
+CLASS_BODY_ITEM : SLOT_DECLARATION
+CLASS_BODY_ITEM : FUNCTION_DECLARATION
+
+CLASS_BODY_ITEM : CODE_STATEMENT {
+    code_t*c = state->cls->static_init;
+    c = code_append(c, $1);  
+    state->cls->static_init = c;
+}
+
+MAYBE_INTERFACE_BODY : 
+MAYBE_INTERFACE_BODY : INTERFACE_BODY
+INTERFACE_BODY : IDECLARATION
+INTERFACE_BODY : INTERFACE_BODY IDECLARATION
 IDECLARATION : ';'
 IDECLARATION : "var" T_IDENTIFIER {
     syntaxerror("variable declarations not allowed in interfaces");
@@ -1528,45 +1772,58 @@ VARCONST: "var" | "const"
 
 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
     int flags = $1;
-    memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
+    memberinfo_t* info = state->cls?
+            memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
+            memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
+
     info->type = $4;
     info->flags = flags;
-    trait_t*t=0;
 
+    /* slot name */
     namespace_t mname_ns = {flags2access(flags), ""};
     multiname_t mname = {QNAME, &mname_ns, 0, $3};
-
-    if(!(flags&FLAG_STATIC)) {
-        if($4) {
-            MULTINAME(m, $4);
-            t=abc_class_slot(state->cls->abc, &mname, &m);
-        } else {
-            t=abc_class_slot(state->cls->abc, &mname, 0);
-        }
-        info->slot = t->slot_id;
+  
+    trait_list_t**traits;
+    code_t**code;
+    if(!state->cls) {
+        // global variable
+        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;
     } else {
-        if($4) {
-            MULTINAME(m, $4);
-            t=abc_class_staticslot(state->cls->abc, &mname, &m);
-        } else {
-            t=abc_class_staticslot(state->cls->abc, &mname, 0);
-        }
-        info->slot = t->slot_id;
+        // instance variable
+        traits = &state->cls->abc->traits;
+        code = &state->cls->init;
+    }
+    
+    trait_t*t=0;
+    if($4) {
+        MULTINAME(m, $4);
+        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($5.c && !is_pushundefined($5.c)) {
-        code_t*c = 0;
         c = abc_getlocal_0(c);
         c = code_append(c, $5.c);
         c = converttype(c, $5.t, $4);
         c = abc_setslot(c, t->slot_id);
-        if(!(flags&FLAG_STATIC))
-            state->cls->init = code_append(state->cls->init, c);
-        else
-            state->cls->static_init = code_append(state->cls->static_init, c);
     }
+
+    *code = code_append(*code, c);
+
     if($2==KW_CONST) {
         t->kind= TRAIT_CONST;
     }
+
+    $$=0;
 }
 
 /* ------------ constants -------------------------------------- */
@@ -1647,6 +1904,7 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P
     }
     c = wrap_function(c, state->method->initcode, $11);
     endfunction(0,$1,$3,$4,&$6,$8,c);
+    $$=0;
 }
 
 /* ------------- package + class ids --------------- */
@@ -1661,6 +1919,7 @@ CLASS: T_IDENTIFIER {
 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
     $$ = registry_findclass($1, $3);
     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
+    free($1);$1=0;
 }
 
 QNAME: PACKAGEANDCLASS
@@ -1685,19 +1944,18 @@ MAYBETYPE:          {$$=0;}
 
 /* ----------function calls, delete, constructor calls ------ */
 
-MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
+MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.len=0;}
 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
 
-MAYBE_EXPRESSION_LIST : {$$=0;}
+MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
-EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
-                                                  typedcode_t*t = malloc(sizeof(typedcode_t));
-                                                  *t = $1;
-                                                  list_append($$, t);}
-EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
-                                                  typedcode_t*t = malloc(sizeof(typedcode_t));
-                                                  *t = $3;
-                                                  list_append($$, t);}
+EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.len=1;
+                                                  $$.cc = $1.c;
+                                                 }
+EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
+                                                  $$.len= $1.len+1;
+                                                  $$.cc = code_append($1.cc, $3.c);
+                                                  }
 
 NEW : "new" CLASS MAYBE_PARAM_VALUES {
     MULTINAME(m, $2);
@@ -1710,17 +1968,12 @@ NEW : "new" CLASS MAYBE_PARAM_VALUES {
         $$.c = abc_findpropstrict2($$.c, &m);
     }
 
-    typedcode_list_t*l = $3;
-    int len = 0;
-    while(l) {
-        $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
-        l = l->next;
-        len ++;
-    }
+    $$.c = code_append($$.c, $3.cc);
+
     if($2->slot)
-        $$.c = abc_construct($$.c, len);
+        $$.c = abc_construct($$.c, $3.len);
     else
-        $$.c = abc_constructprop2($$.c, &m, len);
+        $$.c = abc_constructprop2($$.c, &m, $3.len);
     $$.t = $2;
 }
 
@@ -1729,47 +1982,41 @@ NEW : "new" CLASS MAYBE_PARAM_VALUES {
          call (for closures)
 */
 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
-    typedcode_list_t*l = $3;
-    int len = 0;
-    code_t*paramcode = 0;
-    while(l) {
-        paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
-        l = l->next;
-        len ++;
-    }
-       
+    
     $$.c = $1.c;
     if($$.c->opcode == OPCODE_COERCE_A) {
         $$.c = code_cutlast($$.c);
     }
+    code_t*paramcode = $3.cc;
 
     $$.t = TYPE_ANY;
-    multiname_t*name = 0;
     if($$.c->opcode == OPCODE_GETPROPERTY) {
-        name = multiname_clone($$.c->data[0]);
+        multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
         $$.c = code_cutlast($$.c);
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_callproperty2($$.c, name, len);
+        $$.c = abc_callproperty2($$.c, name, $3.len);
+        multiname_destroy(name);
     } else if($$.c->opcode == OPCODE_GETSLOT) {
         int slot = (int)(ptroff_t)$$.c->data[0];
         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
         if(t->kind!=TRAIT_METHOD) {
             //ok: flash allows to assign closures to members.
         }
-        name = t->name;
+        multiname_t*name = t->name;
         $$.c = code_cutlast($$.c);
         $$.c = code_append($$.c, paramcode);
         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
-        $$.c = abc_callproperty2($$.c, name, len);
+        $$.c = abc_callproperty2($$.c, name, $3.len);
     } else if($$.c->opcode == OPCODE_GETSUPER) {
-        name = multiname_clone($$.c->data[0]);
+        multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
         $$.c = code_cutlast($$.c);
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_callsuper2($$.c, name, len);
+        $$.c = abc_callsuper2($$.c, name, $3.len);
+        multiname_destroy(name);
     } else {
         $$.c = abc_getlocal_0($$.c);
         $$.c = code_append($$.c, paramcode);
-        $$.c = abc_call($$.c, len);
+        $$.c = abc_call($$.c, $3.len);
     }
    
     memberinfo_t*f = 0;
@@ -1780,6 +2027,7 @@ FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
         $$.c = abc_coerce_a($$.c);
         $$.t = TYPE_ANY;
     }
+
 }
 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
     if(!state->cls) syntaxerror("super() not allowed outside of a class");
@@ -1788,18 +2036,15 @@ FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
 
     $$.c = code_new();
     $$.c = abc_getlocal_0($$.c);
-    typedcode_list_t*l = 0;
-    int len = 0;
-    for(l=$3;l;l=l->next) {
-        $$.c = code_append($$.c, l->typedcode->c);len++;
-    }
+
+    $$.c = code_append($$.c, $3.cc);
     /*
     this is dependent on the control path, check this somewhere else
     if(state->method->has_super)
         syntaxerror("constructor may call super() only once");
     */
     state->method->has_super = 1;
-    $$.c = abc_constructsuper($$.c, len);
+    $$.c = abc_constructsuper($$.c, $3.len);
     $$.c = abc_pushundefined($$.c);
     $$.t = TYPE_ANY;
 }
@@ -2014,6 +2259,11 @@ E : E '*' E {$$.c = code_append($1.c,$3.c);
              }
             }
 
+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)) {
                 MULTINAME(m,$3.t->cls);
@@ -2077,43 +2327,33 @@ E : E '[' E ']' {
 
 E : '[' MAYBE_EXPRESSION_LIST ']' {
     $$.c = code_new();
-    typedcode_list_t*l = 0;
-    int len = 0;
-    for(l=$2;l;l=l->next) {
-        $$.c = code_append($$.c, l->typedcode->c);len++;
-    }
-    $$.c = abc_newarray($$.c, len);
+    $$.c = code_append($$.c, $2.cc);
+    $$.c = abc_newarray($$.c, $2.len);
     $$.t = registry_getarrayclass();
 }
 
-MAYBE_EXPRPAIR_LIST : {$$=0;}
+MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
 
 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
-    typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $1;
-    typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $3;
-    $$ = 0;
-    list_append($$, t1);
-    list_append($$, t2);
+    $$.cc = 0;
+    $$.cc = code_append($$.cc, $1.c);
+    $$.cc = code_append($$.cc, $3.c);
+    $$.len = 2;
 }
 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
-    $$=$1;
-    typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $3;
-    typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $5;
-    list_append($$, t1);
-    list_append($$, t2);
+    $$.cc = $1.cc;
+    $$.len = $1.len+2;
+    $$.cc = code_append($$.cc, $3.c);
+    $$.cc = code_append($$.cc, $5.c);
 }
 //MAYBECOMMA: ','
 //MAYBECOMMA:
 
 E : '{' MAYBE_EXPRPAIR_LIST '}' {
     $$.c = code_new();
-    typedcode_list_t*l = 0;
-    int len = 0;
-    for(l=$2;l;l=l->next) {
-        $$.c = code_append($$.c, l->typedcode->c);len++;
-    }
-    $$.c = abc_newobject($$.c, len/2);
+    $$.c = code_append($$.c, $2.cc);
+    $$.c = abc_newobject($$.c, $2.len/2);
     $$.t = registry_getobjectclass();
 }
 
@@ -2262,7 +2502,7 @@ E : "super" '.' T_IDENTIFIER
               classinfo_t*t = state->cls->info->superclass;
               if(!t) t = TYPE_OBJECT;
 
-              memberinfo_t*f = registry_findmember(t, $3);
+              memberinfo_t*f = registry_findmember(t, $3, 1);
               namespace_t ns = {flags2access(f->flags), ""};
               MEMBER_MULTINAME(m, f, $3);
               $$.c = 0;
@@ -2280,7 +2520,7 @@ E : E '.' T_IDENTIFIER
                  is_static = 1;
              }
              if(t) {
-                 memberinfo_t*f = registry_findmember(t, $3);
+                 memberinfo_t*f = registry_findmember(t, $3, 1);
                  char noslot = 0;
                  if(f && !is_static != !(f->flags&FLAG_STATIC))
                     noslot=1;
@@ -2308,17 +2548,18 @@ E : E '.' T_IDENTIFIER
 VAR_READ : T_IDENTIFIER {
     $$.t = 0;
     $$.c = 0;
-    int i;
     classinfo_t*a = 0;
     memberinfo_t*f = 0;
 
+    variable_t*v;
     /* look at variables */
-    if((i = find_variable($1, &$$.t)) >= 0) {
+    if((v = find_variable($1))) {
         // $1 is a local variable
-        $$.c = abc_getlocal($$.c, i);
+        $$.c = abc_getlocal($$.c, v->index);
+        $$.t = v->type;
 
     /* look at current class' members */
-    } else if((f = registry_findmember(state->cls->info, $1))) {
+    } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
         // $1 is a function in this class
         int var_is_static = (f->flags&FLAG_STATIC);
         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
@@ -2348,7 +2589,7 @@ VAR_READ : T_IDENTIFIER {
             $$.t = f->type;
         }
     
-    /* look at classes in the current package and imported classes */
+    /* look at actual classes, in the current package and imported */
     } else if((a = find_class($1))) {
         if(a->flags & FLAG_METHOD) {
             MULTINAME(m, a);
@@ -2387,9 +2628,9 @@ VAR_READ : T_IDENTIFIER {
 
 // ----------------- namespaces -------------------------------------------------
 
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
 
-USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
+USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}