added implementation for dict-style objects
[swftools.git] / lib / as3 / parser.y
index c69c88c..f119828 100644 (file)
 %error-verbose
 
 %union tokenunion {
-    tokenptr_t token;
+    enum yytokentype token;
+    int flags;
 
-    class_signature_t*class_signature;
-    class_signature_list_t*class_signature_list;
+    classinfo_t*classinfo;
+    classinfo_list_t*classinfo_list;
 
     int number_int;
     unsigned int number_uint;
     typedcode_t value;
     typedcode_list_t*value_list;
     param_t* param;
-    param_list_t* param_list;
-    writeable_t writeable;
-    char*string;
+    params_t params;
+    string_t str;
+    char*id;
+    constant_t*constant;
 }
 
 
-%token<token> T_IDENTIFIER
-%token<string> T_STRING
+%token<id> T_IDENTIFIER
+%token<str> T_STRING
 %token<token> T_REGEXP
 %token<token> T_EMPTY
 %token<number_int> T_INT
 %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
+%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_MODBY "%="
+%token<token> T_MULBY "*="
 %token<token> T_PLUSBY "+=" 
 %token<token> T_MINUSBY "-="
 %token<token> T_SHRBY ">>="
 %token<token> T_MINUSMINUS "--"
 %token<token> T_PLUSPLUS "++"
 %token<token> T_DOTDOT ".."
+%token<token> T_DOTDOTDOT "..."
 %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> CODE
 %type <code> CODEPIECE
 %type <code> CODEBLOCK MAYBECODE
 %type <token> PACKAGE_DECLARATION
 %type <token> FUNCTION_DECLARATION
-%type <code> VARIABLE_DECLARATION
+%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
 %type <token> CLASS_DECLARATION
 %type <token> NAMESPACE_DECLARATION
 %type <token> INTERFACE_DECLARATION
 %type <code> VOIDEXPRESSION
-%type <value> EXPRESSION
+%type <value> EXPRESSION NONCOMMAEXPRESSION
 %type <value> MAYBEEXPRESSION
-%type <value> E
-%type <writeable> LH
+%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> ASSIGNMENT FOR_INIT
+%type <code> FOR_INIT
 %type <token> IMPORT
-%type <class_signature> MAYBETYPE
+%type <classinfo> MAYBETYPE
 %type <token> GETSET
 %type <param> PARAM
-%type <param_list> PARAM_LIST
-%type <param_list> MAYBE_PARAM_LIST
-%type <token> MODIFIERS
-%type <token> MODIFIER_LIST
-%type <class_signature_list> IMPLEMENTS_LIST
-%type <class_signature> EXTENDS
-%type <class_signature_list> EXTENDS_LIST
-%type <class_signature> PACKAGEANDCLASS
-%type <class_signature_list> PACKAGEANDCLASS_LIST
-%type <token> MULTILEVELIDENTIFIER
-%type <class_signature> TYPE
+%type <params> PARAM_LIST
+%type <params> MAYBE_PARAM_LIST
+%type <flags> MAYBE_MODIFIERS
+%type <flags> MODIFIER_LIST
+%type <constant> STATICCONSTANT MAYBESTATICCONSTANT
+%type <classinfo_list> IMPLEMENTS_LIST
+%type <classinfo> EXTENDS
+%type <classinfo_list> EXTENDS_LIST
+%type <classinfo> CLASS PACKAGEANDCLASS QNAME
+%type <classinfo_list> QNAME_LIST
+%type <classinfo> TYPE
 %type <token> VAR
 //%type <token> VARIABLE
 %type <value> VAR_READ
 %type <value> NEW
-%type <token> X_IDENTIFIER
+//%type <token> T_IDENTIFIER
 %type <token> MODIFIER
-%type <token> PACKAGE
 %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 '?' ':'
-%nonassoc '='
-%nonassoc "/=" "%="
-%nonassoc "+=" "-="
-%nonassoc ">>="
-%nonassoc "<<="
-%nonassoc ">>>="
-%nonassoc "||"
-%nonassoc "&&"
+%left "||"
+%left "&&"
 %nonassoc '|'
 %nonassoc '^'
 %nonassoc '&'
