made pool_optimize sort entries the other way around, dump frequencies in pool_dump()
[swftools.git] / lib / as3 / parser.y
index 0c8c635..6b52765 100644 (file)
     constant_t*constant;
     for_start_t for_start;
     abc_exception_t *exception;
-    abc_exception_list_t *exception_list;
+    regexp_t regexp;
+    struct {
+        abc_exception_list_t *l;
+        code_t*finally;
+    } catch_list;
 }
 
 
 %token<id> T_IDENTIFIER
 %token<str> T_STRING
-%token<token> T_REGEXP
+%token<regexp> T_REGEXP
 %token<token> T_EMPTY
 %token<number_int> T_INT
 %token<number_uint> T_UINT
 %token<id> T_DO "do"
 %token<id> T_SWITCH "switch"
 
-%token<token> KW_IMPLEMENTS
+%token<token> KW_IMPLEMENTS "implements"
 %token<token> KW_NAMESPACE "namespace"
 %token<token> KW_PACKAGE "package"
-%token<token> KW_PROTECTED
-%token<token> KW_PUBLIC
-%token<token> KW_PRIVATE
+%token<token> KW_PROTECTED "protected"
+%token<token> KW_PUBLIC "public"
+%token<token> KW_PRIVATE "private"
 %token<token> KW_USE "use"
-%token<token> KW_INTERNAL
+%token<token> KW_INTERNAL "internal"
 %token<token> KW_NEW "new"
-%token<token> KW_NATIVE
+%token<token> KW_NATIVE "native"
 %token<token> KW_FUNCTION "function"
+%token<token> KW_FINALLY "finally"
 %token<token> KW_UNDEFINED "undefined"
 %token<token> KW_CONTINUE "continue"
 %token<token> KW_CLASS "class"
 %token<token> KW_SET "set"
 %token<token> KW_VOID "void"
 %token<token> KW_THROW "throw"
-%token<token> KW_STATIC
+%token<token> KW_STATIC "static"
+%token<token> KW_WITH "with"
 %token<token> KW_INSTANCEOF "instanceof"
 %token<token> KW_IMPORT "import"
 %token<token> KW_RETURN "return"
 %token<token> KW_NULL "null"
 %token<token> KW_VAR "var"
 %token<token> KW_DYNAMIC "dynamic"
-%token<token> KW_OVERRIDE
-%token<token> KW_FINAL
+%token<token> KW_OVERRIDE "override"
+%token<token> KW_FINAL "final"
 %token<token> KW_EACH "each"
 %token<token> KW_GET "get"
 %token<token> KW_TRY "try"
 %token<token> KW_SUPER "super"
-%token<token> KW_EXTENDS
+%token<token> KW_EXTENDS "extends"
 %token<token> KW_FALSE "false"
 %token<token> KW_TRUE "true"
 %token<token> KW_BOOLEAN "Boolean"
 %token<token> T_NEE "!=="
 %token<token> T_LE "<="
 %token<token> T_GE ">="
+%token<token> T_ORBY "|=" 
 %token<token> T_DIVBY "/=" 
 %token<token> T_MODBY "%="
 %token<token> T_MULBY "*="
 %token<token> T_SHR ">>"
 
 %type <for_start> FOR_START
-%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
+%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
 %type <token> VARCONST
 %type <code> CODE
 %type <code> CODEPIECE CODE_STATEMENT
-%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
+%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 <exception> CATCH FINALLY
+%type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
 %type <code> CLASS_DECLARATION
 %type <code> NAMESPACE_DECLARATION
 %type <code> INTERFACE_DECLARATION
 %type <value> MAYBEEXPRESSION
 %type <value> E DELETE
 %type <value> CONSTANT
-%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
+%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY 
+%type <value> INNERFUNCTION
 %type <token> USE_NAMESPACE
 %type <code> FOR_INIT
 %type <code> IMPORT
 %right '?' ':'
 %left "||"
 %left "&&"
-%nonassoc '|'
-%nonassoc '^'
+%left '|'
+%left '^'
 %nonassoc '&'
 %nonassoc "==" "!=" "===" "!=="
 %nonassoc "is" "as" "in"
 // needed for "return" precedence:
 %nonassoc T_STRING T_REGEXP
 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
-%nonassoc "false" "true" "null" "undefined" "super"
+%nonassoc "false" "true" "null" "undefined" "super" "function"
+%nonassoc above_function
 
 
      
 static int yyerror(char*s)
 {
    syntaxerror("%s", s); 
+   return 0; //make gcc happy
 }
 
 static char* concat2(const char* t1, const char* t2)
