import parse-define.patch
[nedit-bw.git] / extend-for-key-in-array-syntax.patch
blobd059996e3e7feffb24205bb221221f471f8a4b41
1 ---
3 doc/help.etx | 5 ++
4 source/interpret.c | 102 +++++++++++++++++++++++++++++++++++++----------------
5 source/parse.y | 75 +++++++++++++++++++++++++++++++++++---
6 3 files changed, 147 insertions(+), 35 deletions(-)
8 diff --quilt old/source/interpret.c new/source/interpret.c
9 --- old/source/interpret.c
10 +++ new/source/interpret.c
11 @@ -3339,13 +3339,13 @@ static int arrayRefAndAssignSetup(void)
15 ** setup symbol values for array iteration in interpreter
17 -** Before: Prog-> [iter], ARRAY_ITER, iterVar, iter, endLoopBranch, next, ...
18 +** Before: Prog-> [iter], ARRAY_ITER, withVal, iterVarKey(, iterVarVal), iter, endLoopBranch, next, ...
19 ** TheStack-> [arrayVal], next, ...
20 -** After: Prog-> iter, [ARRAY_ITER], iterVar, iter, endLoopBranch, next, ...
21 +** After: Prog-> iter, [ARRAY_ITER], withVal, iterVarKey(, iterVarVal), iter, endLoopBranch, next, ...
22 ** TheStack-> [next], ...
23 ** Where:
24 ** iter is a symbol which gives the position of the iterator value in
25 ** the stack frame
26 ** arrayVal is the data value holding the array in question
27 @@ -3379,74 +3379,105 @@ static int beginArrayIter(void)
28 iteratorValPtr->val.arrayPtr = arrayIterateFirst(&arrayVal);
29 return(STAT_OK);
33 -** copy key to symbol if node is still valid, marked bad by a color of -1
34 -** then move iterator to next node
35 +** copy key and value to symbols if node is still valid, marked bad by a color
36 +** of -1 then move iterator to next node
37 ** this allows iterators to progress even if you delete any node in the array
38 ** except the item just after the current key
40 -** Before: Prog-> iter, ARRAY_ITER, [iterVar], iter, endLoopBranch, next, ...
41 +** Before: Prog-> iter, ARRAY_ITER, [withVal], iterVarKey(, iterVarVal), iter, endLoopBranch, next, ...
42 ** TheStack-> [next], ...
43 -** After: Prog-> iter, ARRAY_ITER, iterVar, iter, endLoopBranch, [next], ...
44 +** After: Prog-> iter, ARRAY_ITER, withVal, iterVarKey(, iterVarVal), iter, endLoopBranch, [next], ...
45 ** TheStack-> [next], ... (unchanged)
46 -** Where:
47 +** Where:
48 ** iter is a symbol which gives the position of the iterator value in
49 -** the stack frame (set up by BEGIN_ARRAY_ITER); that value refers
50 +** the stack frame (set up by OP_BEGIN_ARRAY_ITER); that value refers
51 ** to the array and a position within it
52 -** iterVal is the programmer-visible symbol which will take the current
53 +** iterVarKey is the programmer-visible symbol which will take the current
54 ** key value
55 +** iterVarVal is the programmer-visible symbol which will take the current
56 +** entry value (only if withVal is true)
57 ** endLoopBranch is the instruction offset to the instruction following the
58 ** loop (measured from itself)
59 ** arrayVal is the data value holding the array in question
60 ** The return-to-start-of-loop branch (at the end of the loop) should address
61 ** the ARRAY_ITER instruction
63 static int arrayIter(void)
65 Symbol *iterator;
66 - Symbol *item;
67 + Symbol *itemKey;
68 + Symbol *itemVal;
69 DataValue *iteratorValPtr;
70 - DataValue *itemValPtr;
71 + DataValue *itemVarKeyPtr;
72 + DataValue *itemVarValPtr;
73 SparseArrayEntry *thisEntry;
74 Inst *branchAddr;
75 + int withVal;
77 DISASM_RT(PC-1, 4);
78 - STACKDUMP(0, 3);
79 + STACKDUMP(0, 4);
81 - item = PC->sym;
82 + withVal = PC->value;
83 + PC++;
84 + itemKey = PC->sym;
85 PC++;
86 + if (withVal) {
87 + itemVal = PC->sym;
88 + PC++;
89 + }
90 iterator = PC->sym;
91 PC++;
92 branchAddr = PC + PC->value;
93 PC++;
95 - if (item->type == LOCAL_SYM) {
96 - itemValPtr = &FP_GET_SYM_VAL(FrameP, item);
97 + if (itemKey->type == LOCAL_SYM) {
98 + itemVarKeyPtr = &FP_GET_SYM_VAL(FrameP, itemKey);
100 - else if (item->type == GLOBAL_SYM) {
101 - itemValPtr = &(item->value);
102 + else if (itemKey->type == GLOBAL_SYM) {
103 + itemVarKeyPtr = &(itemKey->value);
105 else {
106 - return(execError("can't assign to: %s", item->name));
107 + return(execError("can't assign to: %s", itemKey->name));
109 + itemVarKeyPtr->tag = NO_TAG;
111 + if (withVal) {
112 + if (itemVal->type == LOCAL_SYM) {
113 + itemVarValPtr = &FP_GET_SYM_VAL(FrameP, itemVal);
115 + else if (itemVal->type == GLOBAL_SYM) {
116 + itemVarValPtr = &(itemVal->value);
118 + else {
119 + return(execError("can't assign to: %s", itemVal->name));
121 + itemVarValPtr->tag = NO_TAG;
123 - itemValPtr->tag = NO_TAG;
125 if (iterator->type == LOCAL_SYM) {
126 iteratorValPtr = &FP_GET_SYM_VAL(FrameP, iterator);
128 else {
129 return(execError("bad temporary iterator: %s", iterator->name));
132 thisEntry = iteratorValPtr->val.arrayPtr;
133 if (thisEntry && thisEntry->nodePtrs.color != -1) {
134 - itemValPtr->tag = STRING_TAG;
135 - itemValPtr->val.str.rep = thisEntry->key;
136 - itemValPtr->val.str.len = strlen(thisEntry->key);
138 + /* set key */
139 + itemVarKeyPtr->tag = STRING_TAG;
140 + itemVarKeyPtr->val.str.rep = thisEntry->key;
141 + itemVarKeyPtr->val.str.len = strlen(thisEntry->key);
143 + if (withVal) {
144 + /* set value */
145 + *itemVarValPtr = thisEntry->value;
148 + /* advance iterator */
149 iteratorValPtr->val.arrayPtr = arrayIterateNext(thisEntry);
151 else {
152 PC = branchAddr;
154 @@ -3970,16 +4001,29 @@ static void disasmInternal(Inst *inst, i
155 else if (j == OP_BEGIN_ARRAY_ITER) {
156 printd(" %s in", inst[i+1].sym->name);
157 ++i;
159 else if (j == OP_ARRAY_ITER) {
160 - printd(" %s = %s++ end-loop=(%+d) %8p",
161 - inst[i+1].sym->name,
162 - inst[i+2].sym->name,
163 - inst[i+3].value,
164 - &inst[i+3] + inst[i+3].value);
165 - i += 3;
166 + if (!inst[i+1].value) {
167 + /* without val */
168 + printd(" %s = %s++ end-loop=(%+d) %8p",
169 + inst[i+2].sym->name,
170 + inst[i+3].sym->name,
171 + inst[i+4].value,
172 + &inst[i+4] + inst[i+4].value);
173 + i += 4;
175 + else {
176 + /* with val */
177 + printd(" %s=%s = %s++ end-loop=(%+d) %8p",
178 + inst[i+2].sym->name,
179 + inst[i+3].sym->name,
180 + inst[i+4].sym->name,
181 + inst[i+5].value,
182 + &inst[i+5] + inst[i+5].value);
183 + i += 5;
186 else if (j == OP_ARRAY_REF ||
187 j == OP_ARRAY_DELETE ||
188 j == OP_ARRAY_ASSIGN ||
189 j == OP_ANONARRAY_INDEX_VAL ||
190 diff --quilt old/source/parse.y new/source/parse.y
191 --- old/source/parse.y
192 +++ new/source/parse.y
193 @@ -66,10 +66,11 @@ static int yyerror(char *s);
194 static int yylex(void);
195 int yyparse(void);
196 static int follow(char expect, int yes, int no);
197 static int follow2(char expect1, int yes1, char expect2, int yes2, int no);
198 static int follow_non_whitespace(char expect, int yes, int no);
199 +static int eq_look_ahead(void);
200 static Symbol *matchesActionRoutine(char **inPtr);
201 static int scanString(void);
203 static char *ErrMsg;
204 static char *InPtr;
205 @@ -91,11 +92,11 @@ static int nextSymIsField = 0;
206 enum operations oper;
207 AccumulatorData *acc;
209 %token <sym> NUMBER STRING SYMBOL FIELD
210 %token DELETE ARG_LOOKUP
211 -%token IF WHILE DO ELSE FOR BREAK CONTINUE RETURN TYPEOF
212 +%token IF WHILE DO ELSE FOR BREAK CONTINUE RETURN TYPEOF KEYVAL
213 %token <acc> DEFINE
214 %type <nArgs> arrlist arrentry
215 %type <nArgs> arglistopt arglist catlist fnarglsopt fnarglist fnarg
216 %type <inst> cond comastmts comastmtlst for while do else and or arrayexpr mark
217 %type <sym> evalsym
218 @@ -209,18 +210,41 @@ stmt: ';' blank
219 SwapCode($5+1, $7, GetPC());
220 ADD_OP(OP_BRANCH); ADD_BR_OFF($3); SET_BR_OFF($5, GetPC());
222 | for '(' blank SYMBOL IN blank arrayexpr blank ')' {
223 Symbol *iterSym = InstallIteratorSymbol();
224 - ADD_OP(OP_BEGIN_ARRAY_ITER); ADD_SYM(iterSym);
225 - ADD_OP(OP_ARRAY_ITER); ADD_SYM($4); ADD_SYM(iterSym); ADD_BR_OFF(0);
226 + ADD_OP(OP_BEGIN_ARRAY_ITER);
227 + ADD_SYM(iterSym);
228 + ADD_OP(OP_ARRAY_ITER);
229 + ADD_IMMED(0); /* without val symbol */
230 + ADD_SYM($4);
231 + ADD_SYM(iterSym);
232 + ADD_BR_OFF(0);
234 blank block {
235 - ADD_OP(OP_BRANCH); ADD_BR_OFF($7+2);
236 - SET_BR_OFF($7+5, GetPC());
237 + ADD_OP(OP_BRANCH);
238 + ADD_BR_OFF($7+2);
239 + SET_BR_OFF($7+6, GetPC());
240 FillLoopAddrs(GetPC(), $7+2);
242 + | for '(' blank SYMBOL KEYVAL SYMBOL IN blank arrayexpr blank ')' {
243 + Symbol *iterSym = InstallIteratorSymbol();
244 + ADD_OP(OP_BEGIN_ARRAY_ITER);
245 + ADD_SYM(iterSym);
246 + ADD_OP(OP_ARRAY_ITER);
247 + ADD_IMMED(1); /* with val symbol */
248 + ADD_SYM($4);
249 + ADD_SYM($6);
250 + ADD_SYM(iterSym);
251 + ADD_BR_OFF(0);
253 + blank block {
254 + ADD_OP(OP_BRANCH);
255 + ADD_BR_OFF($9+2);
256 + SET_BR_OFF($9+7, GetPC());
257 + FillLoopAddrs(GetPC(), $9+2);
259 | BREAK stmtend blank {
260 ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
261 if (AddBreakAddr(GetPC()-1)) {
262 yyerror("break outside loop"); YYERROR;
264 @@ -741,11 +765,11 @@ static int yylex(void)
265 /* process remaining two character tokens or return single char as token */
266 result = *InPtr++;
267 switch (result) {
268 case '>': return follow('=', GE, GT);
269 case '<': return follow('=', LE, LT);
270 - case '=': return follow('=', EQ, '=');
271 + case '=': return eq_look_ahead();
272 case '!': return follow('=', NE, NOT);
273 case '+': return follow2('+', INCR, '=', ADDEQ, '+');
274 case '-': return follow2('-', DECR, '=', SUBEQ, '-');
275 case '|': return follow2('|', OR, '=', OREQ, '|');
276 case '&': return follow2('&', AND, '=', ANDEQ, '&');
277 @@ -804,10 +828,49 @@ static int follow_non_whitespace(char ex
278 return(no);
283 +static int eq_look_ahead(void)
285 + char *savedInPtr = InPtr;
287 + /* check "==" */
288 + if (*InPtr == '=') {
289 + ++InPtr;
290 + return EQ;
293 + /* skip any whitespace */
294 + skipWhitespace();
296 + /* now a symbol */
297 + if (!isalpha((unsigned char)*InPtr) && *InPtr != '$') {
298 + InPtr = savedInPtr;
299 + return '=';
302 + /* skip remaining symbol chars */
303 + while (isalnum((unsigned char)*InPtr) || *InPtr == '_') {
304 + ++InPtr;
307 + /* skip any whitespace */
308 + skipWhitespace();
310 + /* now "in" */
311 + if (InPtr[0] == 'i' && InPtr[1] == 'n' &&
312 + (!isalnum((unsigned char)InPtr[2]) && InPtr[2] != '_')) {
313 + InPtr = savedInPtr;
314 + return KEYVAL;
317 + /* not the '=' in a key=val for loop */
318 + InPtr = savedInPtr;
319 + return '=';
323 ** Look (way) ahead for hyphenated routine names which begin at inPtr. A
324 ** hyphenated name is allowed if it is pre-defined in the global symbol
325 ** table. If a matching name exists, returns the symbol, and update "inPtr".
327 diff --quilt old/doc/help.etx new/doc/help.etx
328 --- old/doc/help.etx
329 +++ new/doc/help.etx
330 @@ -2256,10 +2256,15 @@ Macro Language
331 Keys are not guaranteed in any particular order:
333 for (aKey in x)
334 <body>
336 + Or, to get also the corresponding value for the key:
338 + for (aKey = theVal in x)
339 + <body>
341 Elements can be removed from an array using the delete command:
343 delete x[3] # deletes element with key 3
344 delete x[] # deletes all elements