-%nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
-%nonassoc "is"
-%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 '('
-%left prec_highest
+
+// 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"
+
 
      
 %{
@@ -221,30 +230,6 @@ static int yyerror(char*s)
 {
    syntaxerror("%s", s); 
 }
-static token_t* concat2(token_t* t1, token_t* t2)
-{
-    NEW(token_t,t);
-    int l1 = strlen(t1->text);
-    int l2 = strlen(t2->text);
-    t->text = malloc(l1+l2+1);
-    memcpy(t->text   , t1->text, l1);
-    memcpy(t->text+l1, t2->text, l2);
-    t->text[l1+l2] = 0;
-    return t;
-}
-static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
-{
-    NEW(token_t,t);
-    int l1 = strlen(t1->text);
-    int l2 = strlen(t2->text);
-    int l3 = strlen(t3->text);
-    t->text = malloc(l1+l2+l3+1);
-    memcpy(t->text   , t1->text, l1);
-    memcpy(t->text+l1, t2->text, l2);
-    memcpy(t->text+l1+l2, t3->text, l3);
-    t->text[l1+l2+l3] = 0;
-    return t;
-}
 static char* concat3str(const char* t1, const char* t2, const char* t3)
 {
     int l1 = strlen(t1);
@@ -264,39 +249,100 @@ 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;
 
-    abc_method_body_t*m;
-    
+typedef struct _state {
+    int level;
+
+    char*package;     
     import_list_t*wildcard_imports;
     dict_t*imports;
     char has_own_imports;
-   
-    /* class data */
-    char*classname;
-    abc_class_t*cls;
-
-    array_t*vars;
-    int local_var_base;
+  
+    classstate_t*cls;   
+    methodstate_t*method;
+    
+    dict_t*vars;
 } state_t;
 
+typedef struct _global {
+    abc_file_t*file;
+    abc_script_t*init;
+
+    int variable_count;
+} global_t;
+
+static global_t*global = 0;
 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) \
+    namespace_t m##_ns = {access, package}; \
+    namespace_set_t m##_nsset; \
+    namespace_list_t m##_l;m##_l.next = 0; \
+    m##_nsset.namespaces = &m##_l; \
+    m##_nsset = m##_nsset; \
+    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()
+{
+    global = rfx_calloc(sizeof(global_t));
+}
 
 static void new_state()
 {
@@ -308,18 +354,14 @@ static void new_state()
         memcpy(s, state, sizeof(state_t)); //shallow copy
     sl->next = state_stack;
     sl->state = s;
-    if(oldstate) {
-        s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
-    }
     if(!s->imports) {
         s->imports = dict_new();
     }
     state_stack = sl;
     state = s;
     state->level++;
-    state->vars = array_new();
-    state->initcode = 0;
-    state->has_own_imports = 0;
+    state->has_own_imports = 0;    
+    state->vars = dict_new();
 }
 static void state_has_imports()
 {
@@ -337,54 +379,83 @@ 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);
-    abc_method_body_t*m = state->init->method->body;
-    __ getlocal_0(m);
-    __ pushscope(m);
-    __ findpropstrict(m, "[package]::trace");
-    __ pushstring(m, "[entering global init function]");
-    __ callpropvoid(m, "[package]::trace", 1);
+    global->init = abc_initscript(global->file, 0);
+    code_t*c = global->init->method->body->code;
+
+    c = abc_getlocal_0(c);
+    c = abc_pushscope(c);
+  
+    /* 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
+       contain properties like "trace". Trying to find the same
+       property on a "vanilla" local_0 yields only a "undefined" */
+    //c = abc_findpropstrict(c, "[package]::trace");
+    
+    /*c = abc_getlocal_0(c);
+    c = abc_findpropstrict(c, "[package]::trace");
+    c = abc_coerce_a(c);
+    c = abc_setlocal_1(c);
+
+    c = abc_pushbyte(c, 0);
+    c = abc_setlocal_2(c);
+   
+    code_t*xx = c = abc_label(c);
+    c = abc_findpropstrict(c, "[package]::trace");
+    c = abc_pushstring(c, "prop:");
+    c = abc_hasnext2(c, 1, 2);
+    c = abc_dup(c);
+    c = abc_setlocal_3(c);
+    c = abc_callpropvoid(c, "[package]::trace", 2);
+    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);
+    
+    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;
 }
 
 
-static void startpackage(token_t*t) 
+static void startpackage(char*name)
 {
     if(state->package) {
         syntaxerror("Packages can not be nested."); 
     } 
     new_state();
-    char*name = t?t->text:"";
     /*printf("entering package \"%s\"\n", name);*/
     state->package = name;
 }
@@ -395,51 +466,40 @@ static void endpackage()
 }
 
 char*globalclass=0;
-static void startclass(token_t*modifiers, token_t*name, class_signature_t*extends, class_signature_list_t*implements, char interface)
+static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
 {
     if(state->cls) {
         syntaxerror("inner classes now allowed"); 
     }
     new_state();
-    state->classname = name->text;
+    state->cls = rfx_calloc(sizeof(classstate_t));
 
     token_list_t*t=0;
-    class_signature_list_t*mlist=0;
-    /*printf("entering class %s\n", name->text);
-    printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
+    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->class_signature?mlist->class_signature->name:0);
+        printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
     }
     printf("\n");
     */
 
-    char public=0,internal=0,final=0,sealed=1;
-    for(t=modifiers->tokens;t;t=t->next) {
-        if(t->token->type == KW_INTERNAL) {
-            /* the programmer is being explicit- 
-               being internal is the default anyway */
-            internal = 1;
-        } else if(t->token->type == KW_PUBLIC) {
-            public = 1;
-        } else if(t->token->type == KW_FINAL) {
-            final = 1;
-        } else {
-            syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
-        }
-    }
-    if(public&&internal)
+    if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
+        syntaxerror("invalid modifier(s)");
+
+    if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
         syntaxerror("public and internal not supported at the same time.");
 
     /* create the class name, together with the proper attributes */
     int access=0;
     char*package=0;
 
-    if(!public && !state->package) {
+    if(!(flags&FLAG_PUBLIC) && !state->package) {
         access = ACCESS_PRIVATE; package = current_filename;
-    } else if(!public && state->package) {
+    } else if(!(flags&FLAG_PUBLIC) && state->package) {
         access = ACCESS_PACKAGEINTERNAL; package = state->package;
     } else if(state->package) {
         access = ACCESS_PACKAGE; package = state->package;
@@ -447,32 +507,51 @@ static void startclass(token_t*modifiers, token_t*name, class_signature_t*extend
         syntaxerror("public classes only allowed inside a package");
     }
 
-    if(registry_findclass(package, state->classname)) {
-        syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
+    if(registry_findclass(package, classname)) {
+        syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
     }
-    
-    class_signature_t* classname = class_signature_register(access, package, state->classname);
+   
 
-    MULTINAME(classname2,classname);
+    /* build info struct */
+    int num_interfaces = (list_length(implements));
+    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->cls->info->interfaces[pos++] = l->classinfo;
+    }
     
     multiname_t*extends2 = sig2mname(extends);
 
-    state->cls = abc_class_new(state->file, &classname2, extends2);
-    if(final) abc_class_final(state->cls);
-    if(sealed) abc_class_sealed(state->cls);
-    if(interface) abc_class_interface(state->cls);
+    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 = 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->class_signature);
-        abc_class_add_interface(state->cls, &m);
+        MULTINAME(m, mlist->classinfo);
+        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);
-    class_signature_t*s = extends;
+    classinfo_t*s = extends;
 
     int count=0;
     
@@ -487,9 +566,8 @@ static void startclass(token_t*modifiers, token_t*name, class_signature_t*extend
         __ getlex2(m, s2);
         multiname_destroy(s2);
 
-        __ pushscope(m);
+        __ pushscope(m); count++;
         m->code = m->code->prev->prev; // invert
-        count++;
     }
     /* continue appending after last op end */
     while(m->code && m->code->next) m->code = m->code->next; 
@@ -500,196 +578,414 @@ static void startclass(token_t*modifiers, token_t*name, class_signature_t*extend
     if(extends2) {
         __ getlex2(m, extends2);
         __ dup(m);
-        __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
+        /* notice: we get a Verify Error #1107 if the top elemnt on the scope
+           stack is not the superclass */
+        __ pushscope(m);count++;
     } else {
         __ pushnull(m);
+        /* notice: we get a verify error #1107 if the top element on the scope 
+           stack is not the global object */
+        __ getlocal_0(m);
+        __ pushscope(m);count++;
     }
-    __ newclass(m,state->cls);
+    __ newclass(m,state->cls->abc);
     while(count--) {
         __ popscope(m);
     }
     __ setslot(m, slotindex);
 
     /* flash.display.MovieClip handling */
-    if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
+    if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
         if(state->package && state->package[0]) {
-            globalclass = concat3str(state->package, ".", state->classname);
+            globalclass = concat3str(state->package, ".", classname);
         } else {
-            globalclass = strdup(state->classname);
+            globalclass = strdup(classname);
         }
     }
     multiname_destroy(extends2);
 }
 
