numerous small bugfixes
[swftools.git] / lib / as3 / parser.y
index 3f72304..2de22f6 100644 (file)
@@ -175,7 +175,7 @@ extern int a3_lex();
 %type <code> CODE
 %type <code> CODEPIECE CODE_STATEMENT
 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
-%type <code> PACKAGE_DECLARATION SLOT_DECLARATION
+%type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
 %type <exception> CATCH FINALLY
@@ -347,8 +347,9 @@ typedef struct _state {
     
     char*package;     
     import_list_t*wildcard_imports;
-    namespace_list_t*active_namespaces;
+    dict_t*import_toplevel_packages;
     dict_t*imports;
+    namespace_list_t*active_namespaces;
     char has_own_imports;
     char new_vars; // e.g. transition between two functions
   
@@ -426,6 +427,9 @@ static void new_state()
     if(!s->imports) {
         s->imports = dict_new();
     }
+    if(!s->import_toplevel_packages) {
+        s->import_toplevel_packages = dict_new(); 
+    }
     state = s;
     state->level++;
     state->has_own_imports = 0;    
@@ -439,6 +443,18 @@ static void state_has_imports()
     state->imports = dict_clone(state->imports);
     state->has_own_imports = 1;
 }
+static void import_toplevel(const char*package)
+{
+    char* s = strdup(package);
+    while(1) {
+        dict_put(state->import_toplevel_packages, s, 0);
+        char*x = strrchr(s, '.');
+        if(!x)
+            break;
+        *x = 0;
+    }
+    free(s);
+}
 
 static void state_destroy(state_t*state)
 {
@@ -815,6 +831,7 @@ static namespace_t modifiers2access(modifiers_t*mod)
     }
     return ns;
 }
+static slotinfo_t* find_class(const char*name);
 
 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
 {
@@ -835,7 +852,18 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char
            that those variable indices are reserved. It's up to the
            optimizer to later shuffle the variables down to lower
            indices */
-        m->variable_count = m->uses_slots; 
+        m->variable_count = m->uses_slots;
+        DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
+            if(v->type) {
+                if(v->type->package)
+                    v->type = (classinfo_t*)registry_find(v->type->package, v->type->name);
+                else
+                    v->type = (classinfo_t*)find_class(v->type->name);
+                if(!v->type || v->type->kind != INFOTYPE_CLASS) {
+                    syntaxerror("Couldn't find class %s", v->type->name);
+                }
+            }
+        }
     }
 
     if(params) {
@@ -863,6 +891,7 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
     if(state->cls) {
         syntaxerror("inner classes now allowed"); 
     }
+
     new_state();
     token_list_t*t=0;
     classinfo_list_t*mlist=0;
@@ -872,6 +901,11 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
 
     if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
         syntaxerror("public and internal not supported at the same time.");
+    
+    if(!(mod->flags&FLAG_INTERFACE) && !extends) {
+        // all classes extend object
+        extends = registry_getobjectclass();
+    }
 
     /* create the class name, together with the proper attributes */
     int access=0;
@@ -923,7 +957,7 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
             syntaxerror("Can't extend final class '%s'", extends->name);
 
         /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
-        state->cls->info->superclass = extends?extends:TYPE_OBJECT;
+        state->cls->info->superclass = extends;
         int pos = 0;
         classinfo_list_t*l = implements;
         for(l=implements;l;l=l->next) {
@@ -1012,10 +1046,14 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
     }
 }
 