@@ -288,9 +298,6 @@ typedef struct _methodstate {
     /* method data */
     memberinfo_t*info;
     char late_binding;
-    /* code that needs to be executed at the start of
-       a method (like initializing local registers) */
-    code_t*initcode;
     char is_constructor;
     char has_super;
     char is_global;
@@ -300,7 +307,7 @@ typedef struct _methodstate {
 typedef struct _state {
     struct _state*old;
     int level;
-
+    
     char*package;     
     import_list_t*wildcard_imports;
     dict_t*imports;
@@ -335,8 +342,7 @@ DECLARE_LIST(state);
     multiname_t m;\
     namespace_t m##_ns;\
     if(f) { \
-        m##_ns.access = flags2access(f->flags); \
-        m##_ns.name = ""; \
+        m##_ns = flags2namespace(f->flags, ""); \
         m.type = QNAME; \
         m.ns = &m##_ns; \
         m.namespace_set = 0; \
@@ -419,30 +425,56 @@ static void old_state()
     if(!state || !state->old)
         syntaxerror("invalid nesting");
     state_t*leaving = state;
+    
     state = state->old;
-    /*if(state->method->initcode) {
-        printf("residual initcode\n");
-        code_dump(state->method->initcode, 0, 0, "", stdout);
-    }*/
     state_destroy(leaving);
 }
-void initialize_state()
+
+void initialize_parser()
 {
     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);
+    global->init = abc_initscript(global->file);
     code_t*c = global->init->method->body->code;
-
     c = abc_getlocal_0(c);
     c = abc_pushscope(c);
-  
+    /*c = abc_findpropstrict(c, "[package]::trace");
+    c = abc_pushstring(c, "[entering global init function]");
+    c = abc_callpropvoid(c, "[package]::trace", 1);*/
+    global->init->method->body->code = c;
+}
+
+void initialize_file(char*filename)
+{
+    new_state();
+    state->package = filename;
+    // needed for state->method->late_binding:
+    state->method = rfx_calloc(sizeof(methodstate_t));
+}
+void finish_file()
+{
+    if(!state || state->level!=1) {
+        syntaxerror("unexpected end of file");
+    }
+    state_destroy(state);state=0;
+}
+
+void* finish_parser()
+{
+    code_t*c = global->init->method->body->code;
+    /*c = abc_findpropstrict(c, "[package]::trace");
+      c = abc_pushstring(c, "[leaving global init function]");
+      c = abc_callpropvoid(c, "[package]::trace", 1);*/
+    c = abc_returnvoid(c);
+    global->init->method->body->code = c;
+    return global->file;
+}
+
+
+static void xx_scopetest() 
+{
     /* findpropstrict doesn't just return a scope object- it
        also makes it "active" somehow. Push local_0 on the
        scope stack and read it back with findpropstrict, it'll
@@ -468,29 +500,115 @@ void initialize_state()
     c = abc_getlocal_3(c);
     c = abc_kill(c, 3);
     c = abc_iftrue(c,xx);*/
+}
 
-    c = abc_findpropstrict(c, "[package]::trace");
-    c = abc_pushstring(c, "[entering global init function]");
-    c = abc_callpropvoid(c, "[package]::trace", 1);
+
+typedef struct _variable {
+    int index;
+    classinfo_t*type;
+    char init;
+} variable_t;
+
+static variable_t* find_variable(char*name)
+{
+    state_t* s = state;
+    while(s) {
+        variable_t*v = 0;
+        if(s->method)
+            v = dict_lookup(s->vars, name);
+        if(v) {
+            return v;
+        }
+        s = s->old;
+    }
+    return 0;
+} 
+static variable_t* find_variable_safe(char*name)
+{
+    variable_t* v = find_variable(name);
+    if(!v)
+        syntaxerror("undefined variable: %s", name);
+    return v;
+}
+static char variable_exists(char*name) 
+{
+    return dict_lookup(state->vars, name)!=0;
+}
+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;
+    v->init = init;
     
-    global->init->method->body->code = c;
+    dict_put(state->vars, name, v);
+
+    return global->variable_count++;
 }
-void* finalize_state()
+#define TEMPVARNAME "__as3_temp__"
+static int gettempvar()
 {
-    if(state->level!=1) {
-        syntaxerror("unexpected end of file");
+    variable_t*v = find_variable(TEMPVARNAME);
+    if(v) 
+        return v->index;
+    return new_variable(TEMPVARNAME, 0, 0);
+}
+
+code_t* var_block(code_t*body) 
+{
+    code_t*c = 0;
+    code_t*k = 0;
+    int t;
+    int num=0;
+    for(t=0;t<state->vars->hashsize;t++) {
+        dictentry_t*e = state->vars->slots[t];
+        while(e) {
+            variable_t*v = (variable_t*)e->data;
+            if(v->type && v->init) {
+                c = defaultvalue(c, v->type);
+                c = abc_setlocal(c, v->index);
+                k = abc_kill(k, v->index); 
+                num++;
+            }
+            e = e->next;
+        }
     }
-    abc_method_body_t*m = global->init->method->body;
-    //__ popscope(m);
-    
-    __ findpropstrict(m, "[package]::trace");
-    __ pushstring(m, "[leaving global init function]");
-    __ callpropvoid(m, "[package]::trace", 1);
-    __ returnvoid(m);
 
-    state_destroy(state);
+    if(k) {
+        code_t*x = body;
+        while(x) {
+            if(x->opcode== OPCODE___BREAK__ ||
+               x->opcode== OPCODE___CONTINUE__) {
+               /* link kill code before break/continue */
+                code_t*e = code_dup(k);
+                code_t*s = code_start(e);
+                s->prev = x->prev;
+                if(x->prev) {
+                    x->prev->next = s;
+                }
+                e->next = x;
+                x->prev = e;
+            }
+            x = x->prev;
+        }
+    }
+    
+    c = code_append(c, body);
+    c = code_append(c, k);
+    return c;
+}
 
-    return global->file;
+static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
+{
+    c = code_append(c, header);
+    c = code_append(c, var_block(body));
+    /* append return if necessary */
+    if(!c || (c->opcode != OPCODE_RETURNVOID && 
+              c->opcode != OPCODE_RETURNVALUE)) {
+        c = abc_returnvoid(c);
+    }
+    return c;
 }
 
 
@@ -511,7 +629,7 @@ static void endpackage()
     old_state();
 }
 
-char*globalclass=0;
+char*as3_globalclass=0;
 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
 {
     if(state->cls) {
@@ -520,24 +638,15 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     new_state();
     global->variable_count = 1;
     state->cls = rfx_calloc(sizeof(classstate_t));
+    state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
 
     token_list_t*t=0;
     classinfo_list_t*mlist=0;
-    /*printf("entering class %s\n", name);
-    printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
-    if(extends) 
-        printf("  extends: %s.%s\n", extends->package, extends->name);
-    printf("  implements (%d): ", list_length(implements));
-    for(mlist=implements;mlist;mlist=mlist->next)  {
-        printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
-    }
-    printf("\n");
-    */
 
-    if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
+    if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
         syntaxerror("invalid modifier(s)");
 
-    if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
+    if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
         syntaxerror("public and internal not supported at the same time.");
 
     /* create the class name, together with the proper attributes */
@@ -642,28 +751,16 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     __ setslot(m, slotindex);
 
     /* flash.display.MovieClip handling */
-    if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
+    if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
         if(state->package && state->package[0]) {
-            globalclass = concat3(state->package, ".", classname);
+            as3_globalclass = concat3(state->package, ".", classname);
         } else {
-            globalclass = strdup(classname);
+            as3_globalclass = strdup(classname);
         }
     }
     multiname_destroy(extends2);
 }
 
-static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
-{
-    c = code_append(c, initcode);
-    c = code_append(c, body);
-    /* append return if necessary */
-    if(!c || c->opcode != OPCODE_RETURNVOID && 
-             c->opcode != OPCODE_RETURNVALUE) {
-        c = abc_returnvoid(c);
-    }
-    return c;
-}
-
 static void endclass()
 {
     if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
@@ -672,6 +769,13 @@ static void endclass()
         c = abc_constructsuper(c, 0);
         state->cls->init = code_append(state->cls->init, c);
     }
+    if(!state->method->late_binding) {
+        // class initialization code uses late binding
+        code_t*c = 0;
+        c = abc_getlocal_0(c);
+        c = abc_pushscope(c);
+        state->cls->static_init = code_append(c, state->cls->static_init);
+    }
 
     if(state->cls->init) {
         abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
@@ -680,93 +784,13 @@ static void endclass()
     if(state->cls->static_init) {
         abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
         m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
-    } else {
-        // handy for scope testing 
-        /*code_t*c = 0;
-        c = abc_pop(c);
-        c = abc_pop(c);
-        abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
     }
 
     free(state->cls);state->cls=0;
+    free(state->method);state->method=0;
     old_state();
 }
 
-typedef struct _variable {
-    int index;
-    classinfo_t*type;
-} variable_t;
-
-static variable_t* find_variable(char*name)
-{
-    state_t* s = state;
-    while(s) {
-        variable_t*v = 0;
-        if(s->method)
-            v = dict_lookup(s->vars, name);
-        if(v) {
-            return v;
-        }
-        s = s->old;
-    }
-    return 0;
-} 
-static variable_t* find_variable_safe(char*name)
-{
-    variable_t* v = find_variable(name);
-    if(!v)
-        syntaxerror("undefined variable: %s", name);
-    return v;
-}
-static char variable_exists(char*name) 
-{
-    return dict_lookup(state->vars, name)!=0;
-}
-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()
-{
-    variable_t*v = find_variable(TEMPVARNAME);
-    if(v) 
-        return v->index;
-    return new_variable(TEMPVARNAME, 0, 0);
-}
-
-code_t* killvars(code_t*c) 
-{
-    int t;
-    for(t=0;t<state->vars->hashsize;t++) {
-        dictentry_t*e =state->vars->slots[t];
-        while(e) {
-            variable_t*v = (variable_t*)e->data;
-            //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); 
-            e = e->next;
-        }
-    }
-    return c;
-}
-
 void check_code_for_break(code_t*c)
 {
     while(c) {
@@ -801,17 +825,21 @@ 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");
+        if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
+            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");
+        if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
+            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");
+        if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL)) 
+            syntaxerror("invalid combination of access levels");
         access = ACCESS_PROTECTED;
     } else {
         access = ACCESS_PACKAGEINTERNAL;
@@ -819,6 +847,7 @@ static int flags2access(int flags)
     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;
@@ -875,7 +904,7 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
     if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
     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_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
     if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
     return minfo;
 }
@@ -883,14 +912,14 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
                           params_t*params, classinfo_t*return_type)
 {
-    if(state->method) {
+    if(state->method && state->method->info) {
         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->has_super = 0;
+
     if(state->cls) {
         state->method->is_constructor = !strcmp(state->cls->info->name,name);
         state->cls->has_constructor |= state->method->is_constructor;
@@ -924,7 +953,7 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam
     if(state->method->is_constructor) {
         f = abc_class_getconstructor(state->cls->abc, type2);
     } else if(!state->method->is_global) {
-        namespace_t mname_ns = {flags2access(flags), ""};
+        namespace_t mname_ns = flags2namespace(flags, "");
         multiname_t mname = {QNAME, &mname_ns, 0, name};
 
         if(flags&FLAG_STATIC)
@@ -933,7 +962,7 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam
             f = abc_class_method(state->cls->abc, type2, &mname);
         slot = f->trait->slot_id;
     } else {
-        namespace_t mname_ns = {flags2access(flags), state->package};
+        namespace_t mname_ns = flags2namespace(flags, state->package);
         multiname_t mname = {QNAME, &mname_ns, 0, name};
 
         f = abc_method_new(global->file, type2, 1);
@@ -1011,12 +1040,25 @@ void continuejumpsto(code_t*c, char*name, code_t*jump)
     }
 }
 
+#define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
+#define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
+#define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
+
 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
 {
     if(!type1 || !type2) 
         return registry_getanytype();
     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
         return registry_getanytype();
+
+    if(op=='+') {
+        if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
+            return TYPE_NUMBER;
+        } else {
+            return TYPE_ANY;
+        }
+    }
+
     if(type1 == type2)
         return type1;
     return registry_getanytype();
@@ -1064,6 +1106,7 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
         return c;
     syntaxerror("can't convert type %s to %s", from->name, to->name);
+    return 0; // make gcc happy
 }
 
 code_t*defaultvalue(code_t*c, classinfo_t*type)
@@ -1076,8 +1119,12 @@ code_t*defaultvalue(code_t*c, classinfo_t*type)
        c = abc_pushnan(c);
     } else if(TYPE_IS_BOOLEAN(type)) {
        c = abc_pushfalse(c);
+    } else if(!type) {
+       //c = abc_pushundefined(c);
     } else {
        c = abc_pushnull(c);
+       MULTINAME(m, type);
+       c = abc_coerce2(c, &m);
     }
     return c;
 }
@@ -1130,6 +1177,27 @@ static classinfo_t* find_class(char*name)
     return 0;
 }
 
+static char is_getlocal(code_t*c)
+{
+    if(!c || c->prev || c->next)
+        return 0;
+    return(c->opcode == OPCODE_GETLOCAL
+        || c->opcode == OPCODE_GETLOCAL_0
+        || c->opcode == OPCODE_GETLOCAL_1
+        || c->opcode == OPCODE_GETLOCAL_2
+        || c->opcode == OPCODE_GETLOCAL_3);
+}
+static int getlocalnr(code_t*c)
+{
+    if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
+    else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
+    else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
+    else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
+    else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
+    else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
+    return 0;
+}
+
 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
 {
     /* converts this:
@@ -1206,7 +1274,7 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
         write->opcode = OPCODE_SETLOCAL_3;
     } else {
-        code_dump(r, 0, 0, "", stdout);
+        code_dump(r);
         syntaxerror("illegal lvalue: can't assign a value to this expression");
     }
     code_t* c = 0;
@@ -1272,12 +1340,139 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
             c = abc_kill(c, temp);
         }
     }
+    return c;
+}
+
+char is_break_or_jump(code_t*c)
+{
+    if(!c)
+        return 0;
+    if(c->opcode == OPCODE_JUMP ||
+       c->opcode == OPCODE___BREAK__ ||
+       c->opcode == OPCODE___CONTINUE__ ||
+       c->opcode == OPCODE_THROW ||
+       c->opcode == OPCODE_RETURNVOID ||
+       c->opcode == OPCODE_RETURNVALUE) {
+       return 1;
+    }
+    return 0;
+}
+
+
+#define IS_FINALLY_TARGET(op) \
+        ((op) == OPCODE___CONTINUE__ || \
+         (op) == OPCODE___BREAK__ || \
+         (op) == OPCODE_RETURNVOID || \
+         (op) == OPCODE_RETURNVALUE || \
+         (op) == OPCODE___RETHROW__)
+
+static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
+{
+#define NEED_EXTRA_STACK_ARG
+    code_t*finally_label = abc_nop(0);
+    NEW(lookupswitch_t, l);
+    //_lookupswitch
+
+    code_t*i = c;
+    int count=0;
+    while(i) {
+        code_t*prev = i->prev;
+        if(IS_FINALLY_TARGET(i->opcode)) {
+           code_t*p = prev;
+           char needvalue=0;
+           if(i->opcode == OPCODE___RETHROW__ ||
+              i->opcode == OPCODE_RETURNVALUE) {
+               if(i->opcode == OPCODE___RETHROW__)
+                 i->opcode = OPCODE_THROW;
+               needvalue=1;
+               p = abc_coerce_a(p);
+               p = abc_setlocal(p, tempvar);
+           }
+           p = abc_pushbyte(p, count++);
+           p = abc_jump(p, finally_label);
+           code_t*target = p = abc_label(p);
+#ifdef NEED_EXTRA_STACK_ARG
+           p = abc_pop(p);
+#endif
+           if(needvalue) {
+               p = abc_getlocal(p, tempvar);
+           }
+
+           p->next = i;i->prev = p;
+           list_append(l->targets, target);
+        }
+        i = prev;
+    }
+
+    code_t*j,*f;
+    c = abc_pushbyte(c, -1);
+    c = code_append(c, finally_label);
+    c = code_append(c, finally);
+
+#ifdef NEED_EXTRA_STACK_ARG
+    c = abc_dup(c);
+#endif
+    c = abc_lookupswitch(c, l);
+    c = l->def = abc_label(c);
+#ifdef NEED_EXTRA_STACK_ARG
+    c = abc_pop(c);
+#endif
 
     return c;
 }
 
-#define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
-#define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
+static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
+{
+    code_t*i = c;
+    while(i) {
+        code_t*prev = i->prev;
+        if(IS_FINALLY_TARGET(i->opcode)) {
+           if(i->opcode == OPCODE___RETHROW__)
+                i->opcode = OPCODE_THROW;
+           code_t*end = code_dup(finally);
+           code_t*start = code_start(end);
+           if(prev) prev->next = start;
+           start->prev = prev;
+           i->prev = end;
+           end->next = i;
+        }
+        i = prev;
+    }
+    return code_append(c, finally);
+}
+
+code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
+{
+    if(!finally)
+        return c;
+    code_t*i = c;
+    char cantdup=0;
+    int num_insertion_points=0;
+    while(i) {
+        if(IS_FINALLY_TARGET(i->opcode))
+            num_insertion_points++;
+        i = i->prev;
+    }
+    i = finally;
+    int code_size=0;
+    while(i) {
+        code_size++;
+        if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
+            cantdup=1;
+        }
+        i = i->prev;
+    }
+    int simple_version_cost = (1+num_insertion_points)*code_size;
+    int lookup_version_cost = 4*num_insertion_points + 5;
+
+    if(cantdup || simple_version_cost > lookup_version_cost) {
+        printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
+        return insert_finally_lookup(c, finally, tempvar);
+    } else {
+        printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
+        return insert_finally_simple(c, finally, tempvar);
+    }
+}
 
 %}
 
@@ -1319,19 +1514,20 @@ CODE: CODEPIECE {$$=$1;}
 
 // code which also may appear outside a method
 CODE_STATEMENT: IMPORT 
-CODE_STATEMENT: VOIDEXPRESSION 
 CODE_STATEMENT: FOR 
 CODE_STATEMENT: FOR_IN 
 CODE_STATEMENT: WHILE 
 CODE_STATEMENT: DO_WHILE 
 CODE_STATEMENT: SWITCH 
 CODE_STATEMENT: IF
+CODE_STATEMENT: WITH
 CODE_STATEMENT: TRY
+CODE_STATEMENT: VOIDEXPRESSION 
 
 // code which may appear anywhere
 CODEPIECE: ';' {$$=0;}
-CODEPIECE: VARIABLE_DECLARATION
 CODEPIECE: CODE_STATEMENT
+CODEPIECE: VARIABLE_DECLARATION
 CODEPIECE: BREAK
 CODEPIECE: CONTINUE
 CODEPIECE: RETURN
@@ -1348,7 +1544,8 @@ CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
 /* ------------ package init code ------------------- */
 
 PACKAGE_INITCODE: CODE_STATEMENT {
-    if($1) warning("code ignored");
+    code_t**cc = &global->init->method->body->code;
+    *cc = code_append(*cc, $1);
 }
 
 /* ------------ variables --------------------------- */
@@ -1410,6 +1607,7 @@ MAYBEELSE: "else" CODEBLOCK {$$=$2;}
 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
 
 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
+     
     $$ = code_new();
     $$ = code_append($$, $4.c);
     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
@@ -1423,13 +1621,15 @@ IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
         $$ = code_append($$, $7);
         myjmp->branch = $$ = abc_nop($$);
     }
-    
-    $$ = killvars($$);old_state();
+    $$ = var_block($$);
+    old_state();
 }
 
 FOR_INIT : {$$=code_new();}
 FOR_INIT : VARIABLE_DECLARATION
 FOR_INIT : VOIDEXPRESSION
+
+// TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
     $$=$2;new_variable($2,$3,1);
 }
