added implementation for dict-style objects
[swftools.git] / lib / as3 / parser.y
index fbbfdcb..f119828 100644 (file)
 %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<token> KW_IMPLEMENTS
 %token<token> KW_NAMESPACE "namespace"
 %token<token> KW_PACKAGE "package"
 %token<token> KW_NEW "new"
 %token<token> KW_NATIVE
 %token<token> KW_FUNCTION "function"
-%token<token> KW_FOR "for"
+%token<token> KW_UNDEFINED "undefined"
+%token<token> KW_CONTINUE "continue"
 %token<token> KW_CLASS "class"
 %token<token> KW_CONST "const"
 %token<token> KW_SET "set"
+%token<token> KW_VOID "void"
 %token<token> KW_STATIC
+%token<token> KW_INSTANCEOF "instanceof"
 %token<token> KW_IMPORT "import"
 %token<token> KW_RETURN "return"
+%token<token> KW_TYPEOF "typeof"
 %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_GET "get"
+%token<token> KW_SUPER "super"
 %token<token> KW_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_DELETE "delete"
 %token<token> KW_IF "if"
 %token<token> KW_ELSE  "else"
 %token<token> KW_BREAK   "break"
 %token<token> T_EQEQ "=="
 %token<token> T_EQEQEQ "==="
 %token<token> T_NE "!="
+%token<token> T_NEE "!=="
 %token<token> T_LE "<="
 %token<token> T_GE ">="
 %token<token> T_DIVBY "/=" 
 %token<token> T_SHL "<<"
 %token<token> T_USHR ">>>"
 %token<token> T_SHR ">>"
-%token<token> T_SEMICOLON ';'
-%token<token> T_STAR '*'
-%token<token> T_DOT '.'
 
 %type <id> X_IDENTIFIER PACKAGE
 %type <token> VARCONST
 %type <code> VOIDEXPRESSION
 %type <value> EXPRESSION NONCOMMAEXPRESSION
 %type <value> MAYBEEXPRESSION
-%type <value> E
+%type <value> E DELETE
 %type <value> CONSTANT
-%type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
+%type <code> FOR IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
 %type <token> USE_NAMESPACE
 %type <code> FOR_INIT
 %type <token> IMPORT
 //%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
-// http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
 
 %left prec_none
+
+%left below_semicolon
+%left ';'
+%left ','
+%nonassoc below_assignment // for ?:, contrary to spec
+%right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
 %right '?' ':'
-%right '=' "/=" "%=" "*=" "+=" "-=" ">>=" "<<=" ">>>="
 %left "||"
 %left "&&"
 %nonassoc '|'
 %nonassoc '^'
 %nonassoc '&'
-%nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
-%nonassoc "is"
-%left prec_belowminus
-%left '-'
-%left '+'
-%left "<<"
-%left ">>>"
-%left ">>"
-%left '%'
-%left '/'
-%left '*'
-%left '!'
-%left '~'
-%left "--" "++"
-%left '['
-%nonassoc "as"
-%left '.' ".." "::"
+%nonassoc "==" "!=" "===" "!=="
+%nonassoc "is" "as"
+%nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
+%left "<<" ">>" ">>>" 
+%left below_minus
+%left '-' '+'
+%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_semicolon
-%left ';'
+%left below_else
 %nonassoc "else"
 %left '('
 
 // needed for "return" precedence:
 %nonassoc T_STRING T_REGEXP
 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
-%nonassoc "new" "false" "true" "null"
+%nonassoc "false" "true" "null" "undefined" "super"
 