-static void setstaticfunction(int x)
+static int slotstate_varconst = 0;
+static modifiers_t*slotstate_flags = 0;
+static void setslotstate(modifiers_t* flags, int varconst)
 {
+    slotstate_varconst = varconst;
+    slotstate_flags = flags;
     if(state->cls) {
-        if(x&FLAG_STATIC) {
+        if(flags && flags->flags&FLAG_STATIC) {
             state->method = state->cls->static_init;
         } else {
             state->method = state->cls->init;
@@ -1066,6 +1104,10 @@ void check_code_for_break(code_t*c)
             char*name = string_cstr(c->data[0]);
             syntaxerror("Unresolved \"continue %s\"", name);
         }
+        if(c->opcode == OPCODE___PUSHPACKAGE__) {
+            char*name = string_cstr(c->data[0]);
+            syntaxerror("Can't reference a package (%s) as such", name);
+        }
         c=c->prev;
     }
 }
@@ -1101,12 +1143,15 @@ static void check_override(memberinfo_t*m, int flags)
         return;
     if(m->flags & FLAG_FINAL)
         syntaxerror("can't override final member %s", m->name);
+    
+    /* allow this. it's no issue.
     if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
-        syntaxerror("can't override static member %s", m->name);
+        syntaxerror("can't override static member %s", m->name);*/
+
     if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
         syntaxerror("can't override non-static member %s with static declaration", m->name);
 
-    if(!(flags&FLAG_OVERRIDE)) {
+    if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
         if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
             if(m->kind == INFOTYPE_METHOD)
                 syntaxerror("can't override without explicit 'override' declaration");
@@ -1123,7 +1168,7 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c
     if(!state->cls) {
         //package method
         minfo = methodinfo_register_global(ns.access, state->package, name);
-        minfo->return_type = return_type;
+        minfo->return_type = 0; // save this for pass 2
     } else if(getset != KW_GET && getset != KW_SET) {
         //class method
         memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
@@ -1134,7 +1179,7 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c
             syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
         }
         minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
-        minfo->return_type = return_type;
+        minfo->return_type = 0; // save this for pass 2 
         // 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;
@@ -1142,10 +1187,12 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c
         //class getter/setter
         int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
         classinfo_t*type=0;
-        if(getset == KW_GET)
+        if(getset == KW_GET) {
             type = return_type;
-        else if(params->list && params->list->param)
+        } else if(params->list && params->list->param && !params->list->next) {
             type = params->list->param->type;
+        } else
+            syntaxerror("setter function needs to take exactly one argument");
         // not sure wether to look into superclasses here, too
         minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
         if(minfo) {
@@ -1157,17 +1204,22 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c
                 syntaxerror("getter/setter for '%s' already defined", name);
             /* make a setter or getter into a getset */
             minfo->subtype |= gs;
-            if(!minfo->return_type) {
-                minfo->return_type = type;
-            } else {
-                if(minfo && minfo->return_type != type)
-                    syntaxerror("different type in getter and setter");
-            }
+            
+            /*
+            FIXME: this check needs to be done in pass 2
+            
+            if((!minfo->return_type != !type) ||
+                (minfo->return_type && type && 
+                 !strcmp(minfo->return_type->name, type->name))) {
+                syntaxerror("different type in getter and setter: %s and %s", 
+                    minfo->return_type?minfo->return_type->name:"*", 
+                    type?type->name:"*");
+            }*/
         } else {
             minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
             minfo->kind = INFOTYPE_SLOT; //hack
             minfo->subtype = gs;
-            minfo->return_type = type;
+            minfo->return_type = 0;
         }
         /* can't assign a slot as getter and setter might have different slots */
         //minfo->slot = slot;
@@ -1208,7 +1260,7 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
             list_append(parent_method->innerfunctions, state->method);
 
         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
-       
+    
         function_initvars(state->method, params, 0, 1);
     }
 
@@ -1244,7 +1296,6 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
         if(state->method->is_constructor)
             name = "__as3_constructor__";
 
-        return_type = 0;
         state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
        
         function_initvars(state->method, params, mod->flags, 1);
@@ -1281,7 +1332,9 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
         function_initvars(state->method, 0, 0, 0);
 
         methodstate_list_t*ml = state->method->innerfunctions;
+        
         dict_t*xvars = dict_new();
+
         while(ml) {
             methodstate_t*m = ml->methodstate;
             parserassert(m->inner);
@@ -1292,7 +1345,8 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
                     dictentry_t*l = d->slots[t]; 
                     while(l) {
                         /* check parent method's variables */
-                        if(find_variable(state, l->key)) {
+                        variable_t*v;
+                        if((v=find_variable(state, l->key))) {
                             m->uses_parent_function = 1;
                             state->method->uses_slots = 1;
                             dict_put(xvars, l->key, 0);
@@ -1307,6 +1361,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
             }
             ml = ml->next;
         }
+        
         if(state->method->uses_slots) {
             state->method->slots = dict_new();
             int i = 1;
@@ -1324,8 +1379,6 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
             state->method->uses_slots = i;
             dict_destroy(state->vars);state->vars = 0;
         }
-        dict_destroy(xvars);
-
         old_state();
         return 0;
     }
@@ -1397,6 +1450,12 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
 
         check_code_for_break(body);
 
+        if(state->method->exceptions &&
+           (state->method->late_binding || state->method->uses_slots)) {
+           //syntaxerror("try/catch and activation or late binding not supported yet within the same method");
+           as3_warning("try/catch and activation or late binding not supported yet within the same method");
+        }
+
         if(f->body) {
             f->body->code = body;
             f->body->exceptions = state->method->exceptions;
@@ -1543,7 +1602,7 @@ char is_pushundefined(code_t*c)
     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
 }
 
-static slotinfo_t* find_class(char*name)
+static slotinfo_t* find_class(const char*name)
 {
     slotinfo_t*c=0;
 
@@ -1580,6 +1639,43 @@ static slotinfo_t* find_class(char*name)
 
     return 0;
 }
+typedcode_t push_class(slotinfo_t*a)
+{
+    typedcode_t x;
+    x.c = 0;
+    x.t = 0;
+    if(a->access == ACCESS_PACKAGEINTERNAL &&
+       strcmp(a->package, state->package) &&
+       strcmp(a->package, internal_filename_package)
+       ) {
+       syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
+            infotypename(a), a->name, a->package, state->package);
+    }
+
+    if(a->kind != INFOTYPE_CLASS) {
+        MULTINAME(m, a);
+        x.c = abc_findpropstrict2(x.c, &m);
+        x.c = abc_getproperty2(x.c, &m);
+        if(a->kind == INFOTYPE_METHOD) {
+            methodinfo_t*f = (methodinfo_t*)a;
+            x.t = TYPE_FUNCTION(f);
+        } else {
+            varinfo_t*v = (varinfo_t*)a;
+            x.t = v->type;
+        }
+    } else {
+        classinfo_t*c = (classinfo_t*)a;
+        if(c->slot) {
+            x.c = abc_getglobalscope(x.c);
+            x.c = abc_getslot(x.c, c->slot);
+        } else {
+            MULTINAME(m, c);
+            x.c = abc_getlex2(x.c, &m);
+        }
+        x.t = TYPE_CLASS(c);
+    }
+    return x;
+}
 
 static char is_getlocal(code_t*c)
 {
@@ -1627,7 +1723,7 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
     } else {
         prefix = 0;
     }
-
+        
     char use_temp_var = readbefore;
 
     /* generate the write instruction, and maybe append a dup to the prefix code */
@@ -1676,6 +1772,10 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
         write->opcode = OPCODE_SETLOCAL_2;
     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
         write->opcode = OPCODE_SETLOCAL_3;
+    } else if(r->opcode == OPCODE_GETSUPER) { 
+        write->opcode = OPCODE_SETSUPER;
+        multiname_t*m = (multiname_t*)r->data[0];
+        write->data[0] = multiname_clone(m);
     } else {
         code_dump(r);
         syntaxerror("illegal lvalue: can't assign a value to this expression");
@@ -2103,6 +2203,10 @@ FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
 
 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
     variable_t*var = find_variable(state, $2);
+    if(!var) {
+        syntaxerror("variable %s not known in this scope", $2);
+    }
+
     char*tmp1name = concat2($2, "__tmp1__");
     int it = new_variable(tmp1name, TYPE_INT, 0, 0);
     char*tmp2name = concat2($2, "__array__");
@@ -2364,7 +2468,7 @@ THROW : "throw" %prec prec_none {
 
 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
      $$ = $3.c;
-     $$ = abc_pushscope($$);
+     $$ = abc_pushwith($$);
      $$ = code_append($$, $5);
      $$ = abc_popscope($$);
 }
@@ -2385,7 +2489,7 @@ PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
 IMPORT : "import" PACKAGEANDCLASS {
        PASS12
        slotinfo_t*s = registry_find($2->package, $2->name);
-       if(!s) {// || !(s->flags&FLAG_BUILTIN)) {
+       if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
            as3_schedule_class($2->package, $2->name);
        }
 
@@ -2395,11 +2499,12 @@ IMPORT : "import" PACKAGEANDCLASS {
             syntaxerror("Couldn't import class\n");
        state_has_imports();
        dict_put(state->imports, c->name, c);
+       import_toplevel(c->package);
        $$=0;
 }
 IMPORT : "import" PACKAGE '.' '*' {
        PASS12
-       if(strncmp("flash.", $2, 6)) {
+       if(strncmp("flash.", $2, 6) && as3_pass==1) {
            as3_schedule_package($2);
        }
 
@@ -2408,6 +2513,7 @@ IMPORT : "import" PACKAGE '.' '*' {
        i->package = $2;
        state_has_imports();
        list_append(state->wildcard_imports, i);
+       import_toplevel(i->package);
        $$=0;
 }
 
@@ -2437,7 +2543,7 @@ MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
                                $$.ns=$1;
                        }
 
-EXTENDS : {$$=registry_getobjectclass();}
+EXTENDS : {$$=0;}
 EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
 
 EXTENDS_LIST : {PASS12 $$=list_new();}
@@ -2499,33 +2605,39 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI
 
 VARCONST: "var" | "const"
 
-SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1.flags);} MAYBETYPE MAYBEEXPRESSION {
-    int flags = $1.flags;
-    namespace_t ns = modifiers2access(&$1);
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {setslotstate(&$1,$2);} SLOT_LIST {$$=$4;setslotstate(0, 0);}
+
+SLOT_LIST: ONE_SLOT               {$$ = $1;}
+SLOT_LIST: SLOT_LIST ',' ONE_SLOT {$$ = code_append($1, $3);}
+
+ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
+{
+    int flags = slotstate_flags->flags;
+    namespace_t ns = modifiers2access(slotstate_flags);
 
     varinfo_t* info = 0;
     if(state->cls) {
-        memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $3, 1);
+        memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
         if(i) {
             check_override(i, flags);
         }
-        info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $3);
+        info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
     } else {
-        slotinfo_t*i = registry_find(state->package, $3);
+        slotinfo_t*i = registry_find(state->package, $1);
         if(i) {
-            syntaxerror("package %s already contains '%s'", state->package, $3);
+            syntaxerror("package %s already contains '%s'", state->package, $1);
         }
         if(ns.name && ns.name[0]) {
             syntaxerror("namespaces not allowed on package-level variables");
         }
-        info = varinfo_register_global(ns.access, state->package, $3);
+        info = varinfo_register_global(ns.access, state->package, $1);
     }
 
-    info->type = $5;
+    info->type = $2;
     info->flags = flags;
 
     /* slot name */
-    multiname_t mname = {QNAME, &ns, 0, $3};
+    multiname_t mname = {QNAME, &ns, 0, $1};
   
     trait_list_t**traits;
     code_t**code;
@@ -2545,8 +2657,8 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1.fl
     }
     
     trait_t*t=0;