@@ -1456,7 +1656,8 @@ FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
     continuejumpsto($$, $1.name, cont);
     myif->branch = out;
 
-    $$ = killvars($$);old_state();
+    $$ = var_block($$);
+    old_state();
 }
 
 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
@@ -1493,16 +1694,17 @@ FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
     breakjumpsto($$, $1.name, out);
     continuejumpsto($$, $1.name, loopstart);
     
-    $$ = killvars($$);
-    
     myif->branch = out;
 
+    $$ = var_block($$);
     old_state();
+
     free(tmp1name);
     free(tmp2name);
 }
 
 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
+
     $$ = code_new();
 
     code_t*myjmp = $$ = abc_jump($$, 0);
@@ -1516,7 +1718,7 @@ WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
     breakjumpsto($$, $1, out);
     continuejumpsto($$, $1, cont);
 
-    $$ = killvars($$);
+    $$ = var_block($$);
     old_state();
 }
 
@@ -1530,7 +1732,8 @@ DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
     code_t*out = $$ = abc_nop($$);
     breakjumpsto($$, $1, out);
     continuejumpsto($$, $1, cont);
-    $$ = killvars($$);
+    
+    $$ = var_block($$);
     old_state();
 }
 
@@ -1590,56 +1793,111 @@ SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
         }
         c=c->prev;
     }