-static void endclass()
+static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
 {
-    /*printf("leaving class %s\n", state->classname);*/
-    old_state();
+    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 startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
-                          param_list_t*params, class_signature_t*type)
+
+static void endclass()
 {
-    token_list_t*t;
-    new_state();
-    state->function = name->text;
-    
-    /*printf("entering function %s\n", name->text);
-    if(ns)
-        printf("  namespace: %s\n", ns->text);
-    printf("  getset: %s\n", getset->text);
-    printf("  params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
-    printf("  mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
-    if(type)
-        printf("  type: %s.%s\n", type->package, type->name);
-    print_imports();*/
-    
-    if(state->m) {
-        syntaxerror("not able to start another method scope");
+    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);
     }
 
-    multiname_t*type2 = sig2mname(type);
-
-    if(!strcmp(state->classname,name->text)) {
-        state->m = abc_class_constructor(state->cls, type2, 0);
-    } else {
-        state->m = abc_class_method(state->cls, type2, name->text, 0);
+    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);
     }
-    param_list_t*p;
-    for(p=params;p;p=p->next) {
-        multiname_t*m = sig2mname(p->param->type);
-       list_append(state->m->method->parameters, m);
-    }
-
-    /* state->vars is initialized by state_new */
-    array_append(state->vars, "this", 0);
-    for(p=params;p;p=p->next) {
-        array_append(state->vars, p->param->name, 0);
+    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;*/
     }
 
-    __ getlocal_0(state->m);
-    __ pushscope(state->m);
-
-    multiname_destroy(type2);
-}
-static void endfunction()
-{
-    /*printf("leaving function %s\n", state->function);*/
-    __ returnvoid(state->m);
-
     old_state();
 }
 
+typedef struct _variable {
+    int index;
+    classinfo_t*type;
+} variable_t;
 
-static token_t* empty_token()
-{
-    NEW(token_t,t);
-    t->type=T_EMPTY;
-    t->text=0;
-    return t;
-}
-
-void extend(token_t*list, token_t*add) {
-    list_append(list->tokens,add);
-    if(!list->text)
-        list->text = add->text;
-}
-void extend_s(token_t*list, char*seperator, token_t*add) {
-    list_append(list->tokens,add);
-    char*t1 = list->text;
-    char*t2 = seperator;
-    char*t3 = add->text;
-    int l1 = strlen(t1);
-    int l2 = strlen(t2);
-    int l3 = strlen(t3);
-    list->text = malloc(l1+l2+l3+1);
-    strcpy(list->text, t1);
-    strcpy(list->text+l1, t2);
-    strcpy(list->text+l1+l2, t3);
-    list->text[l1+l2+l3]=0;
-}
-
-static int find_variable(char*name, class_signature_t**m)
+static int find_variable(char*name, classinfo_t**m)
 {
     state_list_t* s = state_stack;
     while(s) {
-        int i = array_find(s->state->vars, name);
-        if(i>=0) {
+        variable_t*v = 0;
+        if(s->state->method)
+            v = dict_lookup(s->state->vars, name);
+        if(v) {
             if(m) {
-                *m = array_getvalue(s->state->vars, i);
+                *m = v->type;
             }
-            return i + s->state->local_var_base;
+            return v->index;
         }
         s = s->next;
     }
-    syntaxerror("undefined variable: %s", name);
+    return -1;
 } 
+static int find_variable_safe(char*name, classinfo_t**m)
+{
+    int i = find_variable(name, m);
+    if(i<0)
+        syntaxerror("undefined variable: %s", name);
+    return i;
+}
 static char variable_exists(char*name) 
 {
-    return array_contains(state->vars, name);
+    return dict_lookup(state->vars, name)!=0;
+}
+static int new_variable(char*name, classinfo_t*type)
+{
+    NEW(variable_t, v);
+    v->index = global->variable_count;
+    v->type = type;
+    dict_put(state->vars, name, v);
+    return global->variable_count++;
 }
-static int new_variable(char*name, class_signature_t*type)
+#define TEMPVARNAME "__as3_temp__"
+static int gettempvar()
 {
-    return array_append(state->vars, name, type) + state->local_var_base;
+    int i = find_variable(TEMPVARNAME, 0);
+    if(i<0) {
+        i = new_variable(TEMPVARNAME, 0);
+    }
+    return i;
 }
+
 code_t* killvars(code_t*c) 
 {
     int t;
-    for(t=0;t<state->vars->num;t++) {
-        class_signature_t*type = array_getvalue(state->vars, t);
-        //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, t+state->local_var_base);
-        //}
+    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;
 }
 
-char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
+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)
+{
+#define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
+   if(TYPE_IS_NUMBER(t)) {
+        xassert(c->type == CONSTANT_FLOAT
+             || c->type == CONSTANT_INT
+             || c->type == CONSTANT_UINT);
+   } else if(TYPE_IS_UINT(t)) {
+        xassert(c->type == CONSTANT_UINT ||
+               (c->type == CONSTANT_INT && c->i>0));
+   } else if(TYPE_IS_INT(t)) {
+        xassert(c->type == CONSTANT_INT);
+   } else if(TYPE_IS_BOOLEAN(t)) {
+        xassert(c->type == CONSTANT_TRUE
+             || c->type == CONSTANT_FALSE);
+   }
+}
+
+static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
+{
+    memberinfo_t*minfo = 0;
+    if(getset != KW_GET && getset != KW_SET) {
+        if(registry_findmember(state->cls->info, name)) {
+            syntaxerror("class already contains a member/method called '%s'", name);
+        }
+        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->method->abc->method->trait->slot_id;
+    } else {
+        int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
+        classinfo_t*type=0;
+        if(getset == KW_GET)
+            type = return_type;
+        else if(params->list)
+            type = params->list->param->type;
+        if((minfo=registry_findmember(state->cls->info, name))) {
+            if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
+                syntaxerror("class already contains a member or method called '%s'", name);
+            if(minfo->kind & gs)
+                syntaxerror("getter/setter for '%s' already defined", name);
+            /* make a setter or getter into a getset */
+            minfo->kind |= gs;
+            if(!minfo->type) 
+                minfo->type = type;
+            else
+                if(type && minfo->type != type)
+                    syntaxerror("different type in getter and setter");
+        } else {
+            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)
+{
+    if(state->method) {
+        syntaxerror("not able to start another method scope");
+    }
+    new_state();
+    state->method = rfx_calloc(sizeof(methodstate_t));
+    state->method->initcode = 0;
+    state->method->is_constructor = !strcmp(state->cls->info->name,name);
+    state->method->has_super = 0;
+    
+    state->cls->has_constructor |= state->method->is_constructor;
+
+    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);
+    int slot = 0;
+    if(state->method->is_constructor) {
+        f = abc_class_getconstructor(state->cls->abc, type2);
+    } else {
+        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) 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;
+    for(p=params->list;p;p=p->next) {
+        if(params->varargs && !p->next) {
+            break; //varargs: omit last parameter in function signature
+        }
+        multiname_t*m = sig2mname(p->param->type);
+       list_append(f->parameters, m);
+        if(p->param->value) {
+            check_constant_against_type(p->param->type, 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);
+
+    if(f->body)
+        f->body->code = body;
+    else //interface
+        if(body)
+            syntaxerror("interface methods can't have a method body");
+        
+    old_state();
+}
+
+
+
+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;
     }
 }
 
-class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
+classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
 {
-    return registry_getanytype(); // FIXME
+    if(!type1 || !type2) 
+        return registry_getanytype();
+    if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
+        return registry_getanytype();
+    if(type1 == type2)
+        return type1;
+    return registry_getanytype();
 }
-code_t*converttype(code_t*c, class_signature_t*from, class_signature_t*to)
+code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
 {
     if(from==to)
         return c;
     if(!to) {
-        /*TODO: can omit this if from is zero? */
         return abc_coerce_a(c);
     }
-    if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
-        MULTINAME(m, TYPE_UINT);
+    MULTINAME(m, to);
+    if(!from) {
+        // cast an "any" type to a specific type. subject to
+        // runtime exceptions
         return abc_coerce2(c, &m);
     }
-    if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
-        MULTINAME(m, TYPE_INT);
+    
+    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);
     }
-    return c;
+    //printf("%s.%s\n", from.package, from.name);
+    //printf("%s.%s\n", to.package, to.name);
+
+    classinfo_t*supertype = from;
+    while(supertype) {
+        if(supertype == to) {
+             // target type is one of from's superclasses
+             return abc_coerce2(c, &m);
+        }
+        int t=0;
+        while(supertype->interfaces[t]) {
+            if(supertype->interfaces[t]==to) {
+                // target type is one of from's interfaces
+                return abc_coerce2(c, &m);
+            }
+            t++;
+        }
+        supertype = supertype->superclass;
+    }
+    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, class_signature_t*type)
+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 {
@@ -698,6 +994,197 @@ code_t*defaultvalue(code_t*c, class_signature_t*type)
     return c;
 }
 
