Index: chuck_emit.cpp
===================================================================
--- chuck_emit.cpp	(revision 232)
+++ chuck_emit.cpp	(working copy)
@@ -58,6 +58,7 @@
 t_CKBOOL emit_engine_emit_continue( Chuck_Emitter * emit, a_Stmt_Continue cont );
 t_CKBOOL emit_engine_emit_return( Chuck_Emitter * emit, a_Stmt_Return stmt );
 t_CKBOOL emit_engine_emit_switch( Chuck_Emitter * emit, a_Stmt_Switch stmt );
+t_CKBOOL emit_engine_emit_exp_single( Chuck_Emitter * emit, a_Exp exp, t_CKBOOL doAddRef = FALSE );
 t_CKBOOL emit_engine_emit_exp( Chuck_Emitter * emit, a_Exp exp, t_CKBOOL doAddRef = FALSE );
 t_CKBOOL emit_engine_emit_exp_binary( Chuck_Emitter * emit, a_Exp_Binary binary );
 t_CKBOOL emit_engine_emit_op( Chuck_Emitter * emit, ae_Operator op, a_Exp lhs, a_Exp rhs, a_Exp_Binary binary );
@@ -1254,102 +1255,112 @@
 
 
 //-----------------------------------------------------------------------------
-// name: emit_engine_emit_exp()
+// name: emit_engine_emit_exp_single()
 // desc: (doAddRef added 1.3.0.0 -- typically this is set to TRUE for function
 //        calls so that pointers on the reg is accounted for;  this is important
 //        in case the object is released/reclaimed before the value is used;
 //        on particular case is when sporking with a local object as argument)
 //-----------------------------------------------------------------------------
-t_CKBOOL emit_engine_emit_exp( Chuck_Emitter * emit, a_Exp exp, t_CKBOOL doAddRef )
+t_CKBOOL emit_engine_emit_exp_single( Chuck_Emitter * emit, a_Exp exp, t_CKBOOL doAddRef )
 {
-    // for now...
-    // assert( exp->next == NULL );
-
-    // loop over 
-    while( exp )
+    switch( exp->s_type )
     {
-        switch( exp->s_type )
-        {
-        case ae_exp_binary:
-            if( !emit_engine_emit_exp_binary( emit, &exp->binary ) )
-                return FALSE;
-            break;
+    case ae_exp_binary:
+        if( !emit_engine_emit_exp_binary( emit, &exp->binary ) )
+            return FALSE;
+        break;
 
-        case ae_exp_unary:
-            if( !emit_engine_emit_exp_unary( emit, &exp->unary ) )
-                return FALSE;
-            break;
+    case ae_exp_unary:
+        if( !emit_engine_emit_exp_unary( emit, &exp->unary ) )
+            return FALSE;
+        break;
 
-        case ae_exp_cast:
-            if( !emit_engine_emit_exp_cast( emit, &exp->cast ) )
-                return FALSE;
-            break;
+    case ae_exp_cast:
+        if( !emit_engine_emit_exp_cast( emit, &exp->cast ) )
+            return FALSE;
+        break;
 
-        case ae_exp_postfix:
-            if( !emit_engine_emit_exp_postfix( emit, &exp->postfix ) )
-                return FALSE;
-            break;
+    case ae_exp_postfix:
+        if( !emit_engine_emit_exp_postfix( emit, &exp->postfix ) )
+            return FALSE;
+        break;
 
-        case ae_exp_dur:
-            if( !emit_engine_emit_exp_dur( emit, &exp->dur ) )
-                return FALSE;
-            break;
+    case ae_exp_dur:
+        if( !emit_engine_emit_exp_dur( emit, &exp->dur ) )
+            return FALSE;
+        break;
 
-        case ae_exp_primary:
-            if( !emit_engine_emit_exp_primary( emit, &exp->primary ) )
-                return FALSE;
-            break;
+    case ae_exp_primary:
+        if( !emit_engine_emit_exp_primary( emit, &exp->primary ) )
+            return FALSE;
+        break;
 
-        case ae_exp_array:
-            if( !emit_engine_emit_exp_array( emit, &exp->array ) )
-                return FALSE;
-            break;
+    case ae_exp_array:
+        if( !emit_engine_emit_exp_array( emit, &exp->array ) )
+            return FALSE;
+        break;
 
-        case ae_exp_func_call:
-            if( !emit_engine_emit_exp_func_call( emit, &exp->func_call ) )
-                return FALSE;
-            break;
+    case ae_exp_func_call:
+        if( !emit_engine_emit_exp_func_call( emit, &exp->func_call ) )
+            return FALSE;
+        break;
 
-        case ae_exp_dot_member:
-            if( !emit_engine_emit_exp_dot_member( emit, &exp->dot_member ) )
-                return FALSE;
-            break;
+    case ae_exp_dot_member:
+        if( !emit_engine_emit_exp_dot_member( emit, &exp->dot_member ) )
+            return FALSE;
+        break;
 
-        case ae_exp_if:
-            if( !emit_engine_emit_exp_if( emit, &exp->exp_if ) )
-                return FALSE;
-            break;
+    case ae_exp_if:
+        if( !emit_engine_emit_exp_if( emit, &exp->exp_if ) )
+            return FALSE;
+        break;
 
-        case ae_exp_decl:
-            if( !emit_engine_emit_exp_decl( emit, &exp->decl, FALSE ) )
-                return FALSE;
-            break;
+    case ae_exp_decl:
+        if( !emit_engine_emit_exp_decl( emit, &exp->decl, FALSE ) )
+            return FALSE;
+        break;
 
-        //case ae_exp_namespace:
-        //    if( !emit_engine_emit_exp_namespace( emit, &exp->name_space ) )
-        //        return FALSE;
-        //    break;
+    //case ae_exp_namespace:
+    //    if( !emit_engine_emit_exp_namespace( emit, &exp->name_space ) )
+    //        return FALSE;
+    //    break;
 
-        default:
-            EM_error2( exp->linepos, 
-                 "(emit): internal error: unhandled expression type '%i'...",
-                 exp->s_type );
+    default:
+        EM_error2( exp->linepos, 
+             "(emit): internal error: unhandled expression type '%i'...",
+             exp->s_type );
+        return FALSE;
+    }
+
+    // implicit cast
+    if( exp->cast_to != NULL )
+        if( !emit_engine_emit_cast( emit, exp->cast_to, exp->type ) )
             return FALSE;
-        }
+    
+    // check if we need to handle ref (added 1.3.0.0)
+    // (NOTE: cast shouldn't matter since pointer width should remain constant)
+    if( doAddRef && isobj( exp->type ) )
+    {
+        // add ref in place on the stack
+        emit->append( new Chuck_Instr_Reg_AddRef_Object3() );
+    }
 
-        // implicit cast
-        if( exp->cast_to != NULL )
-            if( !emit_engine_emit_cast( emit, exp->cast_to, exp->type ) )
-                return FALSE;
-        
-        // check if we need to handle ref (added 1.3.0.0)
-        // (NOTE: cast shouldn't matter since pointer width should remain constant)
-        if( doAddRef && isobj( exp->type ) )
-        {
-            // add ref in place on the stack
-            emit->append( new Chuck_Instr_Reg_AddRef_Object3() );
-        }
+    return TRUE;
+}
 