+   
+    $$ = var_block($$);
     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);
-    
+        '{' MAYBECODE '}' {
     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;
+
+    code_t*c = 0;
+    int i = find_variable_safe($3)->index;
+    e->target = c = abc_nop(0);
+    c = abc_setlocal(c, i);
+    c = code_append(c, $8);
+    c = abc_kill(c, i);
+
+    c = var_block(c);
     old_state();
 }
+FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
+    $4 = var_block($4);
+    if(!$4) {
+        $$=0;
+        old_state();
+    } else {
+        NEW(abc_exception_t, e)
+        e->exc_type = 0; //all exceptions
+        e->var_name = 0; //no name
+        e->target = 0;
+        e->to = abc_nop(0);
+        e->to = code_append(e->to, $4);
+        old_state();
+        $$ = e;
+    }
+}
 
-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;
+CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
+CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
+CATCH_FINALLY_LIST: CATCH_LIST {$$=$1};
+CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
+    $$ = $1;
+    $$.finally = 0;
+    if($2) {
+        list_append($$.l,$2);
+        $$.finally = $2->to;$2->to=0;
+    }
+}
+CATCH_FINALLY_LIST: FINALLY {
+    $$.l=list_new();
+    $$.finally = 0;
+    if($1) {
+        list_append($$.l,$1);
+        $$.finally = $1->to;$1->to=0;
+    }
+}
 
+TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
     code_t*out = abc_nop(0);
-    code_t*jmp = $$ = abc_jump($$, out);
 
-    abc_exception_list_t*l = $5;
+    code_t*start = abc_nop(0);
+    $$ = code_append(start, $4);
+    if(!is_break_or_jump($4)) {
+        $$ = abc_jump($$, out);
+    }
+    code_t*end = $$ = abc_nop($$);
+  
+    int tmp;
+    if($6.finally)
+        tmp = new_variable("__finally__", 0, 0);
+    
+    abc_exception_list_t*l = $6.l;
+    int count=0;
     while(l) {
         abc_exception_t*e = l->abc_exception;
+        if(e->var_name) {
+            $$ = code_append($$, e->target);
+            $$ = abc_jump($$, out);
+        } else {
+            parserassert((ptroff_t)$6.finally);
+            // finally block
+            e->target = $$ = abc_nop($$);
+            $$ = abc___rethrow__($$);
+        }
+        
         e->from = start;
-        e->to = jmp;
-        $$ = code_append($$, e->target);
-        $$ = abc_jump($$, out);
+        e->to = end;
+
         l = l->next;
     }
     $$ = code_append($$, out);
-    jmp->branch = out;
+
+    $$ = insert_finally($$, $6.finally, tmp);
         
