fixed vertical alignment bug
[swftools.git] / lib / as3 / parser.y
index 5a3ad79..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<number_uint> T_SHORT
 %token<number_float> T_FLOAT
 
-%token<token> KW_IMPLEMENTS
+%token<id> T_FOR "for"
+%token<id> T_WHILE "while"
+%token<id> T_DO "do"
+%token<id> T_SWITCH "switch"
+
+%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_FOR "for"
+%token<token> KW_CONTINUE "continue"
 %token<token> KW_CLASS "class"
 %token<token> KW_CONST "const"
+%token<token> KW_CATCH "catch"
+%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_INTERFACE "interface"
 %token<token> KW_NULL "null"
 %token<token> KW_VAR "var"
-%token<token> KW_DYNAMIC
-%token<token> KW_OVERRIDE
-%token<token> KW_FINAL
+%token<token> KW_DYNAMIC "dynamic"
+%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_UINT "uint"
 %token<token> KW_INT "int"
-%token<token> KW_WHILE "while"
 %token<token> KW_NUMBER "Number"
 %token<token> KW_STRING "String"
+%token<token> KW_DEFAULT "default"
 %token<token> KW_DELETE "delete"
 %token<token> KW_IF "if"
 %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
-%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 MAYBEELSE BREAK RETURN
+%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
 //%type <token> T_IDENTIFIER
 %type <token> MODIFIER
 %type <value> FUNCTIONCALL
-%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
+%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
 
 // precedence: from low to high
 
 %nonassoc '^'
 %nonassoc '&'
 %nonassoc "==" "!=" "===" "!=="
-%nonassoc "is" "as"
+%nonassoc "is" "as" "in"
 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
 %left "<<" ">>" ">>>" 
 %left below_minus
 %left '/' '*' '%'
 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
 %left "--" "++" 
+%nonassoc below_curly
 %left '[' ']' '{' "new" '.' ".." "::"
 %nonassoc T_IDENTIFIER
+%left above_identifier
 %left below_else
 %nonassoc "else"
 %left '('
 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
 %nonassoc "false" "true" "null" "undefined" "super"
 
+
      
 %{
 
@@ -225,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);
@@ -262,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;     
@@ -274,6 +309,8 @@ typedef struct _state {
   
     classstate_t*cls;   
     methodstate_t*method;
+
+    char*exception_name;
     
     dict_t*vars;
 } state_t;
@@ -332,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()
 {
@@ -365,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;
@@ -441,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();
 }
 
@@ -467,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;
@@ -482,7 +535,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     printf("\n");
     */
 
-    if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
+    if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
         syntaxerror("invalid modifier(s)");
 
     if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
@@ -592,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);
         }
@@ -636,6 +689,7 @@ static void endclass()
         abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
     }
 
+    free(state->cls);state->cls=0;
     old_state();
 }
 
@@ -644,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) 
@@ -700,13 +761,28 @@ 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;
         }
     }
     return c;
 }
 
+void check_code_for_break(code_t*c)
+{
+    while(c) {
+        if(c->opcode == OPCODE___BREAK__) {
+            char*name = string_cstr(c->data[0]);
+            syntaxerror("Unresolved \"break %s\"", name);
+        }
+        if(c->opcode == OPCODE___CONTINUE__) {
+            char*name = string_cstr(c->data[0]);
+            syntaxerror("Unresolved \"continue %s\"", name);
+        }
+        c=c->prev;
+    }
+}
+
 
 static void check_constant_against_type(classinfo_t*t, constant_t*c)
 {
@@ -726,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;
@@ -739,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)
@@ -769,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)
 {
@@ -797,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__";
@@ -820,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;
@@ -858,8 +964,17 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam
             syntaxerror("non-optional parameter not allowed after optional parameters");
         }
     }
-    f->body->code = body;
-        
+    check_code_for_break(body);
+
+    if(f->body) {
+        f->body->code = body;
+        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();
 }
 
@@ -870,16 +985,30 @@ char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
     return 1; // FIXME
 }
 
