update to arrayReplacesArglist4.diff
[nedit-bw.git] / arrayReplacesArglist4.diff
blob17df5fcf3f1cbb42fc41d6594319ec7adee3b4b2
1 Allow all arguments to be passed to a function using a single array value,
2 using the syntax:
4 retval = func( = args)
6 This relies on other patches.
8 Numerically indexed arguments are extracted from the array and pushed on the
9 stack, along with the number of arguments.
11 ---
13 source/interpret.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++-----
14 source/interpret.h | 2
15 source/parse.y | 32 +++++++++---
16 3 files changed, 146 insertions(+), 21 deletions(-)
18 diff --quilt old/source/interpret.c new/source/interpret.c
19 --- old/source/interpret.c
20 +++ new/source/interpret.c
21 @@ -62,10 +62,12 @@ static const char CVSID[] = "$Id: interp
23 #ifdef HAVE_DEBUG_H
24 #include "../debug.h"
25 #endif
27 +#include <assert.h>
29 #define PROGRAM_SIZE 4096 /* Maximum program size */
30 #define MAX_ERR_MSG_LEN 256 /* Max. length for error messages */
31 #define LOOP_STACK_SIZE 200 /* (Approx.) Number of break/continue stmts
32 allowed per program */
33 #define INSTRUCTION_LIMIT 100 /* Number of instructions the interpreter is
34 @@ -117,10 +119,12 @@ static int concatenateNwithSep(int nVals
35 int leaveParams);
36 static int concat(void);
37 static int assign(void);
38 static int callSubroutineFromSymbol(Symbol *sym, int nArgs);
39 static int callSubroutine(void);
40 +static int callSubroutineStackedN(void);
41 +static int unpackArrayToArgs(void);
42 static int fetchRetVal(void);
43 static int branch(void);
44 static int branchTrue(void);
45 static int branchFalse(void);
46 static int branchIf(Boolean trueOrFalse);
47 @@ -229,10 +233,12 @@ static int (*OpFns[N_OPS])() = {returnNo
48 branchNever, arrayRef, arrayAssign, beginArrayIter, arrayIter, inArray,
49 deleteArrayElement, pushArraySymVal,
50 arrayRefAndAssignSetup, pushArgVal, pushArgCount, pushArgArray,
51 anonArrayOpen, anonArraySkip, anonArrayNextVal, anonArrayIndexVal,
52 anonArrayClose, namedArg1, namedArgN, swapTop2,
53 + callSubroutineStackedN,
54 + unpackArrayToArgs,
57 /* Stack-> symN-sym0(FP), nArgs, oldFP, retPC, argArray, argN-arg1, next, ... */
58 #define FP_ARG_COUNT_INDEX (-1)
59 #define FP_FUNCTION_NAME (-2) /* !! */
60 @@ -656,11 +662,11 @@ void RunMacroAsSubrCall(Program *prog)
62 StackP->tag = NO_TAG;
63 StackP->val.sym = prog->localSymList; /* symbol table */
64 StackP++;
66 - StackP->tag = STRING_TAG;
67 + StackP->tag = STRING_TAG; /* function name */
68 StackP->val.str.rep = prog->name ? prog->name : "<run-macro>";
69 StackP->val.str.len = strlen(StackP->val.str.rep);
70 StackP++;
72 StackP->tag = INT_TAG; /* nArgs */
73 @@ -1360,11 +1366,11 @@ static int pushArgArray(void)
74 resultArray->tag = ARRAY_TAG;
75 resultArray->val.arrayPtr = ArrayNew();
78 /* load arguments from positional arg list if not already done */
79 - if (nArgs && !ArrayGet(resultArray, longAsStr(argNum + 1), &argVal)) {
80 + if (nArgs && !ArrayGet(resultArray, (char *)longAsStr(argNum+1), &argVal)) {
81 for (argNum = 0; argNum < nArgs; ++argNum) {
82 argVal = FP_GET_ARG_N(FrameP, argNum);
83 if (!ArrayInsert(resultArray, AllocStringOfNumber(argNum + 1),
84 &argVal)) {
85 return(execError("argument array insertion failure", NULL));
86 @@ -2340,10 +2346,15 @@ static int concat(void)
89 ** For callSubroutine:
90 ** Before: Prog-> [subrSym], nArgs, next, ...
91 ** TheStack-> argArray?, argN-arg1, next, ...
92 +**
93 +** For callSubroutineStackedN:
94 +** Before: Prog-> [subrSym], next, ...
95 +** TheStack-> nArgs, argArray, argN-arg1, next, ...
96 +**
97 ** After: Prog-> next, ... -- (built-in called subr)
98 ** TheStack-> retVal?, next, ...
99 ** or: Prog-> (in called)next, ... -- (macro code called subr)
100 ** TheStack-> symN-sym1(FP), nArgs, oldFP, retPC, argArray, argN-arg1, next, ...
102 @@ -2363,12 +2374,13 @@ static int callSubroutineFromSymbol(Symb
103 ** If the subroutine is built-in, call the built-in routine
105 if (sym->type == C_FUNCTION_SYM) {
106 DataValue result;
108 - if (!haveNamedArgs)
109 + if (!haveNamedArgs) {
110 PUSH(noValue) /* push dummy named arg array */
113 /* "pop" stack back to the first argument in the call stack */
114 StackP -= nArgs + 1;
116 /* Call the function and check for preemption */
117 @@ -2488,23 +2500,56 @@ static int callSubroutineFromSymbol(Symb
118 ** Stack-> argN-arg1, next, ...
120 ** After: Prog-> next, ... -- (built-in called subr)
121 ** Stack-> retVal?, next, ...
122 ** or: Prog-> (in called)next, ... -- (macro code called subr)
123 -** Stack-> symN-sym1(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ...
124 +** Stack-> symN-sym1(FP), nArgs, oldFP, retPC, argArray, argN-arg1, next, ...
126 static int callSubroutine(void)
128 Symbol *sym;
129 int nArgs;
130 - int n;
132 sym = PC++->sym;
133 nArgs = PC++->value;
135 DISASM_RT(PC-3, 3);
136 - STACKDUMP(nArgs, 3);
137 + STACKDUMP(nArgs > 0 ? nArgs : -nArgs, 3);
139 + return callSubroutineFromSymbol(sym, nArgs);
143 +** Before: Prog-> [subrSym], next, ...
144 +** Stack-> nArgs, argArray, argN-arg1, next, ...
146 +** After: Prog-> next, ... -- (built-in called subr)
147 +** Stack-> retVal?, next, ...
148 +** or: Prog-> (in called)next, ... -- (macro code called subr)
149 +** Stack-> symN-sym1(FP), nArgs, oldFP, retPC, argArray, argN-arg1, next, ...
151 +static int callSubroutineStackedN(void)
153 + Symbol *sym;
154 + int nArgs;
155 + /* this is much like callSubroutine, but we get nArgs off the stack
156 + and it will always be negative since there is always an argArray */
158 + sym = PC++->sym;
160 + PEEK_INT(nArgs, 0)
161 + DISASM_RT(PC-2, 2);
162 + STACKDUMP(-nArgs + 1, 3); /* +1 for stacked nArgs */
164 + POP_INT(nArgs)
166 + assert (nArgs < 0);
168 + if (nArgs >= 0) {
169 + /* should never happen */
170 + return execError("array argument call to %s erroneous", sym->name);
173 return callSubroutineFromSymbol(sym, nArgs);
177 @@ -2514,24 +2559,35 @@ static int callSubroutine(void)
178 ** removeArgs must indicate how many.
181 int OverlayRoutineFromSymbol(Symbol *sym, int nArgs, int removeArgs)
183 - DataValue *stackTop = StackP + nArgs - removeArgs;
184 + DataValue *argArray = StackP + nArgs - removeArgs;
186 + assert (nArgs >= 0);
187 + assert (nArgs - removeArgs >= 0);
189 if (removeArgs > 0) {
190 DataValue *from = StackP + removeArgs;
191 DataValue *to = StackP;
192 int n = nArgs - removeArgs;
194 nArgs = n;
195 + ++n; /* add one for the argArray */
196 while (n--) {
197 *to++ = *from++;
201 - StackP = stackTop;
202 + if (argArray->tag == ARRAY_TAG) {
203 + StackP = argArray + 1;
204 + nArgs = -nArgs - 1;
206 + else {
207 + assert (argArray->tag == NO_TAG);
208 + StackP = argArray;
210 return callSubroutineFromSymbol(sym, nArgs);
214 ** Assumes a valid prog. Wraps the program in a dummy symbol then calls
215 @@ -2542,18 +2598,64 @@ int OverlayRoutineFromSymbol(Symbol *sym
216 int OverlayRoutineFromProg(Program *prog, int nArgs, int removeArgs)
218 Symbol sym;
220 sym.type = MACRO_FUNCTION_SYM;
221 - sym.name = "<overlaid function>";
222 + sym.name = prog->name;
223 sym.value.val.str.rep = (char *)prog;
224 sym.next = NULL;
226 return OverlayRoutineFromSymbol(&sym, nArgs, removeArgs);
230 +** For special call style where the $args array in the called function is
231 +** assigned from an array in the caller (as "calledFunc([]=argsArray)"),
232 +** take consecutive elements indexed from 1 and put them on the stack, leaving
233 +** the actual array at the top of the stack. Finally, add the negative of the
234 +** number of arguments plus 1 (for the argArray itself). This operation must
235 +** be followed by OP_SUBR_CALL_STACKED_N (callSubroutineStackedN()).
236 +** Before: Prog-> next, ...
237 +** Stack-> argArray, next, ...
238 +** After: Prog-> next, ...
239 +** Stack-> -(nArgs+1), argArray, argN-arg1, next, ...
241 +static int unpackArrayToArgs(void)
243 + int nArgs, res;
245 + DataValue dvEntry, dvArray;
247 + DISASM_RT(PC-1, 1);
248 + STACKDUMP(1, 3);
250 + POP(dvEntry)
252 + if (dvArray.tag != ARRAY_TAG) {
253 + return execError("argument array call made with non-array value", NULL);
256 + res = ArrayCopy(&dvArray, &dvEntry);
257 + if (res != STAT_OK) {
258 + return execError("cannot copy array in array call", NULL);
261 + /* push positional argument entries in the array on the stack */
262 + for (nArgs = 1; ; ++nArgs) {
263 + char *key = (char *)longAsStr(nArgs);
264 + if (!ArrayGet(&dvArray, key, &dvEntry))
265 + break;
266 + /* remove them from remaining array */
267 + ArrayDelete(&dvArray, key);
268 + PUSH(dvEntry)
270 + PUSH(dvArray)
271 + PUSH_INT(-nArgs)
272 + return STAT_OK;
276 ** This should never be executed, returnVal checks for the presence of this
277 ** instruction at the PC to decide whether to push the function's return
278 ** value, then skips over it without executing.
280 static int fetchRetVal(void)
281 @@ -3581,10 +3683,12 @@ static void disasmInternal(Inst *inst, i
282 "ARRAY_INDEX_VAL", /* anonArrayIndexVal: "{ [i]=expr }" */
283 "ARRAY_CLOSE", /* anonArrayClose: "{...}" */
284 "NAMED_ARG1", /* namedArg1: "fn([...]=..., ...)" */
285 "NAMED_ARGN", /* namedArgN: "fn(..., [...]=...)" */
286 "SWAP_TOP2", /* swapTop2: cf namedArgN */
287 + "SUBR_CALL_STACKED_N", /* callSubroutineStackedN */
288 + "UNPACKTOARGS", /* unpackArrayToArgs */
290 int i, j;
292 printd("\n");
293 for (i = 0; i < nInstr; ++i) {
294 @@ -3620,10 +3724,14 @@ static void disasmInternal(Inst *inst, i
295 else {
296 printd("%d args", args);
298 i += 2;
300 + else if (j == OP_SUBR_CALL_STACKED_N) {
301 + printd("%s args[] (?)", inst[i+1].sym->name);
302 + ++i;
304 else if (j == OP_BEGIN_ARRAY_ITER) {
305 printd("%s in", inst[i+1].sym->name);
306 ++i;
308 else if (j == OP_ARRAY_ITER) {
309 @@ -3667,10 +3775,11 @@ static void disasm(Inst *inst, int nInst
311 static int outIsTTY = -1;
312 if (outIsTTY == -1) outIsTTY = isatty(fileno(stdout));
313 if (outIsTTY) { printd("\033[H"); }
314 disasmInternal(inst, nInstr);
315 + if (outIsTTY) { printd("\033[J\n"); }
316 outPrintd();
318 #endif /* #ifdef DEBUG_DISASSEMBLER */
320 #ifdef DEBUG_STACK /* for run-time stack dumping */
321 @@ -3707,11 +3816,11 @@ static void stackdumpframe(DataValue *ar
322 if (len > 27)
323 len = 27;
324 if (len > symLen)
325 symLen = len;
330 /* output instructions between endDv and sp - 1 inclusive */
331 #ifdef DEBUG_STACK_HEADFIRST
332 dv = sp;
333 while (--dv >= endDv)
334 @@ -3754,11 +3863,11 @@ static void stackdumpframe(DataValue *ar
335 break;
337 printd(posFmt, pos);
339 /* local symbol names? */
340 - if (offset < nSyms) {
341 + if (0 <= offset && offset < nSyms) {
342 for (sym = syms; sym != NULL; sym = sym->next) {
343 if (sym->value.val.n == offset) {
344 symName = sym->name;
345 break;
347 @@ -3767,11 +3876,11 @@ static void stackdumpframe(DataValue *ar
348 printd("%-*.*s ", symLen, symLen, symName);
350 if (dv == fnNm && dv->tag == STRING_TAG && dv->val.str.rep)
351 printd("%s", dv->val.str.rep);
352 else
353 - dumpVal(*dv);
354 + dumpVal(*dv);
356 printd("\n");
359 #ifdef DEBUG_STACK_HEADFIRST
360 diff --quilt old/source/interpret.h new/source/interpret.h
361 --- old/source/interpret.h
362 +++ new/source/interpret.h
363 @@ -50,10 +50,12 @@ enum operations {OP_RETURN_NO_VAL, OP_RE
364 OP_ARRAY_DELETE, OP_PUSH_ARRAY_SYM, OP_ARRAY_REF_ASSIGN_SETUP, OP_PUSH_ARG,
365 OP_PUSH_ARG_COUNT, OP_PUSH_ARG_ARRAY,
366 OP_ANONARRAY_OPEN, OP_ANONARRAY_SKIP, OP_ANONARRAY_NEXT_VAL,
367 OP_ANONARRAY_INDEX_VAL, OP_ANONARRAY_CLOSE,
368 OP_NAMED_ARG1, OP_NAMED_ARGN, OP_SWAP_TOP2,
369 + OP_SUBR_CALL_STACKED_N,
370 + OP_UNPACKTOARGS,
371 N_OPS};
373 enum typeTags {NO_TAG, INT_TAG, STRING_TAG, ARRAY_TAG};
375 enum execReturnCodes {MACRO_TIME_LIMIT, MACRO_PREEMPT, MACRO_DONE, MACRO_ERROR};
376 diff --quilt old/source/parse.y new/source/parse.y
377 --- old/source/parse.y
378 +++ new/source/parse.y
379 @@ -66,10 +66,11 @@ static int nextSymIsField = 0;
380 enum operations oper;
382 %token <sym> NUMBER STRING SYMBOL FIELD
383 %token DELETE ARG_LOOKUP
384 %token IF WHILE DO ELSE FOR BREAK CONTINUE RETURN
385 +%type <nArgs> arrlist arrentry
386 %type <nArgs> arglistopt arglist catlist fnarglsopt fnarglist fnarg
387 %type <inst> cond comastmts comastmtlst for while do else and or arrayexpr mark
388 %type <sym> evalsym
389 %type <oper> operassign incrdecr
390 %token <oper> '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
391 @@ -244,15 +245,11 @@ simpstmt: /* simple variable assignmen
392 | incrdecr blank initarraylv dot field {
393 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED(0); ADD_IMMED(1);
394 ADD_OP($1);
395 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED(1);
397 - /* function call */
398 - | SYMBOL '(' fnarglsopt ')' {
399 - ADD_OP(OP_SUBR_CALL);
400 - ADD_SYM(PromoteToGlobal($1)); ADD_IMMED($3);
402 + | funccall
405 evalsym: SYMBOL {
406 $$ = $1; ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
408 @@ -262,19 +259,36 @@ comastmts: blank { $$ = G
410 comastmtlst: simpstmt blank { $$ = GetPC(); }
411 | comastmtlst ',' blank simpstmt blank { $$ = GetPC(); }
414 +/* array key argument lists */
415 arglistopt: blank { $$ = 0; }
416 | arglist { $$ = $1; }
418 arglist: blank expr blank { $$ = 1; }
419 | arglist ',' blank expr blank { $$ = $1 + 1; }
422 +/* string concatenation lists */
423 catlist: numexpr %prec CONCAT { $$ = 1; }
424 | catlist numexpr %prec CONCAT { $$ = $1 + 1; }
427 +/* function call and its argument lists */
428 +funccall: SYMBOL '(' fnarglsopt ')' {
429 + ADD_OP(OP_SUBR_CALL);
430 + ADD_SYM(PromoteToGlobal($1)); ADD_IMMED($3);
432 + | SYMBOL '(' blank '=' blank expr blank ')' {
433 + /* a single array replaces the argument list */
434 + ADD_OP(OP_UNPACKTOARGS);
435 + ADD_OP(OP_SUBR_CALL_STACKED_N);
436 + ADD_SYM(PromoteToGlobal($1));
440 fnarg: expr {
441 $$ = 0;
443 | '[' arglist ']' '=' expr {
444 $$ = $2; /* how many index elements to read? */
445 @@ -402,17 +416,17 @@ arrentry: blank {
447 numexpr: '(' blank expr blank ')'
448 | NUMBER { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); }
449 | STRING { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); }
450 | SYMBOL { ADD_OP(OP_PUSH_SYM); ADD_SYM($1); }
451 - | SYMBOL '(' fnarglsopt ')' {
452 - ADD_OP(OP_SUBR_CALL);
453 - ADD_SYM(PromoteToGlobal($1)); ADD_IMMED($3);
454 + | funccall {
455 ADD_OP(OP_FETCH_RET_VAL);
457 - /*
458 + /* this doesn't work for $args["string"]:
459 | ARG_LOOKUP '[' blank numexpr blank ']' { ADD_OP(OP_PUSH_ARG); }
460 + */
461 + /* this doesn't work if $args contains non-argnum indices
462 | ARG_LOOKUP '[' blank ']' { ADD_OP(OP_PUSH_ARG_COUNT); }
464 | ARG_LOOKUP { ADD_OP(OP_PUSH_ARG_ARRAY); }
465 | numexpr '[' arglistopt ']' {
466 ADD_OP(OP_ARRAY_REF); ADD_IMMED($3);