-    list_concat(state->method->exceptions, $5);
+    list_concat(state->method->exceptions, $6.l);
+   
+    $$ = var_block($$);
+    old_state();
 }
 
 /* ------------ throw ------------------------------- */
@@ -1657,6 +1915,15 @@ THROW : "throw" %prec prec_none {
     $$=abc_throw($$);
 }
 
+/* ------------ with -------------------------------- */
+
+WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
+     $$ = $3.c;
+     $$ = abc_pushscope($$);
+     $$ = code_append($$, $5);
+     $$ = abc_popscope($$);
+}
+
 /* ------------ packages and imports ---------------- */
 
 X_IDENTIFIER: T_IDENTIFIER
@@ -1686,7 +1953,7 @@ IMPORT : "import" PACKAGE '.' '*' {
 
 /* ------------ classes and interfaces (header) -------------- */
 
-MAYBE_MODIFIERS : {$$=0;}
+MAYBE_MODIFIERS : %prec above_function {$$=0;}
 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
 MODIFIER_LIST : MODIFIER               {$$=$1;}
 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
@@ -1699,7 +1966,7 @@ MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
          | KW_FINAL {$$=FLAG_FINAL;}
          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
          | KW_NATIVE {$$=FLAG_NATIVE;}
-         | KW_INTERNAL {$$=FLAG_INTERNAL;}
+         | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
 
 EXTENDS : {$$=registry_getobjectclass();}
 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
@@ -1748,7 +2015,7 @@ IDECLARATION : "var" T_IDENTIFIER {
 }
 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
     $1 |= FLAG_PUBLIC;
-    if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
+    if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
         syntaxerror("invalid method modifiers: interface methods always need to be public");
     }
     startfunction(0,$1,$3,$4,&$6,$8);
