let all function types return NO_TAG
[nedit-bw.git] / multi-dim-key-iterator.patch
blob1379700588505ff0095d43001ac0bb4eb6c9c8cd
1 ---
3 source/interpret.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 source/interpret.h | 1
5 source/parse.y | 95 ++++++++++++++++++++++
6 3 files changed, 322 insertions(+)
8 diff --quilt old/source/interpret.c new/source/interpret.c
9 --- old/source/interpret.c
10 +++ new/source/interpret.c
11 @@ -156,10 +156,11 @@ static int arrayEntryCopyToNode(rbTreeNo
12 static int arrayEntryCompare(rbTreeNode *left, rbTreeNode *right);
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);
19 /* is the intepreter in the special typeof() mode? */
20 static int inTypeOfMode;
22 /*#define DEBUG_ASSEMBLY*/
23 @@ -243,10 +244,11 @@ static int (*OpFns[N_OPS])() = {returnNo
24 anonArrayClose, namedArg1, namedArgN, swapTop2,
25 callSubroutineStackedN,
26 unpackArrayToArgs,
27 typeOfIn, typeOfOut,
28 arrayIndex,
29 + arrayMultiIter,
32 /* Stack-> symN-sym0(FP), nArgs, oldFP, retPC, argArray, argN-arg1, next, ... */
33 #define FP_ARG_COUNT_INDEX (-1)
34 #define FP_FUNCTION_NAME (-2) /* !! */
35 @@ -3399,10 +3401,201 @@ static int arrayIter(void)
36 PC = branchAddr;
38 return(STAT_OK);
41 +static int countDim(const char *key)
43 + int nDims = 0;
44 + size_t seplen = strlen(ARRAY_DIM_SEP);
45 + const char *sep = key;
47 + do {
48 + nDims++;
49 + sep = strstr(sep, ARRAY_DIM_SEP);
50 + if (sep)
51 + sep += seplen;
52 + } while (sep);
54 + return nDims;
57 +static Boolean splitKey(const char *key, DataValue **keys)
59 + int nDims = 0;
60 + size_t seplen = strlen(ARRAY_DIM_SEP);
61 + size_t keylen;
62 + const char *sep = key;
63 + const char *nextsep = key;
65 + do {
66 + nextsep = strstr(sep, ARRAY_DIM_SEP);
67 + if (nextsep) {
68 + keylen = nextsep - sep;
69 + } else {
70 + keylen = strlen(sep);
71 + }
73 + keys[nDims]->tag = STRING_TAG;
74 + if (!AllocNStringNCpy(&keys[nDims]->val.str, sep, keylen)) {
75 + return False;
76 + }
78 + nDims++;
79 + sep = nextsep;
80 + if (sep)
81 + sep += seplen;
82 + } while (sep);
84 + return True;
87 +/*
88 +** copy key and value to symbols if node is still valid, marked bad by a color
89 +** of -1 then move iterator to next node
90 +** this allows iterators to progress even if you delete any node in the array
91 +** except the item just after the current key
92 +**
93 +** Before: Prog-> iter, ARRAY_MULTI_ITER, [withVal], nDims, iterVarKey1, ..., iterVarKeynDims, (, iterVarVal), iter, endLoopBranch, next, ...
94 +** TheStack-> [next], ...
95 +** After: Prog-> iter, ARRAY_MULTI_ITER, withVal, nDims, iterVarKey1, ..., iterVarKeynDims, (, iterVarVal), iter, endLoopBranch, [next], ...
96 +** TheStack-> [next], ... (unchanged)
97 +** Where:
98 +** iter is a symbol which gives the position of the iterator value in
99 +** the stack frame (set up by OP_BEGIN_ARRAY_ITER); that value refers
100 +** to the array and a position within it
101 +** iterVarKey1, ..., iterVarKeynDim is the programmer-visible symbol which
102 +** will take the current key value
103 +** iterVarVal is the programmer-visible symbol which will take the current
104 +** entry value (only if withVal is true)
105 +** endLoopBranch is the instruction offset to the instruction following the
106 +** loop (measured from itself)
107 +** arrayVal is the data value holding the array in question
108 +** The return-to-start-of-loop branch (at the end of the loop) should address
109 +** the ARRAY_MULTI_ITER instruction
111 +static int arrayMultiIter(void)
113 + Symbol *iterator;
114 + Symbol **itemKeys;
115 + Symbol *itemVal;
116 + DataValue *iteratorValPtr;
117 + DataValue **itemVarKeyPtrs;
118 + DataValue *itemVarValPtr;
119 + SparseArrayEntry *thisEntry;
120 + Inst *branchAddr;
121 + int withVal;
122 + int nDims, d;
123 + Boolean keyFound = False;
125 + DISASM_RT(PC-1, 4);
126 + STACKDUMP(0, 4);
128 + withVal = PC->value;
129 + PC++;
130 + nDims = PC->value;
131 + PC++;
133 + itemKeys = malloc(nDims * sizeof(*itemKeys));
134 + itemVarKeyPtrs = malloc(nDims * sizeof(*itemVarKeyPtrs));
136 + for (d = 0; d < nDims; d++) {
137 + itemKeys[d] = PC->sym;
138 + PC++;
141 + if (withVal) {
142 + itemVal = PC->sym;
143 + PC++;
146 + iterator = PC->sym;
147 + PC++;
148 + branchAddr = PC + PC->value;
149 + PC++;
151 + for (d = 0; d < nDims; d++) {
152 + if (itemKeys[d]->type == LOCAL_SYM) {
153 + itemVarKeyPtrs[d] = &FP_GET_SYM_VAL(FrameP, itemKeys[d]);
155 + else if (itemKeys[d]->type == GLOBAL_SYM) {
156 + itemVarKeyPtrs[d] = &(itemKeys[d]->value);
158 + else {
159 + const char *name = itemKeys[d]->name;
160 + free(itemKeys);
161 + free(itemVarKeyPtrs);
162 + return(execError("can't assign to: %s", name));
164 + itemVarKeyPtrs[d]->tag = NO_TAG;
167 + if (withVal) {
168 + if (itemVal->type == LOCAL_SYM) {
169 + itemVarValPtr = &FP_GET_SYM_VAL(FrameP, itemVal);
171 + else if (itemVal->type == GLOBAL_SYM) {
172 + itemVarValPtr = &(itemVal->value);
174 + else {
175 + free(itemKeys);
176 + free(itemVarKeyPtrs);
177 + return(execError("can't assign to: %s", itemVal->name));
179 + itemVarValPtr->tag = NO_TAG;
182 + if (iterator->type == LOCAL_SYM) {
183 + iteratorValPtr = &FP_GET_SYM_VAL(FrameP, iterator);
185 + else {
186 + free(itemKeys);
187 + free(itemVarKeyPtrs);
188 + return(execError("bad temporary iterator: %s", iterator->name));
191 + thisEntry = iteratorValPtr->val.arrayPtr;
192 + while (thisEntry && thisEntry->nodePtrs.color != -1) {
193 + /* check if this is a nDims key */
194 + int thisDim = countDim(thisEntry->key);
196 + if (nDims != thisDim) {
197 + /* try next */
198 + thisEntry = arrayIterateNext(thisEntry);
199 + continue;
202 + keyFound = True;
204 + /* set keys */
205 + if (!splitKey(thisEntry->key, itemVarKeyPtrs)) {
206 + free(itemKeys);
207 + free(itemVarKeyPtrs);
208 + return(execError("can't split key: %s", thisEntry->key));
211 + if (withVal) {
212 + /* set value */
213 + *itemVarValPtr = thisEntry->value;
216 + /* advance iterator */
217 + thisEntry = arrayIterateNext(thisEntry);
218 + break;
220 + iteratorValPtr->val.arrayPtr = thisEntry;
222 + if (!keyFound && (!thisEntry || thisEntry->nodePtrs.color == -1)) {
223 + PC = branchAddr;
226 + free(itemKeys);
227 + free(itemVarKeyPtrs);
229 + return(STAT_OK);
233 ** determine if a key or keys exists in an array
234 ** if the left argument is a string or integer a single check is performed
235 ** if the key exists, 1 is pushed onto the stack, otherwise 0
236 ** if the left argument is an array 1 is pushed onto the stack if every key
237 @@ -3846,10 +4039,11 @@ static void disasmInternal(Inst *inst, i
238 "SUBR_CALL_STACKED_N", /* callSubroutineStackedN */
239 "UNPACKTOARGS", /* unpackArrayToArgs */
240 "TYPEOF_IN", /* typeOfIn */
241 "TYPEOF_OUT", /* typeOfOut */
242 "ARRAY_INDEX", /* arrayIndex */
243 + "ARRAY_MULTI_ITER", /* arrayMultiIter */
245 int i, j;
246 static size_t opLen;
248 if (!opLen) {
249 @@ -3923,10 +4117,42 @@ static void disasmInternal(Inst *inst, i
250 inst[i+5].value,
251 &inst[i+5] + inst[i+5].value);
252 i += 5;
255 + else if (j == OP_ARRAY_MULTI_ITER) {
256 + int nDim = inst[i+2].value, d;
257 + if (!inst[i+1].value) {
258 + /* without val */
259 + printd(" [");
260 + for (d = 0; d < nDim; d++) {
261 + printd("%s%s",
262 + d ? "," : "",
263 + inst[i+3+d].sym->name);
265 + printd("] = %s++ end-loop=(%+d) %8p",
266 + inst[i+nDim+3].sym->name,
267 + inst[i+nDim+4].value,
268 + &inst[i+nDim+4] + inst[i+nDim+4].value);
269 + i += nDim+4;
271 + else {
272 + /* with val */
273 + printd(" [");
274 + for (d = 0; d < nDim; d++) {
275 + printd("%s%s",
276 + d ? "," : "",
277 + inst[i+3+d].sym->name);
279 + printd("]=%s = %s++ end-loop=(%+d) %8p",
280 + inst[i+nDim+3].sym->name,
281 + inst[i+nDim+4].sym->name,
282 + inst[i+nDim+5].value,
283 + &inst[i+nDim+5] + inst[i+nDim+5].value);
284 + i += nDim+5;
287 else if (j == OP_ARRAY_REF ||
288 j == OP_ARRAY_DELETE ||
289 j == OP_ARRAY_ASSIGN ||
290 j == OP_ANONARRAY_INDEX_VAL ||
291 j == OP_NAMED_ARG1 ||
292 diff --quilt old/source/interpret.h new/source/interpret.h
293 --- old/source/interpret.h
294 +++ new/source/interpret.h
295 @@ -54,10 +54,11 @@ enum operations {OP_RETURN_NO_VAL, OP_RE
296 OP_NAMED_ARG1, OP_NAMED_ARGN, OP_SWAP_TOP2,
297 OP_SUBR_CALL_STACKED_N,
298 OP_UNPACKTOARGS,
299 OP_TYPEOF_IN, OP_TYPEOF_OUT,
300 OP_ARRAY_INDEX,
301 + OP_ARRAY_MULTI_ITER,
302 N_OPS};
304 enum typeTags {NO_TAG, INT_TAG, STRING_TAG, ARRAY_TAG};
306 enum execReturnCodes {MACRO_TIME_LIMIT, MACRO_PREEMPT, MACRO_DONE, MACRO_ERROR};
307 diff --quilt old/source/parse.y new/source/parse.y
308 --- old/source/parse.y
309 +++ new/source/parse.y
310 @@ -55,13 +55,26 @@ extern Inst **LoopStackPtr; /* to fill
312 static int nextSymIsField = 0;
313 /* set to 1 when we don't want a full symbol, just a name (string) for a
314 field name following a '.' */
316 +#define SYMBLK_SIZE ((64 - sizeof(void *)) / sizeof(void *))
318 +typedef struct SymBlkTag {
319 + Symbol *syms[SYMBLK_SIZE];
320 + struct SymBlkTag *next;
321 +} SymBlk;
323 +typedef struct SymListTag {
324 + SymBlk *head, *tail;
325 + int nSyms;
326 +} SymList;
330 %union {
331 + SymList symlist;
332 Symbol *sym;
333 Inst *inst;
334 int nArgs;
335 enum operations oper;
337 @@ -70,10 +83,11 @@ static int nextSymIsField = 0;
338 %token IF WHILE DO ELSE FOR BREAK CONTINUE RETURN TYPEOF
339 %type <nArgs> arrlist arrentry
340 %type <nArgs> arglistopt arglist catlist fnarglsopt fnarglist fnarg
341 %type <inst> cond comastmts comastmtlst for while do else and or arrayexpr mark
342 %type <sym> evalsym
343 +%type <symlist> symlist
344 %type <oper> operassign incrdecr
345 %token <oper> '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
346 %token <oper> INCR DECR
348 %nonassoc IF_NO_ELSE
349 @@ -176,10 +190,65 @@ stmt: ';' blank
350 ADD_OP(OP_BRANCH);
351 ADD_BR_OFF($9+2);
352 SET_BR_OFF($9+7, GetPC());
353 FillLoopAddrs(GetPC(), $9+2);
355 + | for '(' blank '[' symlist ']' IN blank arrayexpr blank ')' {
356 + Symbol *iterSym = InstallIteratorSymbol();
357 + int i = 0;
358 + ADD_OP(OP_BEGIN_ARRAY_ITER);
359 + ADD_SYM(iterSym);
360 + ADD_OP(OP_ARRAY_MULTI_ITER);
361 + ADD_IMMED(0); /* without val symbol */
362 + ADD_IMMED($5.nSyms);
363 + do {
364 + ADD_SYM($5.head->syms[i % SYMBLK_SIZE]);
365 + i++;
366 + if (i % SYMBLK_SIZE == 0 || i == $5.nSyms) {
367 + SymBlk *nextsymblk = $5.head->next;
368 + free($5.head);
369 + $5.head = nextsymblk;
371 + } while (i < $5.nSyms);
372 + $5.tail = $5.head;
373 + ADD_SYM(iterSym);
374 + ADD_BR_OFF(0);
376 + blank block {
377 + ADD_OP(OP_BRANCH);
378 + ADD_BR_OFF($9+2);
379 + SET_BR_OFF($9+6+$5.nSyms, GetPC());
380 + FillLoopAddrs(GetPC(), $9+2);
382 + | for '(' blank '[' symlist ']' ':' SYMBOL IN blank arrayexpr blank ')' {
383 + Symbol *iterSym = InstallIteratorSymbol();
384 + int i = 0;
385 + ADD_OP(OP_BEGIN_ARRAY_ITER);
386 + ADD_SYM(iterSym);
387 + ADD_OP(OP_ARRAY_MULTI_ITER);
388 + ADD_IMMED(1); /* with val symbol */
389 + ADD_IMMED($5.nSyms);
390 + do {
391 + ADD_SYM($5.head->syms[i % SYMBLK_SIZE]);
392 + i++;
393 + if (i % SYMBLK_SIZE == 0 || i == $5.nSyms) {
394 + SymBlk *nextsymblk = $5.head->next;
395 + free($5.head);
396 + $5.head = nextsymblk;
398 + } while (i < $5.nSyms);
399 + $5.tail = $5.head;
400 + ADD_SYM($8);
401 + ADD_SYM(iterSym);
402 + ADD_BR_OFF(0);
404 + blank block {
405 + ADD_OP(OP_BRANCH);
406 + ADD_BR_OFF($11+2);
407 + SET_BR_OFF($11+7+$5.nSyms, GetPC());
408 + FillLoopAddrs(GetPC(), $11+2);
410 | BREAK stmtend blank {
411 ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
412 if (AddBreakAddr(GetPC()-1)) {
413 yyerror("break outside loop"); YYERROR;
415 @@ -290,10 +359,36 @@ arglistopt: blank { $$ = 0; }
417 arglist: blank expr blank { $$ = 1; }
418 | arglist ',' blank expr blank { $$ = $1 + 1; }
421 +/* SYMBOL list for multi dimension array iterator */
422 +symlist: blank SYMBOL blank {
423 + SymBlk *symblk = malloc(sizeof(*symblk));
424 + symblk->syms[0] = $2;
425 + symblk->next = NULL;
426 + $$.head = $$.tail = symblk;
427 + $$.nSyms = 1;
429 + | symlist ',' blank SYMBOL blank {
430 + /* copy all from $1 to $$, and clear $1 */
431 + $$.head = $1.head;
432 + $$.tail = $1.tail;
433 + $$.nSyms = $1.nSyms;
434 + $1.head = $1.tail = NULL;
435 + /* alloc new SymBlk, if current tail is full */
436 + if ($$.nSyms % SYMBLK_SIZE == 0) {
437 + SymBlk *symblk = malloc(sizeof(*symblk));
438 + symblk->next = NULL;
439 + $$.tail->next = symblk;
440 + $$.tail = symblk;
442 + $$.tail->syms[$$.nSyms % SYMBLK_SIZE] = $4;
443 + $$.nSyms++;
447 /* string concatenation lists */
448 catlist: numexpr %prec CONCAT { $$ = 1; }
449 | catlist numexpr %prec CONCAT { $$ = $1 + 1; }