-%left prec_highest
 
      
 %{
@@ -246,37 +249,44 @@ typedef struct _import {
 
 DECLARE_LIST(import);
 
-typedef struct _state {
-    abc_file_t*file;
-    abc_script_t*init;
-
-    int level;
-
-    char*package;     
-    char*function;
+typedef struct _classstate {
+    /* class data */
+    classinfo_t*info;
+    abc_class_t*abc;
+    code_t*init;
+    code_t*static_init;
+    char has_constructor;
+} classstate_t;
+
+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;
+} methodstate_t;
 
+typedef struct _state {
+    int level;
+
+    char*package;     
     import_list_t*wildcard_imports;
     dict_t*imports;
     char has_own_imports;
-   
-    /* class data */
-    classinfo_t*clsinfo;
-    abc_class_t*cls;
-    code_t*cls_init;
-    code_t*cls_static_init;
+  
+    classstate_t*cls;   
+    methodstate_t*method;
     
-    /* method data */
-    memberinfo_t*minfo;
-    abc_method_t*m;
-
     dict_t*vars;
-    char late_binding;
 } state_t;
 
 typedef struct _global {
+    abc_file_t*file;
+    abc_script_t*init;
+
     int variable_count;
 } global_t;
 
@@ -285,7 +295,27 @@ static state_t* state = 0;
 
 DECLARE_LIST(state);
 
-#define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
+#define MULTINAME(m,x) \
+    multiname_t m;\
+    namespace_t m##_ns;\
+    registry_fill_multiname(&m, &m##_ns, x);
+                    
+#define MEMBER_MULTINAME(m,f,n) \
+    multiname_t m;\
+    namespace_t m##_ns;\
+    if(f) { \
+        m##_ns.access = flags2access(f->flags); \
+        m##_ns.name = ""; \
+        m.type = QNAME; \
+        m.ns = &m##_ns; \
+        m.namespace_set = 0; \
+        m.name = f->name; \
+    } else { \
+        m.type = MULTINAME; \
+        m.ns =0; \
+        m.namespace_set = &nopackage_namespace_set; \
+        m.name = n; \
+    }
 
 /* warning: list length of namespace set is undefined */
 #define MULTINAME_LATE(m, access, package) \
@@ -297,6 +327,16 @@ DECLARE_LIST(state);
     m##_l.namespace = &m##_ns; \
     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
 
+static namespace_t ns1 = {ACCESS_PRIVATE, ""};
+static namespace_t ns2 = {ACCESS_PROTECTED, ""};
+static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
+static namespace_t ns4 = {ACCESS_PACKAGE, ""};
+static namespace_list_t nl4 = {&ns4,0};
+static namespace_list_t nl3 = {&ns3,&nl4};
+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()
@@ -320,9 +360,8 @@ static void new_state()
     state_stack = sl;
     state = s;
     state->level++;
+    state->has_own_imports = 0;    
     state->vars = dict_new();
-    state->initcode = 0;
-    state->has_own_imports = 0;
 }
 static void state_has_imports()
 {
@@ -340,26 +379,25 @@ static void old_state()
     state_stack = state_stack->next;
     free(old);
     state = state_stack->state;
-    /*if(state->initcode) {
+    /*if(state->method->initcode) {
         printf("residual initcode\n");
-        code_dump(state->initcode, 0, 0, "", stdout);
+        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->initcode = code_append(state->initcode, oldstate->initcode);
 }
 void initialize_state()
 {
     init_globals();
     new_state();
 
-    state->file = abc_file_new();
-    state->file->flags &= ~ABCFILE_LAZY;
+    global->file = abc_file_new();
+    global->file->flags &= ~ABCFILE_LAZY;
     
-    state->init = abc_initscript(state->file, 0, 0);
-    code_t*c = state->init->method->body->code;
+    global->init = abc_initscript(global->file, 0);
+    code_t*c = global->init->method->body->code;
 
     c = abc_getlocal_0(c);
     c = abc_pushscope(c);
@@ -394,21 +432,21 @@ void initialize_state()
     c = abc_pushstring(c, "[entering global init function]");
     c = abc_callpropvoid(c, "[package]::trace", 1);
     
-    state->init->method->body->code = c;
+    global->init->method->body->code = c;
 }
 void* finalize_state()
 {
     if(state->level!=1) {
         syntaxerror("unexpected end of file");
     }
-    abc_method_body_t*m = state->init->method->body;
+    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);
-    return state->file;
+    return global->file;
 }
 
 
@@ -434,6 +472,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
         syntaxerror("inner classes now allowed"); 
     }
     new_state();
+    state->cls = rfx_calloc(sizeof(classstate_t));
 
     token_list_t*t=0;
     classinfo_list_t*mlist=0;
@@ -448,7 +487,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))
@@ -472,39 +511,45 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
     }
    
+
     /* build info struct */
     int num_interfaces = (list_length(implements));
-    state->clsinfo = classinfo_register(access, package, classname, num_interfaces);
-    state->clsinfo->superclass = extends;
+    state->cls->info = classinfo_register(access, package, classname, num_interfaces);
+    state->cls->info->superclass = extends?extends:TYPE_OBJECT;
     int pos = 0;
     classinfo_list_t*l = implements;
     for(l=implements;l;l=l->next) {
-        state->clsinfo->interfaces[pos++] = l->classinfo;
+        state->cls->info->interfaces[pos++] = l->classinfo;
     }
-
-    MULTINAME(classname2,state->clsinfo);
     
     multiname_t*extends2 = sig2mname(extends);
 
+    MULTINAME(classname2,state->cls->info);
+
     /*if(extends) {
         state->cls_init = abc_getlocal_0(state->cls_init);
         state->cls_init = abc_constructsuper(state->cls_init, 0);
     }*/
 
-    state->cls = abc_class_new(state->file, &classname2, extends2);
-    if(flags&FLAG_FINAL) abc_class_final(state->cls);
-    if(flags&FLAG_DYNAMIC) abc_class_sealed(state->cls);
-    if(interface) abc_class_interface(state->cls);
+    state->cls->abc = abc_class_new(global->file, &classname2, extends2);
+    if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
+    if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
+    if(interface) {
+        state->cls->info->flags |= CLASS_INTERFACE;
+        abc_class_interface(state->cls->abc);
+    }
+
+    abc_class_protectedNS(state->cls->abc, classname);
 
     for(mlist=implements;mlist;mlist=mlist->next) {
         MULTINAME(m, mlist->classinfo);
-        abc_class_add_interface(state->cls, &m);
+        abc_class_add_interface(state->cls->abc, &m);
     }
 
     /* now write the construction code for this class */
-    int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
+    int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
 
-    abc_method_body_t*m = state->init->method->body;
+    abc_method_body_t*m = global->init->method->body;
     __ getglobalscope(m);
     classinfo_t*s = extends;
 
@@ -543,7 +588,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
         __ getlocal_0(m);
         __ pushscope(m);count++;
     }
-    __ newclass(m,state->cls);
+    __ newclass(m,state->cls->abc);
     while(count--) {
         __ popscope(m);
     }
@@ -560,28 +605,40 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     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_init) {
-        if(!state->cls->constructor) {
-            abc_method_t*m = abc_class_constructor(state->cls, 0, 0);
-            m->body->code = code_append(m->body->code, state->cls_init);
-            m->body->code = abc_returnvoid(m->body->code);
-        } else {
-            code_t*c = state->cls->constructor->body->code;
-            c = code_append(state->cls_init, c);
-            state->cls->constructor->body->code = c;
+    if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
+        code_t*c = 0;
+        c = abc_getlocal_0(c);
+        c = abc_constructsuper(c, 0);
+        state->cls->init = code_append(state->cls->init, c);
+    }
 
-        }
+    if(state->cls->init) {
+        abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
+        m->body->code = wrap_function(0, state->cls->init, m->body->code);
     }
-    if(state->cls_static_init) {
-        if(!state->cls->static_constructor) {
-            abc_method_t*m = abc_class_staticconstructor(state->cls, 0, 0);
-            m->body->code = state->cls_static_init;
-        } else {
-            state->cls->static_constructor->body->code = 
-                code_append(state->cls_static_init, state->cls->static_constructor->body->code);
-        }
+    if(state->cls->static_init) {
+        abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
+        m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
+    } 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;*/
     }
 
     old_state();
@@ -596,7 +653,9 @@ static int find_variable(char*name, classinfo_t**m)
 {
     state_list_t* s = state_stack;
     while(s) {
-        variable_t*v = dict_lookup(s->state->vars, name);
+        variable_t*v = 0;
+        if(s->state->method)
+            v = dict_lookup(s->state->vars, name);
         if(v) {
             if(m) {
                 *m = v->type;
@@ -631,10 +690,9 @@ static int gettempvar()
 {
     int i = find_variable(TEMPVARNAME, 0);
     if(i<0) {
-        return new_variable(TEMPVARNAME, 0);
-    } else {
-        return i;
+        i = new_variable(TEMPVARNAME, 0);
     }
+    return i;
 }
 
 code_t* killvars(code_t*c) 
@@ -654,6 +712,21 @@ code_t* killvars(code_t*c)
     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)
 {
@@ -673,18 +746,18 @@ static void check_constant_against_type(classinfo_t*t, constant_t*c)
    }
 }
 
-static memberinfo_t*registerfunction(enum yytokentype getset, char*name, params_t*params, classinfo_t*return_type, int slot)
+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->clsinfo, name)) {
+        if(registry_findmember(state->cls->info, name)) {
             syntaxerror("class already contains a member/method called '%s'", name);
         }
-        minfo = memberinfo_register(state->clsinfo, name, MEMBER_METHOD);
+        minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
         minfo->return_type = return_type;
         // getslot on a member slot only returns "undefined", so no need
         // to actually store these
-        //state->minfo->slot = state->m->method->trait->slot_id;
+        //state->minfo->slot = state->method->abc->method->trait->slot_id;
     } else {
         int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
         classinfo_t*type=0;
@@ -692,7 +765,7 @@ static memberinfo_t*registerfunction(enum yytokentype getset, char*name, params_
             type = return_type;
         else if(params->list)
             type = params->list->param->type;
-        if((minfo=registry_findmember(state->clsinfo, name))) {
+        if((minfo=registry_findmember(state->cls->info, name))) {
             if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
                 syntaxerror("class already contains a member or method called '%s'", name);
             if(minfo->kind & gs)
@@ -705,39 +778,90 @@ static memberinfo_t*registerfunction(enum yytokentype getset, char*name, params_
                 if(type && minfo->type != type)
                     syntaxerror("different type in getter and setter");
         } else {
-            minfo = memberinfo_register(state->clsinfo, name, gs);
+            minfo = memberinfo_register(state->cls->info, name, gs);
             minfo->type = type;
         }
         /* can't assign a slot as getter and setter might have different slots */
         //minfo->slot = slot;
     }
+    if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
+    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;
     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)
 {
-    token_list_t*t;
+    if(state->method) {
+        syntaxerror("not able to start another method scope");
+    }
     new_state();
-    global->variable_count = 0;
-    state->function = name;
+    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;
     
-    if(state->m) {
-        syntaxerror("not able to start another method scope");
+    state->cls->has_constructor |= state->method->is_constructor;
+
+    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");
+    param_list_t*p=0;
+    for(p=params->list;p;p=p->next) {
+        new_variable(p->param->name, p->param->type);
     }
+    if(state->method->is_constructor)
+        name = "__as3_constructor__";
+    state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
+}
+
+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);
-    if(!strcmp(state->clsinfo->name,name)) {
-        state->m = abc_class_constructor(state->cls, type2, 0);
+    int slot = 0;
+    if(state->method->is_constructor) {
+        f = abc_class_getconstructor(state->cls->abc, type2);
     } else {
-        state->m = abc_class_method(state->cls, type2, name, 0);
-        int slot = state->m->trait->slot_id;
-        state->minfo = registerfunction(getset, name, params, return_type, slot);
+        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;
     }
+    //flash doesn't seem to allow us to access function slots
+    //state->method->info->slot = slot;
 
-    if(getset == KW_GET) state->m->trait->kind = TRAIT_GETTER;
-    if(getset == KW_SET) state->m->trait->kind = TRAIT_SETTER;
-    if(params->varargs) state->m->flags |= METHOD_NEED_REST;
+    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;
 
     char opt=0;
     param_list_t*p=0;
@@ -746,42 +870,22 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
             break; //varargs: omit last parameter in function signature
         }
         multiname_t*m = sig2mname(p->param->type);
-       list_append(state->m->parameters, m);
+       list_append(f->parameters, m);
         if(p->param->value) {
             check_constant_against_type(p->param->type, p->param->value);
-            opt=1;list_append(state->m->optional_parameters, p->param->value);
+            opt=1;list_append(f->optional_parameters, p->param->value);
         } else if(opt) {
             syntaxerror("non-optional parameter not allowed after optional parameters");
         }
     }
+    check_code_for_break(body);
 
-    /* state->vars is initialized by state_new */
-    if(new_variable("this", state->clsinfo)!=0) syntaxerror("Internal error");
-
-    for(p=params->list;p;p=p->next) {
-        new_variable(p->param->name, p->param->type);
-    }
-}
-static void endfunction(code_t*body)
-{
+    if(f->body)
+        f->body->code = body;
+    else //interface
+        if(body)
+            syntaxerror("interface methods can't have a method body");
         
-    if(!(state->cls->flags & CLASS_INTERFACE)) {
-        code_t*c = 0;
-        if(state->late_binding) {
-            c = abc_getlocal_0(c);
-            c = abc_pushscope(c);
-        }
-        c = code_append(c, state->initcode);
-        c = code_append(c, body);
-
-        /* append return if necessary */
-        if(!c || c->opcode != OPCODE_RETURNVOID && 
-                 c->opcode != OPCODE_RETURNVALUE) {
-            c = abc_returnvoid(c);
-        }
-        if(state->m->body->code) syntaxerror("internal error");
-        state->m->body->code = c;
-    }
     old_state();
 }
 
@@ -792,16 +896,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;
     }
 }
 
