implemented for(in), for each(in)
[swftools.git] / lib / as3 / parser.y
index c74b519..093b1eb 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;
 }
 
 
 %token<number_uint> T_SHORT
 %token<number_float> T_FLOAT
 
+%token<id> T_FOR "for"
+%token<id> T_WHILE "while"
+%token<id> T_DO "do"
+%token<id> T_SWITCH "switch"
+
 %token<token> KW_IMPLEMENTS
 %token<token> KW_NAMESPACE "namespace"
 %token<token> KW_PACKAGE "package"
 %token<token> KW_FUNCTION "function"
 %token<token> KW_UNDEFINED "undefined"
 %token<token> KW_CONTINUE "continue"
-%token<token> KW_FOR "for"
 %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_INTERFACE "interface"
 %token<token> KW_NULL "null"
 %token<token> KW_VAR "var"
-%token<token> KW_DYNAMIC
+%token<token> KW_DYNAMIC "dynamic"
 %token<token> KW_OVERRIDE
 %token<token> KW_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_FALSE "false"
 %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> KW_DO "do"
 
 %token<token> T_EQEQ "=="
 %token<token> T_EQEQEQ "==="
 %token<token> T_USHR ">>>"
 %token<token> T_SHR ">>"
 
-%type <id> X_IDENTIFIER PACKAGE MAYBELABEL
+%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 <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 <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
 %type <token> USE_NAMESPACE
 %type <code> FOR_INIT
 %type <token> IMPORT
 %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
 
 %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 below_else
 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
 %nonassoc "false" "true" "null" "undefined" "super"
 
+
      
 %{
 
@@ -227,7 +239,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);
@@ -267,6 +290,7 @@ typedef struct _methodstate {
 } methodstate_t;
 
 typedef struct _state {
+    struct _state*old;
     int level;
 
     char*package;     
@@ -334,8 +358,6 @@ 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));
@@ -344,21 +366,17 @@ static void init_globals()
 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->old = oldstate;
 }
 static void state_has_imports()
 {
@@ -367,23 +385,41 @@ 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()
 {
@@ -443,6 +479,9 @@ void* finalize_state()
     __ pushstring(m, "[leaving global init function]");
     __ callpropvoid(m, "[package]::trace", 1);
     __ returnvoid(m);
+
+    state_destroy(state);
+
     return global->file;
 }
 
@@ -454,11 +493,15 @@ static void startpackage(char*name)
     } 
     new_state();
     /*printf("entering package \"%s\"\n", name);*/
-    state->package = name;
+    state->package = strdup(name);
 }
 static void endpackage()
 {
     /*printf("leaving package \"%s\"\n", state->package);*/
+
+    //used e.g. in classinfo_register:
+    //free(state->package);state->package=0;
+
     old_state();
 }
 
@@ -484,7 +527,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))
@@ -594,7 +637,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);
         }
@@ -638,6 +681,7 @@ static void endclass()
         abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
     }
 
+    free(state->cls);state->cls=0;
     old_state();
 }
 
@@ -646,50 +690,56 @@ 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) 
@@ -702,13 +752,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)
 {
@@ -732,8 +797,15 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
 {
     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((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;
@@ -747,7 +819,8 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
             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)
@@ -771,6 +844,7 @@ 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;
 }
 
@@ -809,10 +883,10 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
     global->variable_count = 0;
 
     /* state->vars is initialized by state_new */
-    if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
+    if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0)!=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__";
@@ -841,6 +915,7 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam
     //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;
@@ -860,8 +935,15 @@ 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;
+    else //interface
+        if(body)
+            syntaxerror("interface methods can't have a method body");
+       
+    free(state->method);state->method=0;
     old_state();
 }
 
@@ -876,8 +958,11 @@ void breakjumpsto(code_t*c, char*name, code_t*jump)
 {
     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->prev;
     }