+char is_pushundefined(code_t*c)
+{
+    return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
+}
+
+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:
+
+       [prefix code] [read instruction]
+
+       to this:
+
+       [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
+    */
+    
+    if(in && in->opcode == OPCODE_COERCE_A) {
+        in = code_cutlast(in);
+    }
+    if(in->next)
+        syntaxerror("internal error");
+
+    /* chop off read instruction */
+    code_t*prefix = in;
+    code_t*r = in;
+    if(r->prev) {
+        prefix = r->prev;r->prev = 0;
+        prefix->next=0;
+    } else {
+        prefix = 0;
+    }
+
+    char use_temp_var = readbefore;
+
+    /* generate the write instruction, and maybe append a dup to the prefix code */
+    code_t* write = abc_nop(0);
+    if(r->opcode == OPCODE_GETPROPERTY) {
+        write->opcode = OPCODE_SETPROPERTY;
+        multiname_t*m = (multiname_t*)r->data[0];
+        write->data[0] = multiname_clone(m);
+        if(m->type == QNAME || m->type == MULTINAME) {
+            if(!justassign) {
+                prefix = abc_dup(prefix); // we need the object, too
+            }
+            use_temp_var = 1;
+        } 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) {
+            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];
+    } else if(r->opcode == OPCODE_GETLOCAL_0) { 
+        write->opcode = OPCODE_SETLOCAL_0;
+    } else if(r->opcode == OPCODE_GETLOCAL_1) { 
+        write->opcode = OPCODE_SETLOCAL_1;
+    } else if(r->opcode == OPCODE_GETLOCAL_2) { 
+        write->opcode = OPCODE_SETLOCAL_2;
+    } else if(r->opcode == OPCODE_GETLOCAL_3) { 
+        write->opcode = OPCODE_SETLOCAL_3;
+    } else {
+        code_dump(r, 0, 0, "", stdout);
+        syntaxerror("illegal lvalue: can't assign a value to this expression");
+    }
+    code_t* c = 0;
+    
+    int temp = -1;
+    if(!justassign) {
+        if(use_temp_var) {
+            /* with getproperty/getslot, we have to be extra careful not
+               to execute the read code twice, as it might have side-effects
+               (e.g. if the property is in fact a setter/getter combination)
+
+               So read the value, modify it, and write it again,
+               using prefix only once and making sure (by using a temporary
+               register) that the return value is what we just wrote */
+            temp = gettempvar();
+            c = code_append(c, prefix);
+            c = code_append(c, r);
+            if(readbefore) {
+                c = abc_dup(c);
+                c = abc_setlocal(c, temp);
+            }
+            c = code_append(c, middlepart);
+            if(!readbefore) {
+                c = abc_dup(c);
+                c = abc_setlocal(c, temp);
+            }
+            c = code_append(c, write);
+            c = abc_getlocal(c, temp);
+            c = abc_kill(c, temp);
+        } else {
+            /* if we're allowed to execute the read code twice *and*
+               the middlepart doesn't modify the code, things are easier.
+            */
+            code_t* r2 = code_dup(r);
+            //c = code_append(c, prefix);
+            parserassert(!prefix);
+            c = code_append(c, r);
+            c = code_append(c, middlepart);
+            c = code_append(c, write);
+            c = code_append(c, r2);
+        }
+    } else {
+        /* even smaller version: overwrite the value without reading
+           it out first */
+        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);
+        }
+    }
+
+    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))
+
 %}
 
 
