bring back the 'key = val' syntax in the array-for loop
[nedit-bw.git] / multi-dim-key-iterator-arr.patch
blob11394249092a87fbdf0e619a8db3e3654d17a60c
1 ---
3 doc/help.etx | 8 +
4 source/interpret.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
5 source/interpret.h | 1
6 source/parse.y | 35 +++++++
7 4 files changed, 281 insertions(+), 1 deletion(-)
9 diff --quilt old/source/interpret.c new/source/interpret.c
10 --- old/source/interpret.c
11 +++ new/source/interpret.c
12 @@ -157,10 +157,13 @@ static int arrayEntryCompare(rbTreeNode
13 static void arrayDisposeNode(rbTreeNode *src);
14 static SparseArrayEntry *allocateSparseArrayEntry(void);
15 static int typeOfIn(void);
16 static int typeOfOut(void);
17 static int arrayMultiIter(void);
18 +static int beginArrayMultiIterArray(void);
19 +static int arrayMultiIterArray(void);
20 +static int pop(void);
22 /* is the intepreter in the special typeof() mode? */
23 static int inTypeOfMode;
25 static const char *tagToStr(enum typeTags tag);
26 @@ -247,10 +250,11 @@ static int (*OpFns[N_OPS])() = {returnNo
27 callSubroutineStackedN,
28 unpackArrayToArgs,
29 typeOfIn, typeOfOut,
30 arrayIndex,
31 arrayMultiIter,
32 + beginArrayMultiIterArray, arrayMultiIterArray, pop,
35 /* Stack-> symN-sym0(FP), nArgs, oldFP, retPC, argArray, argN-arg1, next, ... */
36 #define FP_ARG_COUNT_INDEX (-1)
37 #define FP_FUNCTION_NAME (-2) /* !! */
38 @@ -3667,10 +3671,217 @@ static int arrayMultiIter(void)
40 return(STAT_OK);
44 +** Before: Prog-> [iter], ARRAY_MULTI_ITER_ARRAY, withVal, iterVarKeyArray(, iterVarVal), iter, endLoopBranch, next, ...
45 +** TheStack-> [arrayVal], nDims, next, ...
46 +** After: Prog-> iter, [ARRAY_MULTI_ITER_ARRAY], withVal, iterVarKeyArray(, iterVarVal), iter, endLoopBranch, next, ...
47 +** TheStack-> [nDims], next, ...
48 +*/
49 +static int beginArrayMultiIterArray(void)
51 + Symbol *iterator;
52 + DataValue *iteratorValPtr;
53 + DataValue arrayVal;
54 + int nDims;
56 + DISASM_RT(PC-1, 2);
57 + STACKDUMP(2, 3);
59 + iterator = PC->sym;
60 + PC++;
62 + POP(arrayVal);
63 + PEEK_INT(nDims, 0);
65 + if (iterator->type == LOCAL_SYM) {
66 + iteratorValPtr = &FP_GET_SYM_VAL(FrameP, iterator);
67 + }
68 + else {
69 + return(execError("bad temporary iterator: %s", iterator->name));
70 + }
72 + if (nDims < 1) {
73 + return(execError("bad multi dimension", NULL));
74 + }
76 + iteratorValPtr->tag = INT_TAG;
77 + if (arrayVal.tag != ARRAY_TAG) {
78 + return(execError("can't iterate non-array", NULL));
79 + }
81 + iteratorValPtr->val.arrayPtr = arrayIterateFirst(&arrayVal);
83 + return(STAT_OK);
86 +static Boolean splitKeyArr(const char *key, DataValue *keyArr)
88 + int nDims = 0;
89 + size_t seplen = strlen(ARRAY_DIM_SEP);
90 + size_t keylen;
91 + const char *sep = key;
92 + const char *nextsep = key;
93 + DataValue keyVal;
95 + do {
96 + nextsep = strstr(sep, ARRAY_DIM_SEP);
97 + if (nextsep) {
98 + keylen = nextsep - sep;
99 + } else {
100 + keylen = strlen(sep);
103 + keyVal.tag = STRING_TAG;
104 + if (!AllocNStringNCpy(&keyVal.val.str, sep, keylen)) {
105 + return False;
108 + if (!ArrayInsert(keyArr, AllocStringOfNumber(nDims), &keyVal)) {
109 + return False;
112 + nDims++;
113 + sep = nextsep;
114 + if (sep)
115 + sep += seplen;
116 + } while (sep);
118 + return True;
123 +** Before: Prog-> iter, ARRAY_MULTI_ITER_ARRAY, [withVal], iterVarKeyArray, (, iterVarVal), iter, endLoopBranch, next, ...
124 +** TheStack-> [nDims], next, ...
125 +** After: Prog-> iter, ARRAY_MULTI_ITER_ARRAY, withVal, iterVarKeyArray, (, iterVarVal), iter, endLoopBranch, [next], ...
126 +** TheStack-> [nDims], next, ... (unchanged)
128 +static int arrayMultiIterArray(void)
130 + Symbol *iterator;
131 + Symbol *itemArrKey;
132 + Symbol *itemVal;
133 + DataValue *iteratorValPtr;
134 + DataValue *itemVarArrKeyPtr;
135 + DataValue *itemVarValPtr;
136 + SparseArrayEntry *thisEntry;
137 + Inst *branchAddr;
138 + int withVal;
139 + int nDims, d;
140 + Boolean keyFound = False;
142 + DISASM_RT(PC-1, 4);
143 + STACKDUMP(1, 4);
145 + withVal = PC->value;
146 + PC++;
148 + PEEK_INT(nDims, 0);
150 + itemArrKey = PC->sym;
151 + PC++;
153 + if (withVal) {
154 + itemVal = PC->sym;
155 + PC++;
158 + iterator = PC->sym;
159 + PC++;
160 + branchAddr = PC + PC->value;
161 + PC++;
163 + if (itemArrKey->type == LOCAL_SYM) {
164 + itemVarArrKeyPtr = &FP_GET_SYM_VAL(FrameP, itemArrKey);
166 + else if (itemArrKey->type == GLOBAL_SYM) {
167 + itemVarArrKeyPtr = &(itemArrKey->value);
169 + else {
170 + return(execError("can't assign to: %s", itemArrKey->name));
172 + itemVarArrKeyPtr->tag = ARRAY_TAG;
173 + itemVarArrKeyPtr->val.arrayPtr = NULL;
175 + if (withVal) {
176 + if (itemVal->type == LOCAL_SYM) {
177 + itemVarValPtr = &FP_GET_SYM_VAL(FrameP, itemVal);
179 + else if (itemVal->type == GLOBAL_SYM) {
180 + itemVarValPtr = &(itemVal->value);
182 + else {
183 + return(execError("can't assign to: %s", itemVal->name));
185 + itemVarValPtr->tag = NO_TAG;
188 + if (iterator->type == LOCAL_SYM) {
189 + iteratorValPtr = &FP_GET_SYM_VAL(FrameP, iterator);
191 + else {
192 + return(execError("bad temporary iterator: %s", iterator->name));
195 + thisEntry = iteratorValPtr->val.arrayPtr;
196 + while (thisEntry && thisEntry->nodePtrs.color != -1) {
197 + /* check if this is a nDims key */
198 + int thisDim = countDim(thisEntry->key);
200 + if (nDims != thisDim) {
201 + /* try next */
202 + thisEntry = arrayIterateNext(thisEntry);
203 + continue;
206 + keyFound = True;
208 + /* set keys */
209 + if (!splitKeyArr(thisEntry->key, itemVarArrKeyPtr)) {
210 + return(execError("can't split key: %s", thisEntry->key));
213 + if (withVal) {
214 + /* set value */
215 + *itemVarValPtr = thisEntry->value;
218 + /* advance iterator */
219 + thisEntry = arrayIterateNext(thisEntry);
220 + break;
222 + iteratorValPtr->val.arrayPtr = thisEntry;
224 + if (!keyFound && (!thisEntry || thisEntry->nodePtrs.color == -1)) {
225 + PC = branchAddr;
228 + return(STAT_OK);
233 +** Before: Prog-> next, ...
234 +** TheStack-> [val], next, ...
235 +** After: Prog-> next, ... (unchanged)
236 +** TheStack-> [next], ...
238 +static int pop(void)
240 + DataValue val;
242 + DISASM_RT(PC-1, 1);
243 + STACKDUMP(1, 4);
245 + POP(val);
247 + return STAT_OK;
251 ** determine if a key or keys exists in an array
252 ** if the left argument is a string or integer a single check is performed
253 ** if the key exists, 1 is pushed onto the stack, otherwise 0
254 ** if the left argument is an array 1 is pushed onto the stack if every key
255 ** in the left array exists in the right array, otherwise 0
256 @@ -4129,10 +4340,13 @@ static void disasmInternal(Inst *inst, i
257 "UNPACKTOARGS", /* unpackArrayToArgs */
258 "TYPEOF_IN", /* typeOfIn */
259 "TYPEOF_OUT", /* typeOfOut */
260 "ARRAY_INDEX", /* arrayIndex */
261 "ARRAY_MULTI_ITER", /* arrayMultiIter */
262 + "BEGIN_ARRAY_MULTI_ITER_ARRAY", /* beginArrayMultiIterArray */
263 + "ARRAY_MULTI_ITER_ARRAY", /* arrayMultiIterArray */
264 + "POP", /* pop */
266 int i, j;
267 static size_t opLen;
269 if (!opLen) {
270 @@ -4181,11 +4395,12 @@ static void disasmInternal(Inst *inst, i
272 else if (j == OP_SUBR_CALL_STACKED_N) {
273 printd(" %s args[] (?)", inst[i+1].sym->name);
274 ++i;
276 - else if (j == OP_BEGIN_ARRAY_ITER) {
277 + else if (j == OP_BEGIN_ARRAY_ITER ||
278 + j == OP_BEGIN_ARRAY_MULTI_ITER_ARRAY) {
279 printd(" %s in", inst[i+1].sym->name);
280 ++i;
282 else if (j == OP_ARRAY_ITER) {
283 if (!inst[i+1].value) {
284 @@ -4238,10 +4453,31 @@ static void disasmInternal(Inst *inst, i
285 inst[i+nDim+5].value,
286 &inst[i+nDim+5] + inst[i+nDim+5].value);
287 i += nDim+5;
290 + else if (j == OP_ARRAY_MULTI_ITER_ARRAY) {
291 + if (!inst[i+1].value) {
292 + /* without val */
293 + printd(" %s[] = %s++ end-loop=(%+d) %8p",
294 + inst[i+2].sym->name,
295 + inst[i+3].sym->name,
296 + inst[i+4].value,
297 + &inst[i+4] + inst[i+4].value);
298 + i += 4;
300 + else {
301 + /* with val */
302 + printd(" %s[]=%s = %s++ end-loop=(%+d) %8p",
303 + inst[i+2].sym->name,
304 + inst[i+3].sym->name,
305 + inst[i+4].sym->name,
306 + inst[i+5].value,
307 + &inst[i+5] + inst[i+5].value);
308 + i += 5;
311 else if (j == OP_ARRAY_REF ||
312 j == OP_ARRAY_DELETE ||
313 j == OP_ARRAY_ASSIGN ||
314 j == OP_ANONARRAY_INDEX_VAL ||
315 j == OP_NAMED_ARG1 ||
316 diff --quilt old/source/interpret.h new/source/interpret.h
317 --- old/source/interpret.h
318 +++ new/source/interpret.h
319 @@ -55,10 +55,11 @@ enum operations {OP_RETURN_NO_VAL, OP_RE
320 OP_SUBR_CALL_STACKED_N,
321 OP_UNPACKTOARGS,
322 OP_TYPEOF_IN, OP_TYPEOF_OUT,
323 OP_ARRAY_INDEX,
324 OP_ARRAY_MULTI_ITER,
325 + OP_BEGIN_ARRAY_MULTI_ITER_ARRAY, OP_ARRAY_MULTI_ITER_ARRAY, OP_POP,
326 N_OPS};
328 enum typeTags {NO_TAG, INT_TAG, STRING_TAG, ARRAY_TAG};
330 enum execReturnCodes {MACRO_TIME_LIMIT, MACRO_PREEMPT, MACRO_DONE, MACRO_ERROR};
331 diff --quilt old/source/parse.y new/source/parse.y
332 --- old/source/parse.y
333 +++ new/source/parse.y
334 @@ -269,10 +269,45 @@ stmt: ';' blank
335 ADD_OP(OP_BRANCH);
336 ADD_BR_OFF($11+2);
337 SET_BR_OFF($11+7+$5.nSyms, GetPC());
338 FillLoopAddrs(GetPC(), $11+2);
340 + | for '(' blank SYMBOL '[' numexpr ']' IN blank arrayexpr blank ')' {
341 + Symbol *iterSym = InstallIteratorSymbol();
342 + ADD_OP(OP_BEGIN_ARRAY_MULTI_ITER_ARRAY);
343 + ADD_SYM(iterSym);
344 + ADD_OP(OP_ARRAY_MULTI_ITER_ARRAY);
345 + ADD_IMMED(0); /* without val symbol */
346 + ADD_SYM($4);
347 + ADD_SYM(iterSym);
348 + ADD_BR_OFF(0);
350 + blank block {
351 + ADD_OP(OP_BRANCH);
352 + ADD_BR_OFF($10+2);
353 + SET_BR_OFF($10+6, GetPC());
354 + FillLoopAddrs(GetPC(), $10+2);
355 + ADD_OP(OP_POP);
357 + | for '(' blank SYMBOL '[' numexpr ']' KEYVAL SYMBOL IN blank arrayexpr blank ')' {
358 + Symbol *iterSym = InstallIteratorSymbol();
359 + ADD_OP(OP_BEGIN_ARRAY_MULTI_ITER_ARRAY);
360 + ADD_SYM(iterSym);
361 + ADD_OP(OP_ARRAY_MULTI_ITER_ARRAY);
362 + ADD_IMMED(1); /* with val symbol */
363 + ADD_SYM($4);
364 + ADD_SYM($9);
365 + ADD_SYM(iterSym);
366 + ADD_BR_OFF(0);
368 + blank block {
369 + ADD_OP(OP_BRANCH);
370 + ADD_BR_OFF($12+2);
371 + SET_BR_OFF($12+7, GetPC());
372 + FillLoopAddrs(GetPC(), $12+2);
373 + ADD_OP(OP_POP);
375 | BREAK stmtend blank {
376 ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
377 if (AddBreakAddr(GetPC()-1)) {
378 yyerror("break outside loop"); YYERROR;
380 diff --quilt old/doc/help.etx new/doc/help.etx
381 --- old/doc/help.etx
382 +++ new/doc/help.etx
383 @@ -2349,10 +2349,18 @@ Macro Language
384 Also with the associated value for the multi-dimensional key:
386 for ([dim1Key, ..., dimNKey] = theVal in myArray)
387 <body>
389 + As a last iterator variant, you can use this syntax:
391 + for (keyArray[nDim] in myArray)
392 + <body>
394 + where this loop iterates over all keys with dimension nDim and puts the
395 + dimension keys into the array keyArray (starting with 0).
397 Note that if an array contains a value that is itself an array, you can
398 apply the index operator more than once. For example
400 subarray["a"] = "value"
401 mainarray[1] = subarray