@@ -886,8 +971,11 @@ void continuejumpsto(code_t*c, char*name, code_t*jump)
 {
     while(c) {
         if(c->opcode == OPCODE___CONTINUE__) {
-            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->prev;
     }
@@ -917,19 +1005,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) {
@@ -940,7 +1022,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++;
@@ -1145,7 +1227,6 @@ 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);
@@ -1168,13 +1249,21 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
 
 /* ------------ code blocks / statements ---------------- */
 
-PROGRAM: MAYBECODE
+PROGRAM: MAYBECODE {
+    /* todo: do something with this code if we're outside a function */
+    if($1)
+        warning("ignored code");
+}
 
-MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
-MAYBECODE:      {$$=code_new();}
+MAYBECODE: CODE {$$=$1;}
+MAYBECODE: {$$=code_new();}
 
-CODE: CODE CODEPIECE {$$=code_append($1,$2);}
-CODE: CODEPIECE {$$=$1;}
+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*/}
@@ -1185,8 +1274,10 @@ CODEPIECE: ';'                   {$$=code_new();}
 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
 CODEPIECE: VOIDEXPRESSION        {$$=$1}
 CODEPIECE: FOR                   {$$=$1}
+CODEPIECE: FOR_IN                {$$=$1}
 CODEPIECE: WHILE                 {$$=$1}
 CODEPIECE: DO_WHILE              {$$=$1}
+CODEPIECE: SWITCH                {$$=$1}
 CODEPIECE: BREAK                 {$$=$1}
 CODEPIECE: CONTINUE              {$$=$1}
 CODEPIECE: RETURN                {$$=$1}
@@ -1194,7 +1285,8 @@ CODEPIECE: IF                    {$$=$1}
 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
 
-CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
+CODEBLOCK :  '{' CODE '}' {$$=$2;}
+CODEBLOCK :  '{' '}'      {$$=0;}
 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
 
@@ -1205,43 +1297,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 {
@@ -1263,7 +1348,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);
@@ -1281,54 +1366,105 @@ IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
     $$ = killvars($$);old_state();
 }
 
-MAYBELABEL : T_IDENTIFIER ':' {$$=$1;}
-MAYBELABEL :                  {$$="";}
-
 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 : MAYBELABEL "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($$, $5);
+    $$ = code_append($$, $2);
     code_t*loopstart = $$ = abc_label($$);
-    $$ = code_append($$, $7.c);
+    $$ = code_append($$, $4.c);
     code_t*myif = $$ = abc_iffalse($$, 0);
-    $$ = code_append($$, $11);
+    $$ = code_append($$, $8);
     code_t*cont = $$ = abc_nop($$);
-    $$ = code_append($$, $9);
+    $$ = 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();
 }
 
-WHILE : MAYBELABEL "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($$, $7);
-    myjmp->branch = $$ = abc_nop($$);
-    $$ = code_append($$, $5.c);
+    $$ = code_append($$, $6);
+    code_t*cont = $$ = abc_nop($$);
+    myjmp->branch = cont;
+    $$ = code_append($$, $4.c);
     $$ = abc_iftrue($$, loopstart);
     code_t*out = $$ = abc_nop($$);
     breakjumpsto($$, $1, out);
-    continuejumpsto($$, $1, loopstart);
+    continuejumpsto($$, $1, cont);
 
     $$ = killvars($$);
     old_state();
 }
 
-DO_WHILE : MAYBELABEL "do" {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
+DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
     $$ = code_new();
     code_t*loopstart = $$ = abc_label($$);
-    $$ = code_append($$, $4);
+    $$ = code_append($$, $3);
     code_t*cont = $$ = abc_nop($$);
-    $$ = code_append($$, $7.c);
+    $$ = code_append($$, $6.c);
     $$ = abc_iftrue($$, loopstart);
     code_t*out = $$ = abc_nop($$);
     breakjumpsto($$, $1, out);
@@ -1350,15 +1486,61 @@ 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();
+}
+
 /* ------------ 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" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBECODE '}' {endpackage()}
 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
 
 IMPORT : "import" QNAME {
@@ -1581,6 +1763,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
@@ -1591,6 +1774,7 @@ QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
 
 TYPE : QNAME      {$$=$1;}
      | '*'        {$$=registry_getanytype();}
+     | "void"     {$$=registry_getanytype();}
     /*
      |  "String"  {$$=registry_getstringclass();}
      |  "int"     {$$=registry_getintclass();}
@@ -1604,19 +1788,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);
@@ -1629,17 +1812,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;
 }
 
@@ -1648,47 +1826,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;
@@ -1699,6 +1871,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");
@@ -1707,18 +1880,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;
 }
@@ -1996,15 +2166,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)) {
@@ -2150,7 +2341,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;
@@ -2168,7 +2359,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;
@@ -2196,17 +2387,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((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);
@@ -2236,7 +2428,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);