@@ -707,63 +1194,63 @@ code_t*defaultvalue(code_t*c, class_signature_t*type)
 
 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*/}
-CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
+CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
+CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
 CODEPIECE: ';'                   {$$=code_new();}
 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
 CODEPIECE: VOIDEXPRESSION        {$$=$1}
 CODEPIECE: FOR                   {$$=$1}
 CODEPIECE: WHILE                 {$$=$1}
+CODEPIECE: DO_WHILE              {$$=$1}
 CODEPIECE: BREAK                 {$$=$1}
+CODEPIECE: CONTINUE              {$$=$1}
 CODEPIECE: RETURN                {$$=$1}
 CODEPIECE: IF                    {$$=$1}
-CODEPIECE: ASSIGNMENT            {$$=$1}
 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
-CODEPIECE: FUNCTION_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;}
 
-/* ------------ functions --------------------------- */
-
-FUNCTION_DECLARATION: 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");
-    state->initcode = abc_nop(state->initcode);
-    state->initcode = abc_nop(state->initcode);
-    state->initcode = abc_nop(state->initcode);
-    state->m->code = code_append(state->initcode, $11);state->initcode=0;
-    endfunction()
-}
-
 /* ------------ variables --------------------------- */
 
-MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
+MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
                 |                {$$.c=abc_pushundefined(0);
                                   $$.t=TYPE_ANY;
                                  }
 
 VAR : "const" | "var"
-VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
-    if(variable_exists($2->text))
-        syntaxerror("Variable %s already defined", $2->text);
+VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
+
+VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
+VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
+
+ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
+{
+    if(variable_exists($2))
+        syntaxerror("Variable %s already defined", $2);
    
     if(!is_subtype_of($4.t, $3)) {
         syntaxerror("Can't convert %s to %s", $4.t->name, 
                                               $3->name);
     }
 
-    int index = new_variable($2->text, $3);
+    int index = new_variable($2, $3);
     
     if($3) {
         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
@@ -775,15 +1262,13 @@ VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
             $$ = abc_setlocal($$, index);
         }
 
-        /* push default value for type on stack */
-        state->initcode = defaultvalue(state->initcode, $3);
-        state->initcode = abc_setlocal(state->initcode, index);
+        /* if this is a typed variable:
+           push default value for type on stack */
+        if($3) {
+            state->method->initcode = defaultvalue(state->method->initcode, $3);
+            state->method->initcode = abc_setlocal(state->method->initcode, index);
+        }
     } else {
-        /* only bother to actually set this variable if its syntax is either
-            var x:type;
-           or
-            var x=expr;
-        */
         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
             $$ = $4.c;
             $$ = abc_coerce_a($$);
@@ -795,33 +1280,20 @@ VARIABLE_DECLARATION : VAR 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:"");
-}
-ASSIGNMENT :           T_IDENTIFIER '=' EXPRESSION {
-    class_signature_t*type=0;
-    int i = find_variable($1->text, &type);
-    $$ = $3.c;
-    if(!type && $3.t) {
-        // convert to "any" type, the register is untyped
-        $$ = abc_coerce_a($$);
-    } else {
-        // TODO: convert ints to strings etc.
-    }
-    $$ = abc_setlocal($$, i);
+    //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);
    
@@ -829,167 +1301,362 @@ 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();
 }
 
 FOR_INIT : {$$=code_new();}
-FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
-
-FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
-    $$ = state->initcode;state->initcode=0;
+FOR_INIT : VARIABLE_DECLARATION
+FOR_INIT : VOIDEXPRESSION
 
+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();
 }
 
-BREAK : "break" {
-    $$ = abc___break__(0);
+DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
+    $$ = code_new();
+    code_t*loopstart = $$ = abc_label($$);
+    $$ = code_append($$, $3);
+    code_t*cont = $$ = abc_nop($$);
+    $$ = code_append($$, $6.c);
+    $$ = abc_iftrue($$, loopstart);
+    code_t*out = $$ = abc_nop($$);
+    breakjumpsto($$, $1, out);
+    continuejumpsto($$, $1, cont);
+    $$ = killvars($$);
+    old_state();
+}
+
+BREAK : "break" %prec prec_none {
+    $$ = abc___break__(0, "");
+}
+BREAK : "break" T_IDENTIFIER {
+    $$ = abc___break__(0, $2);
+}
+CONTINUE : "continue" %prec prec_none {
+    $$ = abc___continue__(0, "");
+}
+CONTINUE : "continue" T_IDENTIFIER {
+    $$ = abc___continue__(0, $2);
 }
 
 /* ------------ packages and imports ---------------- */
 
-PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
-PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
+X_IDENTIFIER: T_IDENTIFIER
+            | "package" {$$="package";}
 
-PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
+PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
 PACKAGE: X_IDENTIFIER             {$$=$1;}
 