-void breakjumpsto(code_t*c, code_t*jump) 
+void breakjumpsto(code_t*c, char*name, code_t*jump) 
 {
-    while(c->prev) 
-        c=c->prev;
     while(c) {
         if(c->opcode == OPCODE___BREAK__) {
-            c->opcode = OPCODE_JUMP;
-            c->branch = jump;
+            string_t*name2 = c->data[0];
+            if(!name2->len || !strncmp(name2->str, name, name2->len)) {
+                c->opcode = OPCODE_JUMP;
+                c->branch = jump;
+            }
         }
-        c = c->next;
+        c=c->prev;
+    }
+}
+void continuejumpsto(code_t*c, char*name, code_t*jump) 
+{
+    while(c) {
+        if(c->opcode == OPCODE___CONTINUE__) {
+            string_t*name2 = c->data[0];
+            if(!name2->len || !strncmp(name2->str, name, name2->len)) {
+                c->opcode = OPCODE_JUMP;
+                c->branch = jump;
+            }
+        }
+        c = c->prev;
     }
 }
 
@@ -907,19 +1036,13 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
         return abc_coerce2(c, &m);
     }
     
-    if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
-        return abc_coerce2(c, &m);
-    }
-    if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
-        return abc_coerce2(c, &m);
-    }
-    /* these are subject to overflow */
-    if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
-        return abc_coerce2(c, &m);
-    }
-    if(TYPE_IS_UINT(from) && TYPE_IS_INT(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
         return abc_coerce2(c, &m);
     }
+    //printf("%s.%s\n", from.package, from.name);
+    //printf("%s.%s\n", to.package, to.name);
 
     classinfo_t*supertype = from;
     while(supertype) {
@@ -930,7 +1053,7 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
         int t=0;
         while(supertype->interfaces[t]) {
             if(supertype->interfaces[t]==to) {
-                // to type is one of from's interfaces
+                // target type is one of from's interfaces
                 return abc_coerce2(c, &m);
             }
             t++;
@@ -975,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;
     }
@@ -990,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)
@@ -1054,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 {
@@ -1135,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);
         }
     }
 
@@ -1158,34 +1287,72 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
 
 /* ------------ code blocks / statements ---------------- */
 
-PROGRAM: MAYBECODE
+PROGRAM: MAYBE_PROGRAM_CODE_LIST
+
+MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST 
+PROGRAM_CODE_LIST: PROGRAM_CODE 
+                 | PROGRAM_CODE_LIST PROGRAM_CODE
 
-MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
-MAYBECODE:      {$$=code_new();}
+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: BREAK                 {$$=$1}
-CODEPIECE: RETURN                {$$=$1}
-CODEPIECE: IF                    {$$=$1}
-CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
-CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
-
-CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
+// 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;}
@@ -1193,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 {
@@ -1251,7 +1411,7 @@ MAYBEELSE:  %prec below_else {$$ = code_new();}
 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
 
-IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
+IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
     $$ = code_new();
     $$ = code_append($$, $4.c);
     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
@@ -1272,40 +1432,240 @@ 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 : "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_append($$, $8);
+    code_t*cont = $$ = abc_nop($$);
+    $$ = code_append($$, $6);
     $$ = abc_jump($$, loopstart);
     code_t*out = $$ = abc_nop($$);
-    breakjumpsto($$, out);
+    breakjumpsto($$, $1.name, out);
+    continuejumpsto($$, $1.name, cont);
     myif->branch = out;
 
     $$ = killvars($$);old_state();
 }
 
-WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
+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();
 
     code_t*myjmp = $$ = abc_jump($$, 0);
     code_t*loopstart = $$ = abc_label($$);
     $$ = code_append($$, $6);
-    myjmp->branch = $$ = abc_nop($$);
+    code_t*cont = $$ = abc_nop($$);
+    myjmp->branch = cont;
     $$ = code_append($$, $4.c);
     $$ = abc_iftrue($$, loopstart);
     code_t*out = $$ = abc_nop($$);