+//-----------------------------------------------------------------------------
+// name: emit_engine_emit_exp()
+// desc: ...
+t_CKBOOL emit_engine_emit_exp( Chuck_Emitter * emit, a_Exp exp, t_CKBOOL doAddRef )
+{
+    // for now...
+    // assert( exp->next == NULL );
+
+    // loop over 
+    while( exp )
+    {
+        if( !emit_engine_emit_exp_single( emit, exp, doAddRef ) )
+            return FALSE;
         exp = exp->next;
     }
 
@@ -2996,7 +3007,6 @@
     a_Array_Sub sub = NULL;
     a_Exp exp = NULL;
     t_CKBOOL is_var = FALSE;
-    t_CKBOOL is_str = FALSE;
 
     // get the type
     type = array->self->type;
@@ -3004,10 +3014,8 @@
     base_type = array->base->type;
     // emit as addr?
     is_var = array->self->emit_var;
-    // get the dimension
-    depth = base_type->array_depth - type->array_depth;
     // make sure
-    if( depth == 0 )
+    if( base_type->array_depth - type->array_depth == 0 )
     {
         EM_error2( array->linepos,
             "(emit): internal error: array with 0 depth..." );
@@ -3034,14 +3042,6 @@
     if( !emit_engine_emit_exp( emit, array->base ) )
         return FALSE;
 
-    // emit the exp list
-    if( !emit_engine_emit_exp( emit, exp ) )
-        return FALSE;
-
-    // find out first element
-    if( isa( exp->type, &t_string ) )
-        is_str = TRUE;
-
     // make sure
     // ISSUE: 64-bit (fixed 1.3.1.0)
     if( type->size != sz_INT && type->size != sz_FLOAT && type->size != sz_COMPLEX ) 
@@ -3051,20 +3051,37 @@
         return FALSE;
     }
 
-    // check the depth
-    if( depth == 1 )
+    // generate most efficient series of expression and array access instructions
+    while( exp != NULL )
     {
-        // emit the array access (1.3.1.0: use getkindof instead of type->size)
-        if( is_str )
-            emit->append( new Chuck_Instr_Array_Map_Access( getkindof(type), is_var ) );
+        t_CKBOOL want_var = exp->next == NULL ? is_var : FALSE;
+
+        // emit the exp
+        if( !emit_engine_emit_exp_single( emit, exp ) )
+            return FALSE;
+
+        if( isa( exp->type, &t_string ) )
+        {
+            // emit the array access (1.3.1.0: use getkindof instead of type->size)
+            emit->append( new Chuck_Instr_Array_Map_Access( getkindof(type), want_var ) );
+        }
         else
-            emit->append( new Chuck_Instr_Array_Access( getkindof(type), is_var ) );
+        {
+            depth++;
+
+            if( exp->next == NULL || isa( exp->next->type, &t_string ) ) {
+                // emit the array access (1.3.1.0: use getkindof instead of type->size)
+                if( depth == 1 )
+                    emit->append( new Chuck_Instr_Array_Access( getkindof(type), want_var ) );
+                else
+                    emit->append( new Chuck_Instr_Array_Access_Multi( depth, getkindof(type), want_var ) );
+
+                depth = 0;
+            }
+        }
+
+        exp = exp->next;
     }
-    else
-    {
-        // emit the multi array access (1.3.1.0: use getkindof instead of type->size)
-        emit->append( new Chuck_Instr_Array_Access_Multi( depth, getkindof(type), is_var ) );
-    }
 
     // TODO: variable?
 