-IMPORT : "import" PACKAGE '.' X_IDENTIFIER {
-       class_signature_t*c = registry_findclass($2->text, $4->text);
+PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
+PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
+
+IMPORT : "import" QNAME {
+       classinfo_t*c = $2;
        if(!c) 
-            syntaxerror("Couldn't import %s.%s\n", $2->text, $4->text);
+            syntaxerror("Couldn't import class\n");
        state_has_imports();
-       dict_put(state->imports, $4->text, c);
+       dict_put(state->imports, c->name, c);
        $$=0;
 }
 IMPORT : "import" PACKAGE '.' '*' {
        NEW(import_t,i);
-       i->package = $2->text;
+       i->package = $2;
        state_has_imports();
        list_append(state->wildcard_imports, i);
        $$=0;
 }
 
-/* ------------ classes and interfaces -------------- */
+/* ------------ classes and interfaces (header) -------------- */
+
+MAYBE_MODIFIERS : {$$=0;}
+MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
+MODIFIER_LIST : MODIFIER               {$$=$1;}
+MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
 
-MODIFIERS : {$$=empty_token();}
-MODIFIERS : MODIFIER_LIST {$$=$1}
-MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
-MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
-MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
+MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
+         | KW_PRIVATE {$$=FLAG_PRIVATE;}
+         | KW_PROTECTED {$$=FLAG_PROTECTED;}
+         | KW_STATIC {$$=FLAG_STATIC;}
+         | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
+         | KW_FINAL {$$=FLAG_FINAL;}
+         | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
+         | KW_NATIVE {$$=FLAG_NATIVE;}
+         | KW_INTERNAL {$$=FLAG_INTERNAL;}
 
 EXTENDS : {$$=registry_getobjectclass();}
-EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
+EXTENDS : KW_EXTENDS QNAME {$$=$2;}
 
 EXTENDS_LIST : {$$=list_new();}
-EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
+EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
 
 IMPLEMENTS_LIST : {$$=list_new();}
-IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
+IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
 
-CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER 
+CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
                               EXTENDS IMPLEMENTS_LIST 
                               '{' {startclass($1,$3,$4,$5, 0);} 
                               MAYBE_DECLARATION_LIST 
                               '}' {endclass();}
-INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER 
+
+INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
                               EXTENDS_LIST 
                               '{' {startclass($1,$3,0,$4,1);}
                               MAYBE_IDECLARATION_LIST 
                               '}' {endclass();}
 
-/* ------------- package + class ids --------------- */
+/* ------------ classes and interfaces (body) -------------- */
 
-PACKAGEANDCLASS : T_IDENTIFIER {
+MAYBE_DECLARATION_LIST : 
+MAYBE_DECLARATION_LIST : DECLARATION_LIST
+DECLARATION_LIST : DECLARATION
+DECLARATION_LIST : DECLARATION_LIST DECLARATION
+DECLARATION : ';'
+DECLARATION : SLOT_DECLARATION
+DECLARATION : FUNCTION_DECLARATION
 
-    /* try current package */
-    $$ = registry_findclass(state->package, $1->text);
+MAYBE_IDECLARATION_LIST : 
+MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
+IDECLARATION_LIST : IDECLARATION
+IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
+IDECLARATION : ';'
+IDECLARATION : "var" T_IDENTIFIER {
+    syntaxerror("variable declarations not allowed in interfaces");
+}
+IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
+    $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,$1,$3,$4,&$6,$8, 0);
+}
 
-    /* try explicit imports */
-    dictentry_t* e = dict_get_slot(state->imports, $1->text);
-    while(e) {
-        if($$)
-            break;
-        if(!strcmp(e->key, $1->text)) {
-            $$ = (class_signature_t*)e->data;
+/* ------------ classes and interfaces (body, slots ) ------- */
+
+VARCONST: "var" | "const"
+
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
+    int flags = $1;
+    memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
+    info->type = $4;
+    info->flags = flags;
+    trait_t*t=0;
+
+    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);
         }
-        e = e->next;
+        info->slot = t->slot_id;
+    } else {
+        if($4) {
+            MULTINAME(m, $4);
+            t=abc_class_staticslot(state->cls->abc, &mname, &m);
+        } else {
+            t=abc_class_staticslot(state->cls->abc, &mname, 0);
+        }
+        info->slot = t->slot_id;
     }
-
-    /* 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->text);
-        $$ = registry_findclass(l->import->package, $1->text);
-        l = l->next;
+    if($5.c && !is_pushundefined($5.c)) {
+        code_t*c = 0;
+        c = abc_getlocal_0(c);
+        c = code_append(c, $5.c);
+        c = converttype(c, $5.t, $4);
+        c = abc_setslot(c, t->slot_id);
+        if(!(flags&FLAG_STATIC))
+            state->cls->init = code_append(state->cls->init, c);
+        else
+            state->cls->static_init = code_append(state->cls->static_init, c);
+    }
+    if($2==KW_CONST) {
+        t->kind= TRAIT_CONST;
     }
+}
 
-    /* try global package */
-    if(!$$) {
-        $$ = registry_findclass("", $1->text);
+/* ------------ constants -------------------------------------- */
+
+MAYBESTATICCONSTANT: {$$=0;}
+MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
+
+STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
+STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
+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 : "true" {$$ = constant_new_true($1);}
+STATICCONSTANT : "false" {$$ = constant_new_false($1);}
+STATICCONSTANT : "null" {$$ = constant_new_null($1);}
+
+/* ------------ classes and interfaces (body, functions) ------- */
+
+// non-vararg version
+MAYBE_PARAM_LIST: {
+    memset(&$$,0,sizeof($$));
+}
+MAYBE_PARAM_LIST: PARAM_LIST {
+    $$=$1;
+}
+
+// vararg version
+MAYBE_PARAM_LIST: "..." PARAM {
+    memset(&$$,0,sizeof($$));
+    $$.varargs=1;
+    list_append($$.list, $2);
+}
+MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
+    $$ =$1;
+    $$.varargs=1;
+    list_append($$.list, $4);
+}
+
+// non empty
+PARAM_LIST: PARAM_LIST ',' PARAM {
+    $$ = $1;
+    list_append($$.list, $3);
+}
+PARAM_LIST: PARAM {
+    memset(&$$,0,sizeof($$));
+    list_append($$.list, $1);
+}
+
+PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
+     $$ = malloc(sizeof(param_t));
+     $$->name=$1;
+     $$->type = $3;
+     $$->value = $4;
+}
+PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
+     $$ = malloc(sizeof(param_t));
+     $$->name=$1;
+     $$->type = TYPE_ANY;
+     $$->value = $2;
+}
+GETSET : "get" {$$=$1;}
+       | "set" {$$=$1;}
+       |       {$$=0;}
+
+FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
+                      MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
+{
+    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);
+}
 
-    if(!$$) syntaxerror("Could not find class %s\n", $1->text);
+/* ------------- package + class ids --------------- */
+
+CLASS: T_IDENTIFIER {
+
+    /* try current package */
+    $$ = find_class($1);
+    if(!$$) syntaxerror("Could not find class %s\n", $1);
 }
+
 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
-    $$ = registry_findclass($1->text, $3->text);
-    if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
+    $$ = registry_findclass($1, $3);
+    if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
 }
 
+QNAME: PACKAGEANDCLASS
+     | CLASS
+
+QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
+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}
 
 MAYBE_EXPRESSION_LIST : {$$=0;}
 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
