  Allow inline construction of anonymous arrays

  This patch allows arrays to be created in-line as anonymous entities. For
  example:
	    my_array = { \
	        1, 2, 3,                # assigns elements [0] to [2] \
	         ["word"] = "val",      # assigns element ["word"] \
	        ,                       # don't assign to [3] \
	        4,                      # assigns element [4] = 4 \
	        [7] = 7, 8,             # assigns elements [7] and [8] \
	        ["sub"] = { "a", "b" }  # assigns an array to element ["sub"] \
	    }
    The anonymous array is available in contexts where a whole array is needed;
    for example:
	    val0 = { [0] = "zero"}[0]
	    my_array += { [val0] = 4 + 5 - 9 }

diff -ur nedit_official nedit_mod
diff -ur nedit_official/source/interpret.c nedit_mod/source/interpret.c
--- nedit_official/source/interpret.c	2004-11-23 15:37:37.000000000 +0100
+++ nedit_mod/source/interpret.c	2006-10-31 20:01:56.515625000 +0100
@@ -126,6 +126,12 @@
 static int arrayIter(void);
 static int inArray(void);
 static int deleteArrayElement(void);
+static int anonArrayOpen(void);
+static int anonArraySkip(void);
+static int anonArrayNextVal(void);
+static int anonArrayIndexVal(void);
+static int anonArrayClose(void);
+static int makeArrayKeyFromArgs(int nArgs, char **keyString, int leaveParams);
 static void freeSymbolTable(Symbol *symTab);
 static int errCheck(const char *s);
 static int execError(const char *s1, const char *s2);
@@ -208,7 +214,10 @@
     assign, callSubroutine, fetchRetVal, branch, branchTrue, branchFalse,
     branchNever, arrayRef, arrayAssign, beginArrayIter, arrayIter, inArray,
     deleteArrayElement, pushArraySymVal,
-    arrayRefAndAssignSetup, pushArgVal, pushArgCount, pushArgArray};
+    arrayRefAndAssignSetup, pushArgVal, pushArgCount, pushArgArray,
+    anonArrayOpen, anonArraySkip, anonArrayNextVal, anonArrayIndexVal,
+    anonArrayClose,
+    };
 
 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
 #define FP_ARG_ARRAY_CACHE_INDEX (-1)