-    breakjumpsto($$, out);
+    breakjumpsto($$, $1, out);
+    continuejumpsto($$, $1, cont);
 
-    $$ = killvars($$);old_state();
+    $$ = killvars($$);
+    old_state();
+}
+
+DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
+    $$ = code_new();
+    code_t*loopstart = $$ = abc_label($$);
+    $$ = code_append($$, $3);
+    code_t*cont = $$ = abc_nop($$);
+    $$ = code_append($$, $6.c);
+    $$ = abc_iftrue($$, loopstart);
+    code_t*out = $$ = abc_nop($$);
+    breakjumpsto($$, $1, out);
+    continuejumpsto($$, $1, cont);
+    $$ = killvars($$);
+    old_state();
+}
+
+BREAK : "break" %prec prec_none {
+    $$ = abc___break__(0, "");
+}
+BREAK : "break" T_IDENTIFIER {
+    $$ = abc___break__(0, $2);
+}
+CONTINUE : "continue" %prec prec_none {
+    $$ = abc___continue__(0, "");
+}
+CONTINUE : "continue" T_IDENTIFIER {
+    $$ = abc___continue__(0, $2);
+}
+
+MAYBE_CASE_LIST :           {$$=0;}
+MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
+MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
+MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
+CASE_LIST: CASE             {$$=$1}
+CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
+
+CASE: "case" E ':' MAYBECODE {
+    $$ = abc_dup(0);
+    $$ = code_append($$, $2.c);
+    code_t*j = $$ = abc_ifne($$, 0);
+    $$ = code_append($$, $4);
+    if($$->opcode != OPCODE___BREAK__) {
+        $$ = abc___fallthrough__($$, "");
+    }
+    code_t*e = $$ = abc_nop($$);
+    j->branch = e;
+}
+DEFAULT: "default" ':' MAYBECODE {
+    $$ = $3;
+}
+SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
+    $$=$4.c;
+    $$ = code_append($$, $7);
+    code_t*out = $$ = abc_pop($$);
+    breakjumpsto($$, $1, out);
+    
+    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___FALLTHROUGH__) {
+            if(lastblock) {
+                c->opcode = OPCODE_JUMP;
+                c->branch = lastblock;
+            } else {
+                /* fall through end of switch */
+                c->opcode = OPCODE_NOP;
+            }
+        }
+        c=c->prev;
+    }
+    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();
 }
 
-BREAK : "break" {
-    $$ = abc___break__(0);
+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 ---------------- */
@@ -1313,11 +1673,11 @@ BREAK : "break" {
 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;
@@ -1364,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");
@@ -1406,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 -------------------------------------- */
@@ -1525,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 --------------- */
@@ -1539,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
@@ -1549,6 +1930,7 @@ QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
 
 TYPE : QNAME      {$$=$1;}
      | '*'        {$$=registry_getanytype();}
+     | "void"     {$$=registry_getanytype();}
     /*
      |  "String"  {$$=registry_getstringclass();}
      |  "int"     {$$=registry_getintclass();}
@@ -1562,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);
@@ -1587,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;
 }
 
@@ -1606,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;
@@ -1657,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");
@@ -1665,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;
 }
@@ -1891,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);
@@ -1954,15 +2327,36 @@ 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 : {$$.cc=0;$$.len=0;}
+MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
+
+EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+    $$.cc = 0;
+    $$.cc = code_append($$.cc, $1.c);
+    $$.cc = code_append($$.cc, $3.c);
+    $$.len = 2;
+}
+EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+    $$.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();
+    $$.c = code_append($$.c, $2.cc);
+    $$.c = abc_newobject($$.c, $2.len/2);
+    $$.t = registry_getobjectclass();
+}
+
 E : E "*=" E { 
                code_t*c = $3.c;
                if(BOTH_INT($1,$3)) {
@@ -2108,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;
@@ -2126,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;
@@ -2154,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);
@@ -2194,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);
@@ -2233,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;}