@@ -829,19 +947,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) {
@@ -852,7 +964,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++;
@@ -861,13 +973,19 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
     }
     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
         return c;
+    if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
+        return c;
     syntaxerror("can't convert type %s to %s", from->name, to->name);
 }
 
 code_t*defaultvalue(code_t*c, classinfo_t*type)
 {
-    if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
+    if(TYPE_IS_INT(type)) {
        c = abc_pushbyte(c, 0);
+    } else if(TYPE_IS_UINT(type)) {
+       c = abc_pushuint(c, 0);
+    } else if(TYPE_IS_FLOAT(type)) {
+       c = abc_pushnan(c);
     } else if(TYPE_IS_BOOLEAN(type)) {
        c = abc_pushfalse(c);
     } else {
@@ -886,6 +1004,40 @@ void parserassert(int b)
     if(!b) syntaxerror("internal error: assertion failed");
 }
 
+static classinfo_t* find_class(char*name)
+{
+    classinfo_t*c=0;
+
+    c = registry_findclass(state->package, name);
+
+    /* try explicit imports */
+    dictentry_t* e = dict_get_slot(state->imports, name);
+    while(e) {
+        if(c)
+            break;
+        if(!strcmp(e->key, name)) {
+            c = (classinfo_t*)e->data;
+        }
+        e = e->next;
+    }
+
+    /* 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);
+        l = l->next;
+    }
+
+    /* try global package */
+    if(!c) {
+        c = registry_findclass("", name);
+    }
+    return c;
+}
+
 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
 {
     /* converts this:
@@ -921,19 +1073,33 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
         write->opcode = OPCODE_SETPROPERTY;
         multiname_t*m = (multiname_t*)r->data[0];
         write->data[0] = multiname_clone(m);
-        if(m->type != QNAME)
-            syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
-        if(!justassign) {
+        if(m->type == QNAME || m->type == MULTINAME) {
+            if(!justassign) {
+                prefix = abc_dup(prefix); // we need the object, too
+            }
             use_temp_var = 1;
-            prefix = abc_dup(prefix); // we need the object, too
+        } else if(m->type == MULTINAMEL) {
+            if(!justassign) {
+                /* dupping two values on the stack requires 5 operations and one register- 
+                   couldn't adobe just have given us a dup2? */
+                int temp = gettempvar();
+                prefix = abc_setlocal(prefix, temp);
+                prefix = abc_dup(prefix);
+                prefix = abc_getlocal(prefix, temp);
+                prefix = abc_swap(prefix);
+                prefix = abc_getlocal(prefix, temp);
+            }
+            use_temp_var = 1;
+        } else {
+            syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
         }
     } else if(r->opcode == OPCODE_GETSLOT) {
         write->opcode = OPCODE_SETSLOT;
         write->data[0] = r->data[0];
         if(!justassign) {
-            use_temp_var = 1;
             prefix = abc_dup(prefix); // we need the object, too
         }
+        use_temp_var = 1;
     } else if(r->opcode == OPCODE_GETLOCAL) { 
         write->opcode = OPCODE_SETLOCAL;
         write->data[0] = r->data[0];
@@ -991,18 +1157,33 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
     } else {
         /* even smaller version: overwrite the value without reading
            it out first */
-        if(prefix) {
-            c = code_append(c, prefix);
+        if(!use_temp_var) {
+            if(prefix) {
+                c = code_append(c, prefix);
+                c = abc_dup(c);
+            }
+            c = code_append(c, middlepart);
+            c = code_append(c, write);
+            c = code_append(c, r);
+        } else {
+            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 = code_append(c, middlepart);
-        c = code_append(c, write);
-        c = code_append(c, r);
     }
 
     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))
 
 %}
 
