comment reduxed MultipleAssignment
[nedit-bw.git] / MultipleAssignment-redux.patch
blob6b3d09e70ead0b9d6f755b4dd807e2010c740013
1 ---
3 source/interpret.c | 29 ++++++++++
4 source/ops.h | 1
5 source/parse.y | 151 +++++++++++++++--------------------------------------
6 3 files changed, 74 insertions(+), 107 deletions(-)
8 diff --quilt old/source/interpret.c new/source/interpret.c
9 --- old/source/interpret.c
10 +++ new/source/interpret.c
11 @@ -1974,6 +1974,30 @@ static int dupStack(void)
15 +** copy the value at stack postion index onto the stack
16 +** Before: Prog-> [index], next, ...
17 +** TheStack-> val0, ... valIndex, next, ...
18 +** After: Prog-> index, [next], ...
19 +** TheStack-> valIndex, val0, ... valIndex, next, ...
20 +*/
21 +static int peekPush(void)
23 + DataValue value;
24 + int index;
26 + DISASM_RT();
28 + GET_IMMED(index);
30 + STACKDUMP(index + 1, 3);
32 + PEEK(value, index);
33 + PUSH(value);
35 + return STAT_OK;
38 +/*
39 ** if left and right arguments are arrays, then the result is a new array
40 ** in which all the keys from both the right and left are copied
41 ** the values from the right array are used in the result array when the
42 @@ -4534,6 +4558,11 @@ static void disasmInternal(Inst *inst, i
44 break;
46 + case OP_PEEK_PUSH:
47 + printd(" peekIndex=%d", inst[i+1].val.immed);
48 + ++i;
49 + break;
51 case OP_BRANCH:
52 case OP_BRANCH_TRUE:
53 case OP_BRANCH_FALSE:
54 diff --quilt old/source/ops.h new/source/ops.h
55 --- old/source/ops.h
56 +++ new/source/ops.h
57 @@ -10,6 +10,7 @@ OP(PUSH_IMMED, pushImmed)
58 OP(PUSH_STRING, pushString) /* str */ /* push(str) */
59 OP(POP, popStack) /* pop(v) */
60 OP(DUP, dupStack) /* pop(v), push(v,v) */
61 +OP(PEEK_PUSH, peekPush) /* n */ /* peek(v, n), push(v) */
62 OP(ADD, add) /* pop(v2,v1), push(v1 + v2) */
63 OP(SUB, subtract) /* pop(v2,v1), push(v1 - v2) */
64 OP(MUL, multiply) /* pop(v2,v1), push(v1 * v2) */
65 diff --quilt old/source/parse.y new/source/parse.y
66 --- old/source/parse.y
67 +++ new/source/parse.y
68 @@ -108,15 +108,6 @@ static int nextSymIsField = 0;
69 /* set to 1 when we don't want a full symbol, just a name (string) for a
70 field name following a '.' */
72 -/*
73 -** Positions holder for instruction reordering of code generated for the
74 -** left-hand lvalue list in a multi-assignment statement.
75 -*/
76 -typedef struct LVinst {
77 - Inst *start, *mid, *next;
78 - int nArgs;
79 -} LVinst;
83 %union {
84 @@ -124,7 +115,6 @@ typedef struct LVinst {
85 Inst *inst;
86 int num;
87 enum operations oper;
88 - LVinst lvinst;
89 struct {
90 AccumulatorData *acc;
91 Symbol *sym;
92 @@ -141,7 +131,8 @@ typedef struct LVinst {
93 %type <oper> operassign incrdecr
94 %token <oper> '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
95 %token <oper> INCR DECR
96 -%type <lvinst> lvlist lventry
97 +%type <num> lvlist
98 +%type <inst> lventry
99 %token ARGSEP
101 %nonassoc IF_NO_ELSE
102 @@ -412,117 +403,63 @@ simpstmt: /* simple variable assignmen
104 ** Implementing a multi-assignment to a list of lvalues
106 -** Each accepting lvalue requires a push phase P and an assign phase A.
108 -** For arrays, P includes pushing the indices and the destination array value.
109 -** P always also includes pushing N, the position of the lval in the list, i.e.
110 -** the index into the r.h.s. array expression supplying values.
111 +** We do this by executing the rvalue first, and than do the assignment phase
112 +** afterward.
114 -** The assign phase uses N (on the stack) and the stored result E of the source
115 -** array expression - this gives the indexed r.h.s. value to assign. Then, if
116 -** the destination is an array element, the destination array and indices are
117 -** retrieved from the stack and the assignment performed.
119 -** Given "(a, b, c) = e", we need to end up with the command sequence:
120 -** Pc Pb Pa Ee Aa Ab Ac
121 -** However, we have to generate Px and Ax together in the parse. Hence we
122 -** must reorder, using PC mark positions Mx. For the example, we generate:
123 -** read a: M0[Pa]M1[Aa]Mt here Mt is the current GetPC() value
124 -** read b: M0[Pa]M1[Aa]M2[Pb]M3[Ab]Mt now swap(M0, M2, M3)
125 -** M0[Pb Pa]M1[Aa Ab]Mt
126 -** and c: M0[Pb Pa]M1[Aa Ab]M2[Pc]M3[Ac]Mt swap(M0, M2, M3)
127 -** M0[Pc Pb Pa]M1[Aa Ab Ac]Mt
128 -** then e: M0[Pc Pb Pa]M1[Aa Ab Ac]M2[Ee]Mt swap(M1, M2, Mt)
129 -** [Pc Pb Pa][Ee][Aa Ab Ac]
130 -** which is what we want. At each swap, we must retain intermediate positions.
131 -** Below for lvlist, M0 is $$.start, M1 is $$.mid, M2 is $$.next. lventry's $$
132 -** gives the mid value between the P and A phases (M1).
133 +** The rvalue value is constantly duped on the stack to do the array ref.
135 -lvlistexpr: '(' lvlist ')' blank '=' blank expr {
136 - /* store expression value */
137 - ADD_OP(OP_ASSIGN);
138 - ADD_SYM(LookupString("list assign expr", True));
139 - /* swap expression evaluation code into position */
140 - SwapCode($2.mid, $2.next, GetPC());
141 +lvlistexpr: '(' mark lvlist mark ')' blank '=' blank expr {
142 + /* swap expression evaluation code to front */
143 + SwapCode($2, $4, GetPC());
144 + ADD_OP(OP_POP); /* pop expression */
148 -** lvlist: code for pushing the expression's index is generated here, after the code
149 -** for assigning to the lvalue. In other words, the Px portion is split, with
150 -** the assign code in front of the push index code. This needs to be swapped.
151 -** Only then do we have the situation described for overall list assignment.
152 +** lvlist: code for doing the rvalue array ref.
154 +** We need to move this code infront of the actual assignment operation of
155 +** the lvalue, so that the result is ontop od the stack.
156 +** lventry's value will give us the start of this code.
158 lvlist: lventry {
159 + Inst *this = GetPC();
160 /* start case */
161 - $$.nArgs = $1.nArgs;
162 - /* add code to push the rvalue expression index needed */
163 - ADD_OP(OP_PUSH_IMMED); ADD_IMMED($$.nArgs);
164 - $$.start = $1.start;
165 - $$.next = GetPC();
166 + $$ = 1;
167 + /* add code to push the rvalue expression value */
168 + ADD_OP(OP_PUSH_IMMED); ADD_IMMED($$);
169 + ADD_OP(OP_ARRAY_REF); ADD_IMMED(1);
170 /* swap this code in front of the lvalue assignment code */
171 - $$.mid = SwapCode($1.mid, $1.next, $$.next);
172 + SwapCode($1, this, GetPC());
174 | lvlist ',' blank lventry {
175 - /* recursive step case - starts similarly */
176 - $$.nArgs = $1.nArgs + $4.nArgs;
177 - /* add code to push the rvalue expression index needed */
178 - ADD_OP(OP_PUSH_IMMED); ADD_IMMED($$.nArgs);
179 - $$.start = $1.start;
180 - $$.next = GetPC();
181 + Inst *this = GetPC();
182 + /* the index for this entry into the rvalue array */
183 + $$ = $1 + 1;
184 + /* add code to push the rvalue expression value */
185 + ADD_OP(OP_PUSH_IMMED); ADD_IMMED($$);
186 + ADD_OP(OP_ARRAY_REF); ADD_IMMED(1);
187 /* swap this code in front of the lvalue assignment code */
188 - $4.mid = SwapCode($4.mid, $4.next, $$.next);
189 - /*
190 - ** now swap Px code to midpoint and change midpoint
191 - ** $1.start[P...]$1.mid[A...]$1.next[Px]$4.mid[Ax]$$.next --->
192 - ** $1.start[Px][P...]$1.mid[A...]$4.mid[Ax]$$.next
193 - */
194 - SwapCode($1.start, $1.next, $4.mid);
195 - $$.start = $1.start; /* keep start point */
196 - $$.mid = $1.mid + ($4.mid - $1.next); /* adjust mid point */
197 + SwapCode($4, this, GetPC());
200 -/* lventry's value is the PC position between the Px and Ax parts */
201 -lventry: mark SYMBOL {
202 - $$.nArgs = 1;
203 - $$.start = $1;
204 - /* Push code: null */
205 - $$.mid = GetPC();
206 - /* Assign code: stack: N, ... */
207 - ADD_OP(OP_PUSH_SYM);
208 - ADD_SYM(LookupString("list assign expr", True));
209 - /* stack: E, N, ... */
210 - ADD_OP(OP_SWAP_TOP2); /* stack: N, E, ... */
211 - ADD_OP(OP_ARRAY_REF); ADD_IMMED(1); /* stack: E[N] ... */
212 - ADD_OP(OP_ASSIGN); ADD_SYM($2);
213 - $$.next = GetPC();
215 - | mark initarraylv '[' arglist ']' {
216 - $$.nArgs = 1;
217 - $$.start = $1;
218 - /* Push code dealt with in "initarraylv '[' arglist ']'" */
219 - $$.mid = GetPC();
220 - /* Assign code: stack: N, ... */
221 - ADD_OP(OP_PUSH_SYM);
222 - ADD_SYM(LookupString("list assign expr", True));
223 - /* stack: E, N, ... */
224 - ADD_OP(OP_SWAP_TOP2); /* stack: N, E, ... */
225 - ADD_OP(OP_ARRAY_REF); ADD_IMMED(1); /* stack: E[N] ... */
226 - ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($4);
227 - $$.next = GetPC();
229 - | mark initarraylv dot field {
230 - $$.nArgs = 1;
231 - $$.start = $1;
232 - /* Push code dealt with in "initarraylv dot field" */
233 - $$.mid = GetPC();
234 - /* Assign code: stack: N, ... */
235 - ADD_OP(OP_PUSH_SYM);
236 - ADD_SYM(LookupString("list assign expr", True));
237 - /* stack: E, N, ... */
238 - ADD_OP(OP_SWAP_TOP2); /* stack: N, E, ... */
239 - ADD_OP(OP_ARRAY_REF); ADD_IMMED(1); /* stack: E[N] ... */
240 +/* lventry's value is the start of the assignment code */
241 +lventry: SYMBOL {
242 + /* the rvalue is right on top, just dup it */
243 + ADD_OP(OP_DUP);
244 + $$ = GetPC();
245 + ADD_OP(OP_ASSIGN); ADD_SYM($1);
247 + | initarraylv '[' arglist ']' {
248 + /* above the rvalue is the array + nDim strings */
249 + ADD_OP(OP_PEEK_PUSH); ADD_IMMED($3 + 1);
250 + $$ = GetPC();
251 + ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED($3);
253 + | initarraylv dot field {
254 + /* above the rvalue is the array + one string */
255 + ADD_OP(OP_PEEK_PUSH); ADD_IMMED(2);
256 + $$ = GetPC();
257 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(1);
258 - $$.next = GetPC();