-    if($5) {
-        MULTINAME(m, $5);
+    if($2) {
+        MULTINAME(m, $2);
         t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
     } else {
         t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
@@ -2555,21 +2667,20 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1.fl
     
     /* initalization code (if needed) */
     code_t*c = 0;
-    if($6.c && !is_pushundefined($6.c)) {
+    if($3.c && !is_pushundefined($3.c)) {
         c = abc_getlocal_0(c);
-        c = code_append(c, $6.c);
-        c = converttype(c, $6.t, $5);
+        c = code_append(c, $3.c);
+        c = converttype(c, $3.t, $2);
         c = abc_setslot(c, t->slot_id);
     }
 
     *code = code_append(*code, c);
 
-    if($2==KW_CONST) {
+    if(slotstate_varconst==KW_CONST) {
         t->kind= TRAIT_CONST;
     }
 
     $$=0;
-    setstaticfunction(0);
 }
 
 /* ------------ constants -------------------------------------- */
@@ -2587,9 +2698,12 @@ STATICCONSTANT : "true" {$$ = constant_new_true($1);}
 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
 STATICCONSTANT : T_IDENTIFIER {
-    // TODO
-    as3_warning("Couldn't resolve %s", $1);
-    $$ = constant_new_null($1);
+    if(!strcmp($1, "NaN")) {
+        $$ = constant_new_float(__builtin_nan(""));
+    } else {
+        as3_warning("Couldn't evaluate constant value of %s", $1);
+        $$ = constant_new_null($1);
+    }
 }
 
 /* ------------ classes and interfaces (body, functions) ------- */
@@ -2694,10 +2808,15 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
 /* ------------- package + class ids --------------- */
 
 CLASS: T_IDENTIFIER {
-    PASS1 static slotinfo_t c;
+    PASS1 static classinfo_t c;
           memset(&c, 0, sizeof(c));
+          c.kind = INFOTYPE_CLASS;
+          c.subtype = 255;
           c.name = $1;
-          $$ = (classinfo_t*)&c;
+          $$ = &c;
+   
+          /* let the compiler know that we might be looking for this soon */
+          as3_schedule_class_noerror(state->package, $1);
     PASS2
     slotinfo_t*s = find_class($1);
     if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
@@ -2705,11 +2824,13 @@ CLASS: T_IDENTIFIER {
 }
 
 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
-    PASS1 static slotinfo_t c;
+    PASS1 static classinfo_t c;
           memset(&c, 0, sizeof(c));
+          c.kind = INFOTYPE_CLASS;
+          c.subtype = 255;
           c.package = $1;
           c.name = $3;
-          $$=(classinfo_t*)&c;
+          $$ = &c;
     PASS2
     slotinfo_t*s = registry_find($1, $3);
     if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
@@ -2723,9 +2844,9 @@ CLASS_SPEC: PACKAGEANDCLASS
 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
 
-TYPE : CLASS_SPEC {$$=$1;}
-     | '*'        {$$=registry_getanytype();}
-     | "void"     {$$=registry_getanytype();}
+TYPE : CLASS_SPEC {PASS12 $$=$1;}
+     | '*'        {PASS12 $$=registry_getanytype();}
+     | "void"     {PASS12 $$=registry_getanytype();}
     /*
      |  "String"  {$$=registry_getstringclass();}
      |  "int"     {$$=registry_getintclass();}
@@ -2734,8 +2855,8 @@ TYPE : CLASS_SPEC {$$=$1;}
      |  "Number"  {$$=registry_getnumberclass();}
     */
 
-MAYBETYPE: ':' TYPE {$$=$2;}
-MAYBETYPE:          {$$=0;}
+MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
+MAYBETYPE:          {PASS12 $$=0;}
 
 /* ----------function calls, delete, constructor calls ------ */
 
@@ -3293,7 +3414,7 @@ E : E '?' E ':' E %prec below_assignment {
 
 E : E "++" { code_t*c = 0;
              classinfo_t*type = $1.t;
-             if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
+             if(is_getlocal($1.c) && (TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t))) {
                  int nr = getlocalnr($1.c);
                  code_free($1.c);$1.c=0;
                  if(TYPE_IS_INT($1.t)) {
@@ -3414,39 +3535,55 @@ E : E '.' '(' E ')' {
 
 
 
-E : E '.' T_IDENTIFIER
-            {$$.c = $1.c;
-             classinfo_t*t = $1.t;
-             char is_static = 0;
-             if(TYPE_IS_CLASS(t) && t->data) {
-                 t = t->data;
-                 is_static = 1;
-             }
-             if(t) {
-                 memberinfo_t*f = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
-                 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 = slotinfo_gettype((slotinfo_t*)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();
-             }
-            }
+E : E '.' T_IDENTIFIER {
+    $$.c = $1.c;
+    classinfo_t*t = $1.t;
+    char is_static = 0;
+    if(TYPE_IS_CLASS(t) && t->data) {
+        t = t->data;
+        is_static = 1;
+    }
+    if(t) {
+        if(t->subtype==0xff) {
+            syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
+        }
+        memberinfo_t*f = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
+        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 = slotinfo_gettype((slotinfo_t*)f);
+        if(!$$.t)
+           $$.c = abc_coerce_a($$.c);
+    } else if($1.c && $1.c->opcode == OPCODE___PUSHPACKAGE__) {
+        string_t*package = $1.c->data[0];
+        char*package2 = concat3(package->str, ".", $3);
+        if(dict_contains(state->import_toplevel_packages, package2)) {
+            $$.c = $1.c;
+            $$.c->data[0] = string_new4(package2);
+            $$.t = 0;
+        } else {
+            slotinfo_t*a = registry_find(package->str, $3);
+            if(!a) 
+                syntaxerror("couldn't resolve %s", package2);
+            $$ = push_class(a);
+        }
+    } 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 {
     PASS1
@@ -3454,12 +3591,16 @@ VAR_READ : T_IDENTIFIER {
        function's variables.
        We consider everything which is not a local variable "unresolved".
        This encompasses class names, members of the surrounding class
-       etc. which *correct* because local variables of the parent function
+       etc. which is *correct* because local variables of the parent function
        would shadow those.
        */
     if(state->method->inner && !find_variable(state, $1)) {
         unknown_variable($1);
     }
+   
+    /* let the compiler know that it might check the current directory/package
+       for this identifier- maybe there's a file $1.as defining $1. */
+    as3_schedule_class_noerror(state->package, $1);
     PASS2
 
     $$.t = 0;
@@ -3522,41 +3663,21 @@ VAR_READ : T_IDENTIFIER {
     
     /* look at actual classes, in the current package and imported */
     if((a = find_class($1))) {
-        if(a->access == ACCESS_PACKAGEINTERNAL &&
-           strcmp(a->package, state->package) &&
-           strcmp(a->package, internal_filename_package)
-           )
-           syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
-                infotypename(a),$1, a->package, state->package);
-
-        if(a->kind != INFOTYPE_CLASS) {
-            MULTINAME(m, a);
-            $$.c = abc_findpropstrict2($$.c, &m);
-            $$.c = abc_getproperty2($$.c, &m);
-            if(a->kind == INFOTYPE_METHOD) {
-                methodinfo_t*f = (methodinfo_t*)a;
-                $$.t = TYPE_FUNCTION(f);
-            } else {
-                varinfo_t*v = (varinfo_t*)a;
-                $$.t = v->type;
-            }
-        } else {
-            classinfo_t*c = (classinfo_t*)a;
-            if(c->slot) {
-                $$.c = abc_getglobalscope($$.c);
-                $$.c = abc_getslot($$.c, c->slot);
-            } else {
-                MULTINAME(m, c);
-                $$.c = abc_getlex2($$.c, &m);
-            }
-            $$.t = TYPE_CLASS(c);
-        }
+        $$ = push_class(a);
+        break;
+    }
+
+    /* look through package prefixes */
+    if(dict_contains(state->import_toplevel_packages, $1)) {
+        $$.c = abc___pushpackage__($$.c, $1);
+        $$.t = 0;
         break;
     }
 
     /* unknown object, let the avm2 resolve it */
     if(1) {
-        as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
+        //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
+        as3_warning("Couldn't resolve '%s', doing late binding", $1);
         state->method->late_binding = 1;
                 
         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
@@ -3584,9 +3705,9 @@ NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_IDENTIFIER {
 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_STRING {
     $$=0;
 }
-USE_NAMESPACE : "use" PACKAGEANDCLASS {
+USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
     PASS12
-    tokenizer_register_namespace($2->name);
+    tokenizer_register_namespace($3->name);
     $$=0;
 }