@@ -1013,11 +1194,15 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
 
 PROGRAM: MAYBECODE
 
-MAYBECODE: CODE {$$=$1;}
-MAYBECODE:      {$$=code_new();}
+MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
+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*/}
@@ -1029,13 +1214,16 @@ CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
 CODEPIECE: VOIDEXPRESSION        {$$=$1}
 CODEPIECE: FOR                   {$$=$1}
 CODEPIECE: WHILE                 {$$=$1}
+CODEPIECE: DO_WHILE              {$$=$1}
 CODEPIECE: BREAK                 {$$=$1}
+CODEPIECE: CONTINUE              {$$=$1}
 CODEPIECE: RETURN                {$$=$1}
 CODEPIECE: IF                    {$$=$1}
 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
 
-CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
+CODEBLOCK :  '{' CODE '}' {$$=$2;}
+CODEBLOCK :  '{' '}'      {$$=0;}
 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
 
@@ -1077,8 +1265,8 @@ ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
         /* if this is a typed variable:
            push default value for type on stack */
         if($3) {
-            state->initcode = defaultvalue(state->initcode, $3);
-            state->initcode = abc_setlocal(state->initcode, index);
+            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) {
@@ -1092,21 +1280,20 @@ ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
     
     /* that's the default for a local register, anyway
         else {
-        state->initcode = abc_pushundefined(state->initcode);
-        state->initcode = abc_setlocal(state->initcode, index);
+        state->method->initcode = abc_pushundefined(state->method->initcode);
+        state->method->initcode = abc_setlocal(state->method->initcode, index);
     }*/
     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
 }
 
 /* ------------ control flow ------------------------- */
 
-MAYBEELSE:  %prec prec_none {$$ = code_new();}
+MAYBEELSE:  %prec below_else {$$ = code_new();}
 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
 
 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
-    $$ = state->initcode;state->initcode=0;
-
+    $$ = code_new();
     $$ = code_append($$, $4.c);
     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
    
@@ -1114,10 +1301,10 @@ IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
     if($7) {
         myjmp = $$ = abc_jump($$, 0);
     }
-    myif->branch = $$ = abc_label($$);
+    myif->branch = $$ = abc_nop($$);
     if($7) {
         $$ = code_append($$, $7);
-        myjmp->branch = $$ = abc_label($$);
+        myjmp->branch = $$ = abc_nop($$);
     }
     
     $$ = killvars($$);old_state();
