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 | 75 ++++++++++++++++++++++++++++++++++++++++-------------
10 source/parse.y | 28 +++++++++++++++++++
11 2 files changed, 85 insertions(+), 18 deletions(-)
13 diff --quilt old/source/interpret.c new/source/interpret.c
14 --- old/source/interpret.c
15 +++ new/source/interpret.c
16 @@ -2782,34 +2782,63 @@ int OverlayRoutineFromProg(Program *prog
18 static int unpackArrayToArgs(void)
22 - DataValue dvEntry, dvArray;
23 + int nArgs, i, res, haveNamedArgs;
24 + SparseArrayEntry *iter;
25 + DataValue dvEntry, dvArray, argArray;
31 + nArgs = PC++->value;
32 + haveNamedArgs = (nArgs < 0);
36 - if (dvEntry.tag != ARRAY_TAG) {
37 + if (argArray.tag != ARRAY_TAG) {
38 return execError("argument array call made with non-array value", NULL);
40 - res = ArrayCopy(&dvArray, &dvEntry);
41 - if (res != STAT_OK) {
42 - return execError("cannot copy array in array call", NULL);
44 + if (haveNamedArgs) {
49 + dvArray.tag = ARRAY_TAG;
50 + dvArray.val.arrayPtr = ArrayNew();
53 - /* push positional argument entries in the array on the stack */
54 - for (nArgs = 1; ; ++nArgs) {
55 - char *ind = (char *)longAsStr(nArgs);
56 - if (!ArrayGet(&dvArray, ind, &dvEntry))
58 - /* remove them from remaining array */
59 - ArrayDelete(&dvArray, ind);
61 + iter = arrayIterateFirst(&argArray);
65 + if (iter->value.tag == ARRAY_TAG) {
69 + errNum = ArrayCopy(&dvEntry, &iter->value);
70 + if (errNum != STAT_OK) {
75 + dvEntry = iter->value;
78 + if (StringToNum(iter->key, &thisKey) && thisKey >= 0) {
83 + if (!ArrayInsert(&dvArray, iter->key, &dvEntry)) {
84 + return(execError("array copy failed", NULL));
88 + iter = arrayIterateNext(iter);
93 + PUSH_INT(-(nArgs + 1));
97 @@ -4331,8 +4360,18 @@ static void disasmInternal(Inst *inst, i
101 + else if (j == OP_UNPACKTOARGS) {
102 + int args = inst[i+2].value;
104 + printd(" %d+args[]", -args - 1, args);
107 + printd(" %d args", args);
111 else if (j == OP_SUBR_CALL_STACKED_N) {
112 - printd(" %s args[] (?)", inst[i+1].sym->name);
113 + printd(" %s =args[] (?)", inst[i+1].sym->name);
116 else if (j == OP_BEGIN_ARRAY_ITER ||
117 diff --quilt old/source/parse.y new/source/parse.y
118 --- old/source/parse.y
119 +++ new/source/parse.y
120 @@ -69,6 +69,7 @@ static int follow(char expect, int yes,
121 static int follow2(char expect1, int yes1, char expect2, int yes2, int no);
122 static int follow_non_whitespace(char expect, int yes, int no);
123 static int eq_look_ahead(void);
124 +static int comma_look_ahead(void);
125 static Symbol *matchesActionRoutine(char **inPtr);
126 static int scanString(void);
128 @@ -114,6 +115,7 @@ typedef struct LVinst {
129 %token <oper> '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
130 %token <oper> INCR DECR
131 %type <lvinst> lvlist lventry
136 @@ -550,6 +552,14 @@ funccall: TYPEOF '(' {
137 | SYMBOL '(' blank '=' blank expr blank ')' {
138 /* a single array replaces the argument list */
139 ADD_OP(OP_UNPACKTOARGS);
140 + ADD_IMMED(0); /* zero arguments */
141 + ADD_OP(OP_SUBR_CALL_STACKED_N);
142 + ADD_SYM(PromoteToGlobal($1));
144 + | SYMBOL '(' fnarglist ARGSEP blank '=' blank expr blank ')' {
145 + /* a single array replaces the argument list */
146 + ADD_OP(OP_UNPACKTOARGS);
148 ADD_OP(OP_SUBR_CALL_STACKED_N);
149 ADD_SYM(PromoteToGlobal($1));
151 @@ -978,6 +988,7 @@ static int yylex(void)
153 return result; /* but return what we started with */
155 + case ',': return comma_look_ahead();
156 default: return *(InPtr-1);
159 @@ -1062,6 +1073,23 @@ static int eq_look_ahead(void)
163 +static int comma_look_ahead(void)
165 + char *savedInPtr = InPtr;
167 + /* skip any whitespace */
170 + /* '=' from array argument */
171 + if (*InPtr == '=') {
172 + InPtr = savedInPtr;
176 + InPtr = savedInPtr;
181 ** Look (way) ahead for hyphenated routine names which begin at inPtr. A
182 ** hyphenated name is allowed if it is pre-defined in the global symbol