@@ -1293,6 +1302,179 @@
 }
 
 /*
+** create an anonymous array and next index number value (0) on the stack (for
+** array construction expressions)
+**
+** Before: Prog->  [next], ...
+**         Stack-> next, ...
+** After:  Prog->  [next], ...
+**         Stack-> [empty-array, 0], next, ...
+*/
+static int anonArrayOpen(void)
+{
+    DataValue dataVal;
+
+    DISASM_RT(PC-1, 1);
+    STACKDUMP(0, 3);
+
+    /* make an empty array */
+    dataVal.tag = ARRAY_TAG;
+    dataVal.val.arrayPtr = ArrayNew();
+
+    /* push the default next index value first */
+    PUSH_INT(0)
+
+    /* and the empty array */
+    PUSH(dataVal)
+
+    return STAT_OK;
+}
+
+/*
+** cause the auto-incrementing next index number value to increase without
+** actually creating an entry in the anonymous array (for array construction
+** expressions)
+**
+** Before: Prog->  [next], ...
+**         Stack-> [anon-array, next-index], next, ...
+** After:  Prog->  [next], ...
+**         Stack-> [anon-array, next-index+1], next, ...
+*/
+static int anonArraySkip(void)
+{
+    DataValue anonArray;
+    int nextIndex;
+
+    DISASM_RT(PC-1, 1);
+    STACKDUMP(2, 3);
+
+    POP(anonArray)
+    POP_INT(nextIndex)
+
+    /* we need to increment the index for next time */
+    ++nextIndex;
+
+    /* push the default next index value first, then the array */
+    PUSH_INT(nextIndex)
+    PUSH(anonArray)
+
+    return STAT_OK;
+}
+
+/*
+** add an entry to the anonymous array at the stack head, using the numeric
+** index just below that; restack the incremented index and anonymous array
+** (for array construction expressions)
+**
+** Before: Prog->  [next], ...
+**         Stack-> [expr, anon-array, next-index], next, ...
+** After:  Prog->  [next], ...
+**         Stack-> [anon-array, next-index+1], next, ...
+*/
+static int anonArrayNextVal(void)
+{
+    DataValue exprVal, anonArray;
+    int nextIndex;
+    char numString[TYPE_INT_STR_SIZE(int)];
+
+    DISASM_RT(PC-1, 1);
+    STACKDUMP(3, 3);
+
+    POP(exprVal)
+    POP(anonArray)
+    POP_INT(nextIndex)
+
+    sprintf(numString, "%d", nextIndex);
+    if (!ArrayInsert(&anonArray, AllocStringCpy(numString), &exprVal)) {
+        return(execError("array insertion failure", NULL));
+    }
+
+    /* we need to increment the index for next time */
+    ++nextIndex;
+
+    /* push the default next index value first, then the array */
+    PUSH_INT(nextIndex)
+    PUSH(anonArray)
+
+    return STAT_OK;
+}
+
+/*
+**
+** Before: Prog->  [nDim], next, ...
+**         Stack-> [expr, indnDim, ... ind1, anon-array, next-index], next, ...
+** After:  Prog->  nDim, [next], ...
+**         Stack-> [anon-array, new-next-index], next, ...
+*/
+static int anonArrayIndexVal(void)
+{
+    int errNum;
+    char *keyString = NULL;
+    DataValue exprVal, anonArray, intIndex;
+    int nextIndex, index;
+    int nDim;
+
+    nDim = PC->value;
+    PC++;
+
+    DISASM_RT(PC-2, 2);
+    STACKDUMP(nDim+3, 3);
+
+    POP(exprVal)
+
+    /* the next nDim stack entries form the index */
+    errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
+    if (errNum != STAT_OK) {
+        return errNum;
+    }
+
+    POP(anonArray)
+    POP_INT(nextIndex)
+
+    /* if our index is numeric (or can be converted to a number) we must
+       change the next index value */
+    if (nDim == 1 && StringToNum(keyString, &index)) {
+        nextIndex = index + 1;
+    }
+
+    if (!ArrayInsert(&anonArray, keyString, &exprVal)) {
+        return(execError("array insertion failure", NULL));
+    }
+
+    /* push the default next index value first, then the array */
+    PUSH_INT(nextIndex)
+    PUSH(anonArray)
+
+    return STAT_OK;
+}
+
+/*
+** finish building an anonymous array by removing the next index number value
+** from the stack (for array construction expressions)
+**
+** Before: Prog->  [next], ...
+**         Stack-> [anon-array, next-index], next, ...
+** After:  Prog->  [next], ...
+**         Stack-> [anon-array], next, ...
+*/
+static int anonArrayClose(void)
+{
+    DataValue anonArray;
+    DataValue next_index;
+
+    DISASM_RT(PC-1, 1);
+    STACKDUMP(2, 3);
+
+    /* remove top two elements */
+    POP(anonArray)
+    POP(next_index)
+    /* put back the array content */
+    PUSH(anonArray)
+
+    return STAT_OK;
+}
+
+/*
 ** assign top value to next symbol
 **
 ** Before: Prog->  [symbol], next, ...
@@ -2915,7 +3097,12 @@
         "ARRAY_REF_ASSIGN_SETUP",       /* arrayRefAndAssignSetup */
         "PUSH_ARG",                     /* $arg[expr] */
         "PUSH_ARG_COUNT",               /* $arg[] */
-        "PUSH_ARG_ARRAY"                /* $arg */
+        "PUSH_ARG_ARRAY",               /* $arg */
+        "ARRAY_OPEN",                   /* anonArrayOpen: "{...}" */
+        "ARRAY_SKIP",                   /* anonArraySkip: "{ , ...}" */
+        "ARRAY_NEXT_VAL",               /* anonArrayNextVal: "{ expr }" */
+        "ARRAY_INDEX_VAL",              /* anonArrayIndexVal: "{ [i]=expr }"  */
+        "ARRAY_CLOSE",                  /* anonArrayClose: "{...}" */
     };
     int i, j;
     