-EXPRESSION_LIST : EXPRESSION                     {$$=list_new();
+EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
                                                   *t = $1;
                                                   list_append($$, t);}
-EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=$1;
+EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
                                                   *t = $3;
                                                   list_append($$, t);}
 
-NEW : "new" PACKAGEANDCLASS MAYBE_PARAM_VALUES {
+NEW : "new" CLASS MAYBE_PARAM_VALUES {
     MULTINAME(m, $2);
     $$.c = code_new();
-    $$.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;
     while(l) {
@@ -997,27 +1664,114 @@ NEW : "new" PACKAGEANDCLASS 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;
 }
 
-FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
-    /* TODO: use abc_call (for calling local variables),
-             abc_callstatic (for calling own methods) */
-    $$.c = code_new();
-    $$.c = abc_findpropstrict($$.c, $1->text);
+/* TODO: use abc_call (for calling local variables),
+         abc_callstatic (for calling own methods) 
+         call (for closures)
+*/
+FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
     typedcode_list_t*l = $3;
     int len = 0;
+    code_t*paramcode = 0;
     while(l) {
-        $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
+        paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
         l = l->next;
         len ++;
     }
-    $$.c = abc_callproperty($$.c, $1->text, len);
-    /* TODO: look up the functions's return value */
+       
+    $$.c = $1.c;
+    if($$.c->opcode == OPCODE_COERCE_A) {
+        $$.c = code_cutlast($$.c);
+    }
+
+    $$.t = TYPE_ANY;
+    multiname_t*name = 0;
+    if($$.c->opcode == OPCODE_GETPROPERTY) {
+        name = multiname_clone($$.c->data[0]);
+        $$.c = code_cutlast($$.c);
+        $$.c = code_append($$.c, paramcode);
+        $$.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->abc,slot);//FIXME
+        if(t->kind!=TRAIT_METHOD) {
+            //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);
+        $$.c = abc_call($$.c, len);
+    }
+   
+    memberinfo_t*f = 0;
+   
+    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);
 }
@@ -1026,27 +1780,29 @@ RETURN: "return" EXPRESSION {
     $$ = abc_returnvalue($$);
 }
 
-TYPE : PACKAGEANDCLASS {$$=$1;}
-     | '*'        {$$=registry_getanytype();}
-     |  "String"  {$$=registry_getstringclass();}
-     |  "int"     {$$=registry_getintclass();}
-     |  "uint"    {$$=registry_getuintclass();}
-     |  "Boolean" {$$=registry_getbooleanclass();}
-     |  "Number"  {$$=registry_getnumberclass();}
-
-MAYBETYPE: ':' TYPE {$$=$2;}
-MAYBETYPE:          {$$=0;}
+// ----------------------- expression types -------------------------------------
 
-//FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
-FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
-                      MAYBETYPE
+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 below_minus {
+    $$=cut_last_push($1.c);
+}
 
-NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
-NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
-NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
+// ----------------------- expression evaluation -------------------------------------
 
-//NAMESPACE :              {$$=empty_token();}
-//NAMESPACE : T_IDENTIFIER {$$=$1};
+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;
+                                }
 
 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
                    //MULTINAME(m, registry_getintclass());
@@ -1065,31 +1821,22 @@ CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
                     $$.t = TYPE_FLOAT;
                    }
-CONSTANT : T_STRING {$$.c = abc_pushstring(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;
                    }
 
-USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
-
-
-EXPRESSION : E %prec prec_none  /*precedence below '-x'*/ {$$ = $1;}
-VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
-
-E : CONSTANT
-E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
-E : NEW                         {$$ = $1;}
-E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
-                                 $$.t = TYPE_ANY;
-                                }
 E : FUNCTIONCALL
 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
              $$.t = TYPE_BOOLEAN;
@@ -1108,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;
@@ -1118,20 +1868,26 @@ E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
               $$.c = converttype($$.c, $1.t, $$.t);
               $$.c = abc_dup($$.c);
               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
-              $$.c = abc_pop($$.c);
+              $$.c = cut_last_push($$.c);
               $$.c = code_append($$.c,$3.c);
-              $$.c = converttype($$.c, $1.t, $$.t);
+              $$.c = converttype($$.c, $3.t, $$.t);
               code_t*label = $$.c = abc_label($$.c);
               jmp->branch = label;
              }