@@ -1127,40 +1314,67 @@ FOR_INIT : {$$=code_new();}
 FOR_INIT : VARIABLE_DECLARATION
 FOR_INIT : VOIDEXPRESSION
 
-FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
-    $$ = state->initcode;state->initcode=0;
-
+FOR : T_FOR '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
+    $$ = code_new();
     $$ = code_append($$, $4);
     code_t*loopstart = $$ = abc_label($$);
     $$ = code_append($$, $6.c);
     code_t*myif = $$ = abc_iffalse($$, 0);
     $$ = code_append($$, $10);
+    code_t*cont = $$ = abc_nop($$);
     $$ = code_append($$, $8);
     $$ = abc_jump($$, loopstart);
-    code_t*out = $$ = abc_label($$);
-    breakjumpsto($$, out);
+    code_t*out = $$ = abc_nop($$);
+    breakjumpsto($$, $1, out);
+    continuejumpsto($$, $1, cont);
     myif->branch = out;
 
     $$ = killvars($$);old_state();
 }
 
-WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
-    $$ = state->initcode;state->initcode=0;
+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_label($$);
+    code_t*cont = $$ = abc_nop($$);
+    myjmp->branch = cont;
     $$ = code_append($$, $4.c);
     $$ = abc_iftrue($$, loopstart);
-    code_t*out = $$ = abc_label($$);
-    breakjumpsto($$, out);
+    code_t*out = $$ = abc_nop($$);
+    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" {
-    $$ = abc___break__(0);
+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);
 }
 
 /* ------------ packages and imports ---------------- */
@@ -1247,40 +1461,58 @@ IDECLARATION : "var" T_IDENTIFIER {
     syntaxerror("variable declarations not allowed in interfaces");
 }
 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
-    if($1&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
-        syntaxerror("invalid method modifiers: interface methods are always public");
+    $1 |= FLAG_PUBLIC;
+    if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
+        syntaxerror("invalid method modifiers: interface methods always need to be public");
     }
     startfunction(0,$1,$3,$4,&$6,$8);
-    endfunction(0);
+    endfunction(0,$1,$3,$4,&$6,$8, 0);
 }
 
 /* ------------ classes and interfaces (body, slots ) ------- */
 
 VARCONST: "var" | "const"
-SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
 
-    memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
+    int flags = $1;
+    memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
     info->type = $4;
-
+    info->flags = flags;
     trait_t*t=0;
-    if($4) {
-        MULTINAME(m, $4);
-        t=abc_class_slot(state->cls, $3, &m);
+
+    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;
     } else {
-        t=abc_class_slot(state->cls, $3, 0);
-    }
-    if($2==KW_CONST) {
-        t->kind= TRAIT_CONST;
+        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;
     }
-    info->slot = t->slot_id;
     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);
-        //c = abc_setproperty(c, $3); 
-        state->cls_init = code_append(state->cls_init, c);
+        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);
+    }
+    if($2==KW_CONST) {
+        t->kind= TRAIT_CONST;
     }
 }
 
@@ -1295,9 +1527,9 @@ STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
-STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
-STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
-STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
+STATICCONSTANT : "true" {$$ = constant_new_true($1);}
+STATICCONSTANT : "false" {$$ = constant_new_false($1);}
+STATICCONSTANT : "null" {$$ = constant_new_null($1);}
 
 /* ------------ classes and interfaces (body, functions) ------- */
 
@@ -1350,8 +1582,18 @@ GETSET : "get" {$$=$1;}
 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
 {
-    if(!state->m) syntaxerror("internal error: undefined function");
-    endfunction($11);
+    code_t*c = 0;
+    if(state->method->late_binding) {
+        c = abc_getlocal_0(c);
+        c = abc_pushscope(c);
+    }
+    if(state->method->is_constructor && !state->method->has_super) {
+        // call default constructor
+        c = abc_getlocal_0(c);
+        c = abc_constructsuper(c, 0);
+    }
+    c = wrap_function(c, state->method->initcode, $11);
+    endfunction(0,$1,$3,$4,&$6,$8,c);
 }
 
 /* ------------- package + class ids --------------- */
@@ -1359,34 +1601,7 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P
 CLASS: T_IDENTIFIER {
 
     /* try current package */
-    $$ = registry_findclass(state->package, $1);
-
-    /* try explicit imports */
-    dictentry_t* e = dict_get_slot(state->imports, $1);
-    while(e) {
-        if($$)
-            break;
-        if(!strcmp(e->key, $1)) {
-            $$ = (classinfo_t*)e->data;
-        }
-        e = e->next;
-    }
-
-    /* try package.* imports */
-    import_list_t*l = state->wildcard_imports;
-    while(l) {
-        if($$)
-            break;
-        //printf("does package %s contain a class %s?\n", l->import->package, $1);
-        $$ = registry_findclass(l->import->package, $1);
-        l = l->next;
-    }
-
-    /* try global package */
-    if(!$$) {
-        $$ = registry_findclass("", $1);
-    }
-
+    $$ = find_class($1);
     if(!$$) syntaxerror("Could not find class %s\n", $1);
 }
 
@@ -1403,16 +1618,19 @@ QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
 
 TYPE : QNAME      {$$=$1;}
      | '*'        {$$=registry_getanytype();}
+     | "void"     {$$=registry_getanytype();}
+    /*
      |  "String"  {$$=registry_getstringclass();}
      |  "int"     {$$=registry_getintclass();}
      |  "uint"    {$$=registry_getuintclass();}
      |  "Boolean" {$$=registry_getbooleanclass();}
      |  "Number"  {$$=registry_getnumberclass();}
+    */
 
 MAYBETYPE: ':' TYPE {$$=$2;}
 MAYBETYPE:          {$$=0;}
 
