1 Subject: extend fn(=array) syntax to fn(..., =array)
3 All non-negative one-dimensional numerical keys are appended to the
4 previously arguments, in order. All other entries are merge into the named
9 source/interpret.c | 162 +++++++++++++++++++++++++++--------------------------
11 source/parse.y | 30 +++++++++
12 3 files changed, 114 insertions(+), 81 deletions(-)
14 diff --quilt old/source/interpret.c new/source/interpret.c
15 --- old/source/interpret.c
16 +++ new/source/interpret.c
17 @@ -2501,7 +2501,7 @@ static int concat(void)
18 ** Before: Prog-> [subrSym], nArgs, next, ...
19 ** TheStack-> argArray?, argN-arg1, next, ...
21 -** For callSubroutineStackedN:
22 +** For callSubroutineUnpackArray:
23 ** Before: Prog-> [subrSym], next, ...
24 ** TheStack-> nArgs, argArray, argN-arg1, next, ...
26 @@ -2642,37 +2642,92 @@ static int callSubroutine(void)
30 -** Before: Prog-> [subrSym], next, ...
31 -** Stack-> nArgs, argArray, argN-arg1, next, ...
32 +** For special call style where the $args array in the called function is
33 +** assigned from an array in the caller (as "calledFunc(=argsArray)"),
34 +** take consecutive elements indexed from 1 and put them on the stack, leaving
35 +** a copy of the actual array at the top of the stack, with the stacked
36 +** arguments removed. Finally, add the negative of the number of arguments
37 +** aplus 1 (for the argArray itself). This operation must be followed
38 +** by OP_SUBR_CALL_UNPACK_ARRAY (callSubroutineUnpackArray()).
40 -** After: Prog-> next, ... -- (built-in called subr)
41 -** Stack-> retVal?, next, ...
42 -** or: Prog-> (in called)next, ... -- (macro code called subr)
43 -** Stack-> symN-sym1(FP), nArgs, oldFP, retPC, argArray, argN-arg1, next, ...
44 +** The array copy is needed because if/when the $args array is accessed, the
45 +** arguments are copied back to the array, probably in different positions, as
46 +** is the case of a "call(=array)" function, where the first argument is
47 +** removed (the function name) and the others shifted down once. Without a
48 +** copy, this modifies the original array - a pass by reference not allowed in
51 +** Before: Prog-> [sym], nArgs, next, ...
52 +** TheStack-> argArray(, namedArgsArray), argN-arg1, next, ...
53 +** After: Prog-> sym, nArgs, [next], ...
54 +** TheStack-> namedArgsArray, argM-arg1, next, ...
56 -static int callSubroutineStackedN(void)
57 +static int callSubroutineUnpackArray(void)
61 - /* this is much like callSubroutine, but we get nArgs off the stack
62 - and it will always be negative since there is always an argArray */
63 + int nArgs, i, res, haveNamedArgs = 0;
64 + SparseArrayEntry *iter;
65 + DataValue dvEntry, dvArray, argArray;
70 + nArgs = PC++->value;
74 - STACKDUMP(-nArgs + 1, 3); /* +1 for stacked nArgs */
81 + STACKDUMP(nArgs + haveNamedArgs + 1, 3);
87 - /* should never happen */
88 - return execError("array argument call to %s erroneous", sym->name);
89 + if (argArray.tag != ARRAY_TAG) {
90 + return execError("argument array call made with non-array value", NULL);
93 - return callSubroutineFromSymbol(sym, nArgs);
94 + if (haveNamedArgs) {
98 + dvArray.tag = ARRAY_TAG;
99 + dvArray.val.arrayPtr = ArrayNew();
102 + iter = arrayIterateFirst(&argArray);
106 + if (iter->value.tag == ARRAY_TAG) {
108 + DataValue tmpArray;
110 + errNum = ArrayCopy(&dvEntry, &iter->value);
111 + if (errNum != STAT_OK) {
116 + dvEntry = iter->value;
119 + if (StringToNum(iter->key, &thisKey) && thisKey >= 0) {
124 + if (!ArrayInsert(&dvArray, iter->key, &dvEntry)) {
125 + return(execError("array copy failed", NULL));
129 + iter = arrayIterateNext(iter);
134 + return callSubroutineFromSymbol(sym, -nArgs - 1);
138 @@ -2732,60 +2787,6 @@ int OverlayRoutineFromProg(Program *prog
142 -** For special call style where the $args array in the called function is
143 -** assigned from an array in the caller (as "calledFunc(=argsArray)"),
144 -** take consecutive elements indexed from 1 and put them on the stack, leaving
145 -** a copy of the actual array at the top of the stack, with the stacked
146 -** arguments removed. Finally, add the negative of the number of arguments
147 -** aplus 1 (for the argArray itself). This operation must be followed
148 -** by OP_SUBR_CALL_STACKED_N (callSubroutineStackedN()).
150 -** The array copy is needed because if/when the $args array is accessed, the
151 -** arguments are copied back to the array, probably in different positions, as
152 -** is the case of a "call(=array)" function, where the first argument is
153 -** removed (the function name) and the others shifted down once. Without a
154 -** copy, this modifies the original array - a pass by reference not allowed in
157 -** Before: Prog-> next, ...
158 -** TheStack-> argArray, next, ...
159 -** After: Prog-> next, ...
160 -** TheStack-> -(nArgs+1), argArray, argN-arg1, next, ...
162 -static int unpackArrayToArgs(void)
166 - DataValue dvEntry, dvArray;
168 - DISASM_RT(PC-1, 1);
173 - if (dvEntry.tag != ARRAY_TAG) {
174 - return execError("argument array call made with non-array value", NULL);
176 - res = ArrayCopy(&dvArray, &dvEntry);
177 - if (res != STAT_OK) {
178 - return execError("cannot copy array in array call", NULL);
181 - /* push positional argument entries in the array on the stack */
182 - for (nArgs = 1; ; ++nArgs) {
183 - char *ind = (char *)longAsStr(nArgs);
184 - if (!ArrayGet(&dvArray, ind, &dvEntry))
186 - /* remove them from remaining array */
187 - ArrayDelete(&dvArray, ind);
196 ** This should never be executed, returnVal checks for the presence of this
197 ** instruction at the PC to decide whether to push the function's return
198 ** value, then skips over it without executing.
199 @@ -4330,9 +4331,16 @@ static void disasmInternal(Inst *inst, i
203 - else if (j == OP_SUBR_CALL_STACKED_N) {
204 - printd(" %s args[] (?)", inst[i+1].sym->name);
206 + else if (j == OP_SUBR_CALL_UNPACK_ARRAY) {
207 + int args = inst[i+2].value;
208 + printd(" %s", inst[i+1].sym->name);
210 + printd(" %d+args[] =args[]", -args - 1);
213 + printd(" %d args =args[]", args);
217 else if (j == OP_BEGIN_ARRAY_ITER ||
218 j == OP_BEGIN_ARRAY_ITER_ARRAY) {
219 diff --quilt old/source/parse.y new/source/parse.y
220 --- old/source/parse.y
221 +++ new/source/parse.y
222 @@ -69,6 +69,7 @@ static int follow(char expect, int yes,
223 static int follow2(char expect1, int yes1, char expect2, int yes2, int no);
224 static int follow_non_whitespace(char expect, int yes, int no);
225 static int eq_look_ahead(void);
226 +static int comma_look_ahead(void);
227 static Symbol *matchesActionRoutine(char **inPtr);
228 static int scanString(void);
230 @@ -117,6 +118,7 @@ typedef struct LVinst {
231 %token <oper> '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
232 %token <oper> INCR DECR
233 %type <lvinst> lvlist lventry
238 @@ -554,9 +556,15 @@ funccall: TYPEOF '(' {
240 | SYMBOL '(' blank '=' blank expr blank ')' {
241 /* a single array replaces the argument list */
242 - ADD_OP(OP_UNPACKTOARGS);
243 - ADD_OP(OP_SUBR_CALL_STACKED_N);
244 + ADD_OP(OP_SUBR_CALL_UNPACK_ARRAY);
245 ADD_SYM(PromoteToGlobal($1));
246 + ADD_IMMED(0); /* zero arguments */
248 + | SYMBOL '(' fnarglist ARGSEP blank '=' blank expr blank ')' {
249 + /* a single array replaces the argument list */
250 + ADD_OP(OP_SUBR_CALL_UNPACK_ARRAY);
251 + ADD_SYM(PromoteToGlobal($1));
256 @@ -991,6 +999,7 @@ static int yylex(void)
258 return result; /* but return what we started with */
260 + case ',': return comma_look_ahead();
261 default: return *(InPtr-1);
264 @@ -1075,6 +1084,23 @@ static int eq_look_ahead(void)
268 +static int comma_look_ahead(void)
270 + char *savedInPtr = InPtr;
272 + /* skip any whitespace */
275 + /* '=' from array argument */
276 + if (*InPtr == '=') {
277 + InPtr = savedInPtr;
281 + InPtr = savedInPtr;
286 ** Look (way) ahead for hyphenated routine names which begin at inPtr. A
287 ** hyphenated name is allowed if it is pre-defined in the global symbol
288 diff --quilt old/source/ops.h new/source/ops.h
291 @@ -60,7 +60,6 @@ OP(ANONARRAY_CLOSE, anonArrayClos
292 OP(NAMED_ARG1, namedArg1) /* N */ /* pop(v,kN..k1), a=ary(), a[k1..kN]=v, push(a) */
293 OP(NAMED_ARGN, namedArgN) /* N */ /* pop(v,kN..k1,a), a[k1..kN]=v, push(a) */
294 OP(SWAP_TOP2, swapTop2) /* pop(v1,v2), push(v1,v2) */
295 -OP(SUBR_CALL_STACKED_N, callSubroutineStackedN) /*s*/ /* pop(N,a,pN..p1), call(s) */
296 -OP(UNPACKTOARGS, unpackArrayToArgs) /* pop(a), push(a[1]..a[N],a,-(N+1)) */
297 +OP(SUBR_CALL_UNPACK_ARRAY, callSubroutineUnpackArray) /*s,N*/ /* pop(a), push(numerics(a)), call(s) */
298 OP(TYPEOF_IN, typeOfIn) /* enable typeof() */
299 OP(TYPEOF_OUT, typeOfOut) /* pop(v), push(typeof(v)) */