diff -ur nedit_official/source/interpret.h nedit_mod/source/interpret.h
--- nedit_official/source/interpret.h	2004-11-09 22:58:44.000000000 +0100
+++ nedit_mod/source/interpret.h	2006-10-31 19:32:34.593750000 +0100
@@ -40,7 +40,7 @@
 
 enum symTypes {CONST_SYM, GLOBAL_SYM, LOCAL_SYM, ARG_SYM, PROC_VALUE_SYM,
     	C_FUNCTION_SYM, MACRO_FUNCTION_SYM, ACTION_ROUTINE_SYM};
-#define N_OPS 43
+
 enum operations {OP_RETURN_NO_VAL, OP_RETURN, OP_PUSH_SYM, OP_DUP, OP_ADD,
     OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_NEGATE, OP_INCR, OP_DECR, OP_GT, OP_LT,
     OP_GE, OP_LE, OP_EQ, OP_NE, OP_BIT_AND, OP_BIT_OR, OP_AND, OP_OR, OP_NOT,
@@ -48,7 +48,10 @@
     OP_BRANCH_TRUE, OP_BRANCH_FALSE, OP_BRANCH_NEVER, OP_ARRAY_REF,
     OP_ARRAY_ASSIGN, OP_BEGIN_ARRAY_ITER, OP_ARRAY_ITER, OP_IN_ARRAY,
     OP_ARRAY_DELETE, OP_PUSH_ARRAY_SYM, OP_ARRAY_REF_ASSIGN_SETUP, OP_PUSH_ARG,
-    OP_PUSH_ARG_COUNT, OP_PUSH_ARG_ARRAY};
+    OP_PUSH_ARG_COUNT, OP_PUSH_ARG_ARRAY,
+    OP_ANONARRAY_OPEN, OP_ANONARRAY_SKIP, OP_ANONARRAY_NEXT_VAL,
+    OP_ANONARRAY_INDEX_VAL, OP_ANONARRAY_CLOSE,
+    N_OPS};
 
 enum typeTags {NO_TAG, INT_TAG, STRING_TAG, ARRAY_TAG};
 
diff -ur nedit_official/source/parse.y nedit_mod/source/parse.y
--- nedit_official/source/parse.y	2005-02-16 04:44:16.000000000 +0100
+++ nedit_mod/source/parse.y	2006-10-31 19:51:46.125000000 +0100
@@ -306,6 +306,36 @@
                 $$ = GetPC();
             }
             ;
+arrconstr0: '{' {
+                /* create an empty array into which to add things */
+                ADD_OP(OP_ANONARRAY_OPEN);
+            }
+            ;
+arrconstr:  arrconstr0 arrlistopt '}' {
+                /* we're done: the array is complete */
+                ADD_OP(OP_ANONARRAY_CLOSE);
+            }
+            ;
+arrlistopt:   /* nothing */
+            | arrlist
+            ;
+arrlist:                  arrentry
+            | arrlist ',' arrentry
+            | arrlist ',' {
+                /* a comma will skip an index value */
+                ADD_OP(OP_ANONARRAY_SKIP);
+            }
+            ;
+arrentry:     expr {
+                /* make a suitable index >= 0 and add expr there */
+                ADD_OP(OP_ANONARRAY_NEXT_VAL);
+            }
+            | '[' arglist ']' '=' expr {
+                /* build the index from arglistopt and add expr there */
+                ADD_OP(OP_ANONARRAY_INDEX_VAL);
+                ADD_IMMED($2);
+            }
+            ;
 numexpr:    NUMBER {
                 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
             }
@@ -406,6 +436,7 @@
             | numexpr IN numexpr {
                 ADD_OP(OP_IN_ARRAY);
             }
+            | arrconstr
             ;
 while:  WHILE {
             $$ = GetPC(); StartLoopAddrList();