@@ -1891,11 +2158,19 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P
         c = abc_getlocal_0(c);
         c = abc_constructsuper(c, 0);
     }
-    c = wrap_function(c, state->method->initcode, $11);
+    c = wrap_function(c, 0, $11);
     endfunction(0,$1,$3,$4,&$6,$8,c);
     $$=0;
 }
 
+MAYBE_IDENTIFIER: T_IDENTIFIER
+MAYBE_IDENTIFIER: {$$=0;}
+INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
+{
+    syntaxerror("nested functions not supported yet");
+}
+
+
 /* ------------- package + class ids --------------- */
 
 CLASS: T_IDENTIFIER {
@@ -2083,13 +2358,32 @@ VOIDEXPRESSION : EXPRESSION %prec below_minus {
 
 // ----------------------- expression evaluation -------------------------------------
 
+E : INNERFUNCTION %prec prec_none {$$ = $1;}
+//V : CONSTANT                    {$$ = 0;}
 E : CONSTANT
+//V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
+//V : NEW                         {$$ = $1.c;}
 E : NEW                         {$$ = $1;}
+//V : DELETE                      {$$ = $1.c;}
 E : DELETE                      {$$ = $1;}
-E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
-                                 $$.t = TYPE_ANY;
-                                }
+
+E : T_REGEXP {
+    $$.c = 0;
+    namespace_t ns = {ACCESS_PACKAGE, ""};
+    multiname_t m = {QNAME, &ns, 0, "RegExp"};
+    if(!$1.options) {
+        $$.c = abc_getlex2($$.c, &m);
+        $$.c = abc_pushstring($$.c, $1.pattern);
+        $$.c = abc_construct($$.c, 1);
+    } else {
+        $$.c = abc_getlex2($$.c, &m);
+        $$.c = abc_pushstring($$.c, $1.pattern);
+        $$.c = abc_pushstring($$.c, $1.options);
+        $$.c = abc_construct($$.c, 2);
+    }
+    $$.t = TYPE_REGEXP;
+}
 
 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
                    //MULTINAME(m, registry_getintclass());
@@ -2204,15 +2498,6 @@ E : E '|' E {$$.c = code_append($1.c,$3.c);
              $$.t = TYPE_INT;
             }
 
-E : E '-' E {$$.c = code_append($1.c,$3.c);
-             if(BOTH_INT($1,$3)) {
-                $$.c = abc_subtract_i($$.c);
-                $$.t = TYPE_INT;
-             } else {
-                $$.c = abc_subtract($$.c);
-                $$.t = TYPE_NUMBER;
-             }
-            }
 E : E ">>" E {$$.c = code_append($1.c,$3.c);
              $$.c = abc_rshift($$.c);
              $$.t = TYPE_INT;
@@ -2230,16 +2515,30 @@ E : E '/' E {$$.c = code_append($1.c,$3.c);
              $$.c = abc_divide($$.c);
              $$.t = TYPE_NUMBER;
             }
-E : E '+' E {$$.c = code_append($1.c,$3.c);
-             $$.c = abc_add($$.c);
-             $$.t = TYPE_NUMBER;
-            }
 E : E '%' E {$$.c = code_append($1.c,$3.c);
              $$.c = abc_modulo($$.c);
              $$.t = TYPE_NUMBER;
             }
+E : E '+' E {$$.c = code_append($1.c,$3.c);
+             if(BOTH_INT($1.t, $3.t)) {
+                $$.c = abc_add_i($$.c);
+                $$.t = TYPE_INT;
+             } else {
+                $$.c = abc_add($$.c);
+                $$.t = join_types($1.t,$3.t,'+');
+             }
+            }
+E : E '-' E {$$.c = code_append($1.c,$3.c);
+             if(BOTH_INT($1.t,$3.t)) {
+                $$.c = abc_subtract_i($$.c);
+                $$.t = TYPE_INT;
+             } else {
+                $$.c = abc_subtract($$.c);
+                $$.t = TYPE_NUMBER;
+             }
+            }
 E : E '*' E {$$.c = code_append($1.c,$3.c);
-             if(BOTH_INT($1,$3)) {
+             if(BOTH_INT($1.t,$3.t)) {
                 $$.c = abc_multiply_i($$.c);
                 $$.t = TYPE_INT;
              } else {
@@ -2296,7 +2595,7 @@ E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
 
 E : '-' E {
   $$=$2;
-  if(IS_INT($2)) {
+  if(IS_INT($2.t)) {
    $$.c=abc_negate_i($$.c);
    $$.t = TYPE_INT;
   } else {
@@ -2348,7 +2647,7 @@ E : '{' MAYBE_EXPRPAIR_LIST '}' {
 
 E : E "*=" E { 
                code_t*c = $3.c;
-               if(BOTH_INT($1,$3)) {
+               if(BOTH_INT($1.t,$3.t)) {
                 c=abc_multiply_i(c);
                } else {
                 c=abc_multiply(c);
@@ -2388,25 +2687,32 @@ E : E "/=" E {
                $$.c = toreadwrite($1.c, c, 0, 0);
                $$.t = $1.t;
               }
+E : E "|=" E { 
+               code_t*c = abc_bitor($3.c);
+               c=converttype(c, TYPE_INT, $1.t);
+               $$.c = toreadwrite($1.c, c, 0, 0);
+               $$.t = $1.t;
+              }
 E : E "+=" E { 
                code_t*c = $3.c;
-               if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
+
+               if(TYPE_IS_INT($1.t)) {
                 c=abc_add_i(c);
                } else {
                 c=abc_add(c);
+                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
                }
-               c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
                
                $$.c = toreadwrite($1.c, c, 0, 0);
                $$.t = $1.t;
               }
 E : E "-=" E { code_t*c = $3.c; 
-               if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
+               if(TYPE_IS_INT($1.t)) {
                 c=abc_subtract_i(c);
                } else {
                 c=abc_subtract(c);
+                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
                }
-               c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
                
                $$.c = toreadwrite($1.c, c, 0, 0);
                $$.t = $1.t;
@@ -2419,30 +2725,45 @@ E : E '=' E { code_t*c = 0;
             }
 
 E : E '?' E ':' E %prec below_assignment { 
+              $$.t = join_types($3.t,$5.t,'?');
               $$.c = $1.c;
               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
               $$.c = code_append($$.c, $3.c);
+              $$.c = converttype($$.c, $3.t, $$.t);
               code_t*j2 = $$.c = abc_jump($$.c, 0);
               $$.c = j1->branch = abc_label($$.c);
               $$.c = code_append($$.c, $5.c);
+              $$.c = converttype($$.c, $3.t, $$.t);
               $$.c = j2->branch = abc_label($$.c);
-              $$.t = join_types($3.t,$5.t,'?');
             }
 
-// TODO: use inclocal where appropriate
 E : E "++" { code_t*c = 0;
              classinfo_t*type = $1.t;
-             if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
-                 c=abc_increment_i(c);
-                 type = TYPE_INT;
+             if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
+                 int nr = getlocalnr($1.c);
+                 code_free($1.c);$1.c=0;
+                 if(TYPE_IS_INT($1.t)) {
+                    $$.c = abc_getlocal(0, nr);
+                    $$.c = abc_inclocal_i($$.c, nr);
+                 } else if(TYPE_IS_NUMBER($1.t)) {
+                    $$.c = abc_getlocal(0, nr);
+                    $$.c = abc_inclocal($$.c, nr);
+                 } else syntaxerror("internal error");
              } else {
-                 c=abc_increment(c);
-                 type = TYPE_NUMBER;
+                 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
+                     c=abc_increment_i(c);
+                     type = TYPE_INT;
+                 } else {
+                     c=abc_increment(c);
+                     type = TYPE_NUMBER;
+                 }
+                 c=converttype(c, type, $1.t);
+                 $$.c = toreadwrite($1.c, c, 0, 1);
+                 $$.t = $1.t;
              }
-             c=converttype(c, type, $1.t);
-             $$.c = toreadwrite($1.c, c, 0, 1);
-             $$.t = $1.t;
            }
+
+// TODO: use inclocal, like with ++
 E : E "--" { code_t*c = 0;
              classinfo_t*type = $1.t;
              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
@@ -2492,7 +2813,7 @@ E : "super" '.' T_IDENTIFIER
               if(!t) t = TYPE_OBJECT;
 
               memberinfo_t*f = registry_findmember(t, $3, 1);
-              namespace_t ns = {flags2access(f->flags), ""};
+              namespace_t ns = flags2namespace(f->flags, "");
               MEMBER_MULTINAME(m, f, $3);
               $$.c = 0;
               $$.c = abc_getlocal_0($$.c);
@@ -2584,7 +2905,11 @@ VAR_READ : T_IDENTIFIER {
             MULTINAME(m, a);
             $$.c = abc_findpropstrict2($$.c, &m);
             $$.c = abc_getproperty2($$.c, &m);
-            $$.t = TYPE_FUNCTION(a->function);
+            if(a->function->kind == MEMBER_METHOD) {
+                $$.t = TYPE_FUNCTION(a->function);
+            } else {
+                $$.t = a->function->type;
+            }
         } else {
             if(a->slot) {
                 $$.c = abc_getglobalscope($$.c);
@@ -2599,7 +2924,7 @@ VAR_READ : T_IDENTIFIER {
     /* unknown object, let the avm2 resolve it */
     } else {
         if(strcmp($1,"trace"))
-            warning("Couldn't resolve '%s', doing late binding", $1);
+            as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
         state->method->late_binding = 1;
                 
         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};