-/* ----------function calls, constructor calls ------ */
+/* ----------function calls, delete, constructor calls ------ */
 
 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
@@ -1432,8 +1650,12 @@ NEW : "new" CLASS MAYBE_PARAM_VALUES {
     MULTINAME(m, $2);
     $$.c = code_new();
 
-    /* TODO: why do we have to *find* our own classes? */
-    $$.c = abc_findpropstrict2($$.c, &m);
+    if($2->slot) {
+        $$.c = abc_getglobalscope($$.c);
+        $$.c = abc_getslot($$.c, $2->slot);
+    } else {
+        $$.c = abc_findpropstrict2($$.c, &m);
+    }
 
     typedcode_list_t*l = $3;
     int len = 0;
@@ -1442,7 +1664,10 @@ NEW : "new" CLASS MAYBE_PARAM_VALUES {
         l = l->next;
         len ++;
     }
-    $$.c = abc_constructprop2($$.c, &m, len);
+    if($2->slot)
+        $$.c = abc_construct($$.c, len);
+    else
+        $$.c = abc_constructprop2($$.c, &m, len);
     $$.t = $2;
 }
 
@@ -1474,16 +1699,20 @@ FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
         $$.c = abc_callproperty2($$.c, name, len);
     } else if($$.c->opcode == OPCODE_GETSLOT) {
         int slot = (int)(ptroff_t)$$.c->data[0];
-        trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
+        trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
         if(t->kind!=TRAIT_METHOD) {
-            //flash allows to assign closures to members.
-            //syntaxerror("not a function");
+            //ok: flash allows to assign closures to members.
         }
         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);
+    } else if($$.c->opcode == OPCODE_GETSUPER) {
+        name = multiname_clone($$.c->data[0]);
+        $$.c = code_cutlast($$.c);
+        $$.c = code_append($$.c, paramcode);
+        $$.c = abc_callsuper2($$.c, name, len);
     } else {
         $$.c = abc_getlocal_0($$.c);
         $$.c = code_append($$.c, paramcode);
@@ -1492,14 +1721,56 @@ FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
    
     memberinfo_t*f = 0;
    
-    if(TYPE_IS_FUNCTION($1.t) &&
-       (f = registry_findmember($1.t, "call"))) {
-        $$.t = f->return_type;
+    if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
+        $$.t = $1.t->function->return_type;
     } else {
         $$.c = abc_coerce_a($$.c);
         $$.t = TYPE_ANY;
     }
 }
+FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
+    if(!state->cls) syntaxerror("super() not allowed outside of a class");
+    if(!state->method) syntaxerror("super() not allowed outside of a function");
+    if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
+
+    $$.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++;
+    }
+    /*
+    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_pushundefined($$.c);
+    $$.t = TYPE_ANY;
+}
+
+DELETE: "delete" E {
+    $$.c = $2.c;
+    if($$.c->opcode == OPCODE_COERCE_A) {
+        $$.c = code_cutlast($$.c);
+    }
+    multiname_t*name = 0;
+    if($$.c->opcode == OPCODE_GETPROPERTY) {
+        $$.c->opcode = OPCODE_DELETEPROPERTY;
+    } else if($$.c->opcode == OPCODE_GETSLOT) {
+        int slot = (int)(ptroff_t)$$.c->data[0];
+        multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
+        $$.c = code_cutlast($$.c);
+        $$.c = abc_deleteproperty2($$.c, name);
+    } else {
+        $$.c = abc_getlocal_0($$.c);
+        MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
+        $$.c = abc_deleteproperty2($$.c, &m);
+    }
+    $$.t = TYPE_BOOLEAN;
+}
 
 RETURN: "return" %prec prec_none {
     $$ = abc_returnvoid(0);
@@ -1508,23 +1779,27 @@ RETURN: "return" EXPRESSION {
     $$ = $2.c;
     $$ = abc_returnvalue($$);
 }
+
 // ----------------------- expression types -------------------------------------
 
-NONCOMMAEXPRESSION : E        %prec prec_belowminus {$$=$1;}
-EXPRESSION : E                %prec prec_belowminus {$$ = $1;}
-EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
+NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
+EXPRESSION : E                %prec below_minus {$$ = $1;}
+EXPRESSION : EXPRESSION ',' E %prec below_minus {
     $$.c = $1.c;
     $$.c = cut_last_push($$.c);
     $$.c = code_append($$.c,$3.c);
     $$.t = $3.t;
 }
-VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
+VOIDEXPRESSION : EXPRESSION %prec below_minus {
+    $$=cut_last_push($1.c);
+}
 
 // ----------------------- expression evaluation -------------------------------------
 
 E : CONSTANT
 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
 E : NEW                         {$$ = $1;}
+E : DELETE                      {$$ = $1;}
 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
                                  $$.t = TYPE_ANY;
                                 }
@@ -1549,13 +1824,16 @@ CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
                      $$.t = TYPE_STRING;
                     }
-CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
+CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
+                    $$.t = TYPE_ANY;
+                   }
+CONSTANT : "true" {$$.c = abc_pushtrue(0);
                     $$.t = TYPE_BOOLEAN;
                    }
-CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
+CONSTANT : "false" {$$.c = abc_pushfalse(0);
                      $$.t = TYPE_BOOLEAN;
                     }
-CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
+CONSTANT : "null" {$$.c = abc_pushnull(0);
                     $$.t = TYPE_NULL;
                    }
 
@@ -1577,6 +1855,9 @@ E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
              }
 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
               $$.t = TYPE_BOOLEAN;
+              }
+E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
+              $$.t = TYPE_BOOLEAN;
              }
 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
               $$.t = TYPE_BOOLEAN;
@@ -1616,22 +1897,121 @@ E : '!' E    {$$.c=$2.c;
               $$.t = TYPE_BOOLEAN;
              }
 
-E : E '-' E
-E : E '/' E
-E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
-             $$.t = join_types($1.t, $3.t, '+');
+E : '~' E    {$$.c=$2.c;
+              $$.c = abc_bitnot($$.c);
+              $$.t = TYPE_INT;
+             }
+
+E : E '&' E {$$.c = code_append($1.c,$3.c);
+             $$.c = abc_bitand($$.c);
+             $$.t = TYPE_INT;
+            }
+
+E : E '^' E {$$.c = code_append($1.c,$3.c);
+             $$.c = abc_bitxor($$.c);
+             $$.t = TYPE_INT;
+            }
+
+E : E '|' E {$$.c = code_append($1.c,$3.c);
+             $$.c = abc_bitor($$.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;
             }
-E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
-             $$.t = join_types($1.t, $3.t, '%');
+E : E ">>>" E {$$.c = code_append($1.c,$3.c);
+             $$.c = abc_urshift($$.c);
+             $$.t = TYPE_INT;
             }
-E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
-             $$.t = join_types($1.t, $3.t, '*');
+E : E "<<" E {$$.c = code_append($1.c,$3.c);
+             $$.c = abc_lshift($$.c);
+             $$.t = TYPE_INT;
             }
 
-E : E "as" E
-E : E "is" E
-E : '(' E ')' {$$=$2;}
-E : '-' E {$$=$2;}
+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,$3)) {
+                $$.c = abc_multiply_i($$.c);
+                $$.t = TYPE_INT;
+             } else {
+                $$.c = abc_multiply($$.c);
+                $$.t = TYPE_NUMBER;
+             }
+            }
+
+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);
+                $$.c = abc_astype2($1.c, &m);
+                $$.t = $3.t->cls;
+              } else {
+                $$.c = code_append($1.c, $3.c);
+                $$.c = abc_astypelate($$.c);
+                $$.t = TYPE_ANY;
+              }
+             }
+
+E : E "instanceof" E 
+             {$$.c = code_append($1.c, $3.c);
+              $$.c = abc_instanceof($$.c);
+              $$.t = TYPE_BOOLEAN;
+             }
+
+E : E "is" E {$$.c = code_append($1.c, $3.c);
+              $$.c = abc_istypelate($$.c);
+              $$.t = TYPE_BOOLEAN;
+             }
+
+E : "typeof" '(' E ')' {
+              $$.c = $3.c;
+              $$.c = abc_typeof($$.c);
+              $$.t = TYPE_STRING;
+             }
+
+E : "void" E {
+              $$.c = cut_last_push($2.c);
+              $$.c = abc_pushundefined($$.c);
+              $$.t = TYPE_ANY;
+             }
+
+E : "void" { $$.c = abc_pushundefined(0);
+             $$.t = TYPE_ANY;
+           }
+
+E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
+
+E : '-' E {
+  $$=$2;
+  if(IS_INT($2)) {
+   $$.c=abc_negate_i($$.c);
+   $$.t = TYPE_INT;
+  } else {
+   $$.c=abc_negate($$.c);
+   $$.t = TYPE_NUMBER;
+  }
+}
 
 E : E '[' E ']' {
   $$.c = $1.c;
@@ -1639,11 +2019,54 @@ E : E '[' E ']' {
  
   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
   $$.c = abc_getproperty2($$.c, &m);
+  $$.t = 0; // array elements have unknown type
+}
+
+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);
+    $$.t = registry_getarrayclass();
+}
+
+MAYBE_EXPRPAIR_LIST : {$$=0;}
+MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
+
+EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+    typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $1;
+    typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $3;
+    $$ = 0;
+    list_append($$, t1);
+    list_append($$, t2);
+}
+EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+    $$=$1;
+    typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $3;
+    typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $5;
+    list_append($$, t1);
+    list_append($$, t2);
+}
+//MAYBECOMMA: ','
+//MAYBECOMMA:
+
+E : '{' MAYBE_EXPRPAIR_LIST '}' {
+    $$.c = code_new();
+    typedcode_list_t*l = 0;
+    int len = 0;
+    for(l=$2;l;l=l->next) {
+        $$.c = code_append($$.c, l->typedcode->c);len++;
+    }
+    $$.c = abc_newobject($$.c, len/2);
+    $$.t = registry_getobjectclass();
 }
 
 E : E "*=" E { 
                code_t*c = $3.c;
-               if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
+               if(BOTH_INT($1,$3)) {
                 c=abc_multiply_i(c);
                } else {
                 c=abc_multiply(c);
@@ -1652,6 +2075,7 @@ E : E "*=" E {
                $$.c = toreadwrite($1.c, c, 0, 0);
                $$.t = $1.t;
               }
+
 E : E "%=" E { 
                code_t*c = abc_modulo($3.c);
                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
@@ -1712,6 +2136,17 @@ E : E '=' E { code_t*c = 0;
               $$.t = $1.t;
             }
 
+E : E '?' E ':' E %prec below_assignment { 
+              $$.c = $1.c;
+              code_t*j1 = $$.c = abc_iffalse($$.c, 0);
+              $$.c = code_append($$.c, $3.c);
+              code_t*j2 = $$.c = abc_jump($$.c, 0);
+              $$.c = j1->branch = abc_label($$.c);
+              $$.c = code_append($$.c, $5.c);
+              $$.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;
@@ -1740,7 +2175,7 @@ E : E "--" { code_t*c = 0;
              $$.t = $1.t;
             }
 
-E : "++" E { code_t*c = 0;
+E : "++" %prec plusplus_prefix E { code_t*c = 0;
              classinfo_t*type = $2.t;
              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
                  c=abc_increment_i(c);
@@ -1754,7 +2189,7 @@ E : "++" E { code_t*c = 0;
              $$.t = $2.t;
            }
 
-E : "--" E { code_t*c = 0;
+E : "--" %prec minusminus_prefix E { code_t*c = 0;
              classinfo_t*type = $2.t;
              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
                  c=abc_decrement_i(c);
@@ -1768,32 +2203,49 @@ E : "--" E { code_t*c = 0;
              $$.t = $2.t;
            }
 
+E : "super" '.' T_IDENTIFIER 
+           { if(!state->cls->info)
+                  syntaxerror("super keyword not allowed outside a class");
+              classinfo_t*t = state->cls->info->superclass;
+              if(!t) t = TYPE_OBJECT;
+
+              memberinfo_t*f = registry_findmember(t, $3);
+              namespace_t ns = {flags2access(f->flags), ""};
+              MEMBER_MULTINAME(m, f, $3);
+              $$.c = 0;
+              $$.c = abc_getlocal_0($$.c);
+              $$.c = abc_getsuper2($$.c, &m);
+              $$.t = memberinfo_gettype(f);
+           }
+
 E : E '.' T_IDENTIFIER
             {$$.c = $1.c;
-             if($$.t) {
-                 memberinfo_t*f = registry_findmember($$.t, $3);
-
-                 if(f && f->slot) {
+             classinfo_t*t = $1.t;
+             char is_static = 0;
+             if(TYPE_IS_CLASS(t) && t->cls) {
+                 t = t->cls;
+                 is_static = 1;
+             }
+             if(t) {
+                 memberinfo_t*f = registry_findmember(t, $3);
+                 char noslot = 0;
+                 if(f && !is_static != !(f->flags&FLAG_STATIC))
+                    noslot=1;
+                 if(f && f->slot && !noslot) {
                      $$.c = abc_getslot($$.c, f->slot);
                  } else {
-                     namespace_t ns = {$$.t->access, ""}; // needs to be "", not $$.t->package
-                     multiname_t m = {QNAME, &ns, 0, $3};
+                     MEMBER_MULTINAME(m, f, $3);
                      $$.c = abc_getproperty2($$.c, &m);
                  }
                  /* determine type */