-E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
+E : E "&&" E {
+              $$.t = join_types($1.t, $3.t, 'A');
+              /*printf("%08x:\n",$1.t);
+              code_dump($1.c, 0, 0, "", stdout);
+              printf("%08x:\n",$3.t);
+              code_dump($3.c, 0, 0, "", stdout);
+              printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
               $$.c = $1.c;
               $$.c = converttype($$.c, $1.t, $$.t);
               $$.c = abc_dup($$.c);
               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
-              $$.c = abc_pop($$.c);
+              $$.c = cut_last_push($$.c);
               $$.c = code_append($$.c,$3.c);
-              $$.c = converttype($$.c, $1.t, $$.t);
+              $$.c = converttype($$.c, $3.t, $$.t);
               code_t*label = $$.c = abc_label($$.c);
               jmp->branch = label;              
              }
@@ -1141,123 +1897,446 @@ 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_urshift($$.c);
+             $$.t = TYPE_INT;
+            }
+E : E "<<" E {$$.c = code_append($1.c,$3.c);
+             $$.c = abc_lshift($$.c);
+             $$.t = TYPE_INT;
+            }
+
+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);$$.c=abc_coerce_a($$.c);
-             $$.t = join_types($1.t, $3.t, '%');
+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);$$.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);
+             if(BOTH_INT($1,$3)) {
+                $$.c = abc_multiply_i($$.c);
+                $$.t = TYPE_INT;
+             } else {
+                $$.c = abc_multiply($$.c);
+                $$.t = TYPE_NUMBER;
+             }
             }
 
-E : E "as" TYPE
-E : E "is" TYPE
-E : '(' E ')' {$$=$2;}
-E : '-' E {$$=$2;}
+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;
+  $$.c = code_append($$.c, $3.c);
+  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(BOTH_INT($1,$3)) {
+                c=abc_multiply_i(c);
+               } else {
+                c=abc_multiply(c);
+               }
+               c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
+               $$.c = toreadwrite($1.c, c, 0, 0);
+               $$.t = $1.t;
+              }
 
-E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
-               class_signature_t*type = join_types($1.type, $3.t, '+');
-               $$.c=converttype($$.c, type, $1.type);
-               $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
-               $$.t = $1.type;
+E : E "%=" E { 
+               code_t*c = abc_modulo($3.c);
+               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 = abc_lshift($3.c);
+               c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
+               $$.c = toreadwrite($1.c, c, 0, 0);
+               $$.t = $1.t;
               }
-E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
-               class_signature_t*type = join_types($1.type, $3.t, '-');
-               $$.c=converttype($$.c, type, $1.type);
-               $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
-               $$.t = $1.type;
+E : E ">>=" E { 
+               code_t*c = abc_rshift($3.c);
+               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 = abc_urshift($3.c);
+               c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
+               $$.c = toreadwrite($1.c, c, 0, 0);
+               $$.t = $1.t;
+              }
+E : E "/=" E { 
+               code_t*c = abc_divide($3.c);
+               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)) {
+                c=abc_add_i(c);
+               } else {
+                c=abc_add(c);
+               }
+               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)) {
+                c=abc_subtract_i(c);
+               } else {
+                c=abc_subtract(c);
+               }
+               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 = 0;
+              c = code_append(c, $3.c);
+              c = converttype(c, $3.t, $1.t);
+              $$.c = toreadwrite($1.c, c, 1, 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 : LH "++" {$$.c = $1.read;
-             class_signature_t*type = $1.type;
+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);
+                 c=abc_increment_i(c);
+                 type = TYPE_INT;
              } else {
-                 $$.c=abc_increment($$.c);
+                 c=abc_increment(c);
                  type = TYPE_NUMBER;
              }
-             $$.c=converttype($$.c, type, $1.type);
-             $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
-             $$.t = $1.type;
-            }
-E : LH "--" {$$.c = $1.read;
-             class_signature_t*type = $1.type;
+             c=converttype(c, type, $1.t);
+             $$.c = toreadwrite($1.c, c, 0, 1);
+             $$.t = $1.t;
+           }
+E : E "--" { code_t*c = 0;
+             classinfo_t*type = $1.t;
              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
-                 $$.c=abc_decrement_i($$.c);
+                 c=abc_decrement_i(c);
+                 type = TYPE_INT;
              } else {
-                 $$.c=abc_decrement($$.c);
+                 c=abc_decrement(c);
                  type = TYPE_NUMBER;
              }
-             $$.c=converttype($$.c, type, $1.type);
-             $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
-             $$.t = $1.type;
+             c=converttype(c, type, $1.t);
+             $$.c = toreadwrite($1.c, c, 0, 1);
+             $$.t = $1.t;
             }
 
-LH: T_IDENTIFIER {
-  int i = find_variable($1->text, &$$.type);
-  $$.read = abc_getlocal(0, i);
-  $$.write = abc_setlocal(0, i);
-}
+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);
+                 type = TYPE_INT;
+             } else {
+                 c=abc_increment(c);
+                 type = TYPE_NUMBER;
+             }
+             c=converttype(c, type, $2.t);
+             $$.c = toreadwrite($2.c, c, 0, 0);
+             $$.t = $2.t;
+           }
 
+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);
+                 type = TYPE_INT;
+             } else {
+                 c=abc_decrement(c);
+                 type = TYPE_NUMBER;
+             }
+             c=converttype(c, type, $2.t);
+             $$.c = toreadwrite($2.c, c, 0, 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;
+             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 {
+                     MEMBER_MULTINAME(m, f, $3);
+                     $$.c = abc_getproperty2($$.c, &m);
+                 }
+                 /* determine type */
+                 $$.t = memberinfo_gettype(f);
+                 if(!$$.t)
+                    $$.c = abc_coerce_a($$.c);
+             } else {
+                 /* 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();
+             }
+            }
 
 VAR_READ : T_IDENTIFIER {
-    int i = find_variable($1->text, &$$.t);
-    $$.c = abc_getlocal(0, i);
+    $$.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);
+
+    /* 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;
+        }
+    
+    /* 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 {
+        if(strcmp($1,"trace"))
+            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_findpropstrict2($$.c, &m);
+        $$.c = abc_getproperty2($$.c, &m);
+    }
 }
 
-//VARIABLE : T_IDENTIFIER
-//VARIABLE : VARIABLE '.' T_IDENTIFIER
+//TODO: 
 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
-//VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
-
-// keywords which also may be identifiers
-X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
-
-GETSET : "get" {$$=$1;}
-       | "set" {$$=$1;}
-       |       {$$=empty_token();}
-
-MAYBE_PARAM_LIST: {$$=list_new();}
-MAYBE_PARAM_LIST: PARAM_LIST {$$=$1;}
-PARAM_LIST: PARAM_LIST ',' PARAM {$$ =$1;         list_append($$, $3);}
-PARAM_LIST: PARAM                {$$ = list_new();list_append($$, $1);}
-PARAM:  T_IDENTIFIER ':' TYPE {$$ = malloc(sizeof(param_t));
-                               $$->name=$1->text;$$->type = $3;}
-PARAM:  T_IDENTIFIER          {$$ = malloc(sizeof(param_t));
-                               $$->name=$1->text;$$->type = TYPE_ANY;}
-
-DECLARATION : VARIABLE_DECLARATION
-DECLARATION : FUNCTION_DECLARATION
-
-IDECLARATION : VARIABLE_DECLARATION
-IDECLARATION : FUNCTION_DECLARATION
 
-//IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
-//IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
+// ----------------- namespaces -------------------------------------------------
 
-MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
-MULTILEVELIDENTIFIER : T_IDENTIFIER                 {$$=$1;extend($$,$1)};
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
 
-PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
-PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
-
-MAYBE_DECLARATION_LIST : 
-MAYBE_DECLARATION_LIST : DECLARATION_LIST
-DECLARATION_LIST : DECLARATION
-DECLARATION_LIST : DECLARATION_LIST DECLARATION
-
-MAYBE_IDECLARATION_LIST : 
-MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
-IDECLARATION_LIST : IDECLARATION
-IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
-
-// chapter 14
-// keywords: as break case catch class const continue default delete do else extends false finally for function if implements import in instanceof interface internal is native new null package private protected public return super switch this throw to true try typeof use var void while with
-// syntactic keywords: each get set namespace include dynamic final native override static
+USE_NAMESPACE : "use" "namespace" T_IDENTIFIER