-                 if(f) {
-                    if(f->kind == MEMBER_METHOD) {
-                        $$.t = TYPE_FUNCTION(f);
-                    } else {
-                        $$.t = f->type;
-                    }
-                 } else {
+                 $$.t = memberinfo_gettype(f);
+                 if(!$$.t)
                     $$.c = abc_coerce_a($$.c);
-                    $$.t = registry_getanytype();
-                 }
              } else {
-                 namespace_t ns = {ACCESS_PACKAGE, ""};
-                 multiname_t m = {QNAME, &ns, 0, $3};
+                 /* when resolving a property on an unknown type, we do know the
+                    name of the property (and don't seem to need the package), but
+                    we need to make avm2 try out all access modes */
+                 multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
                  $$.c = abc_getproperty2($$.c, &m);
                  $$.c = abc_coerce_a($$.c);
                  $$.t = registry_getanytype();
@@ -1804,35 +2256,74 @@ VAR_READ : T_IDENTIFIER {
     $$.t = 0;
     $$.c = 0;
     int i;
+    classinfo_t*a = 0;
     memberinfo_t*f = 0;
+
+    /* look at variables */
     if((i = find_variable($1, &$$.t)) >= 0) {
         // $1 is a local variable
         $$.c = abc_getlocal($$.c, i);
-    } else if((f = registry_findmember(state->clsinfo, $1))) {
+
+    /* look at current class' members */
+    } else if((f = registry_findmember(state->cls->info, $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);
+        if(var_is_static != i_am_static) {
+            /* there doesn't seem to be any "static" way to access
+               static properties of a class */
+            state->method->late_binding = 1;
+            $$.t = f->type;
+            namespace_t ns = {flags2access(f->flags), ""};
+            multiname_t m = {QNAME, &ns, 0, $1};
+            $$.c = abc_findpropstrict2($$.c, &m);
+            $$.c = abc_getproperty2($$.c, &m);
+        } else {
+            if(f->slot>0) {
+                $$.c = abc_getlocal_0($$.c);
+                $$.c = abc_getslot($$.c, f->slot);
+            } else {
+                namespace_t ns = {flags2access(f->flags), ""};
+                multiname_t m = {QNAME, &ns, 0, $1};
+                $$.c = abc_getlocal_0($$.c);
+                $$.c = abc_getproperty2($$.c, &m);
+            }
+        }
         if(f->kind == MEMBER_METHOD) {
             $$.t = TYPE_FUNCTION(f);
         } else {
             $$.t = f->type;
         }
-        if(f->slot>0) {
-            $$.c = abc_getlocal_0($$.c);
-            $$.c = abc_getslot($$.c, f->slot);
-        } else {
-            namespace_t ns = {state->clsinfo->access, ""};
-            multiname_t m = {QNAME, &ns, 0, $1};
-            $$.c = abc_getlocal_0($$.c);
+    
+    /* look at classes in the current package and imported classes */
+    } else if((a = find_class($1))) {
+        if(a->flags & FLAG_METHOD) {
+            MULTINAME(m, a);
+            $$.c = abc_findpropstrict2($$.c, &m);
             $$.c = abc_getproperty2($$.c, &m);
+            $$.t = TYPE_FUNCTION(a->function);
+        } else {
+            if(a->slot) {
+                $$.c = abc_getglobalscope($$.c);
+                $$.c = abc_getslot($$.c, a->slot);
+            } else {
+                MULTINAME(m, a);
+                $$.c = abc_getlex2($$.c, &m);
+            }
+            $$.t = TYPE_CLASS(a);
         }
+
+    /* unknown object, let the avm2 resolve it */
     } else {
-        // let the avm2 resolve $1 
         if(strcmp($1,"trace"))
-        warning("Couldn't resolve %s, doing late binding", $1);
-        state->late_binding = 1;
+            warning("Couldn't resolve '%s', doing late binding", $1);
+        state->method->late_binding = 1;
+                
+        multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
 
         $$.t = 0;
-        $$.c = abc_findpropstrict($$.c, $1);
-        $$.c = abc_getproperty($$.c, $1);
+        $$.c = abc_findpropstrict2($$.c, &m);
+        $$.c = abc_getproperty2($$.c, &m);
     }
 }