1 From: Tony Balinski <ajbj@free.fr>
2 Subject: Provide a call() macro function which calls another function given its name
4 The function invokes new code in interpret.c which calls the desired, named
5 function with any remaining arguments to call(). In this way, the function
6 is called using the same interpretation environment as call()'s invoker.
10 source/interpret.c | 91 ++++++++++++++++++++++++++++++++++++++++++++---------
11 source/interpret.h | 4 ++
12 source/macro.c | 28 ++++++++++++++++
13 3 files changed, 109 insertions(+), 14 deletions(-)
15 diff --quilt old/source/interpret.c new/source/interpret.c
16 --- old/source/interpret.c
17 +++ new/source/interpret.c
18 @@ -89,6 +89,7 @@ static int returnValOrNone(int valOnStac
19 static int branchIf(Boolean trueOrFalse);
20 static int namedArg1orN(Boolean isFirst);
22 +static int callSubroutineFromSymbol(Symbol *sym, int nArgs);
23 static int concatenateNwithSep(int nVals, const char *sep, char **result,
25 static int makeArrayKeyFromArgs(int nArgs, char **keyString, int leaveParams);
26 @@ -2440,7 +2441,9 @@ static int concat(void)
27 ** arguments and space for local variables are added to the stack, and the
28 ** PC is set to point to the new function. For a built-in routine, the
29 ** arguments are popped off the stack, and the routine is just called.
33 +** For callSubroutine:
34 ** Before: Prog-> [subrSym], nArgs, next, ...
35 ** TheStack-> argArray?, argN-arg1, next, ...
36 ** After: Prog-> next, ... -- (built-in called subr)
37 @@ -2448,30 +2451,21 @@ static int concat(void)
38 ** or: Prog-> (in called)next, ... -- (macro code called subr)
39 ** TheStack-> symN-sym1(FP), nArgs, oldFP, retPC, argArray, argN-arg1, next, ...
41 -static int callSubroutine(void)
42 +static int callSubroutineFromSymbol(Symbol *sym, int nArgs)
48 static DataValue noValue = {NO_TAG, {0}};
49 DataValue argArray = noValue;
58 + int haveNamedArgs = (nArgs < 0);
60 - haveNamedArgs = (nArgs < 0);
67 - STACKDUMP(nArgs + haveNamedArgs, 3);
70 ** If the subroutine is built-in, call the built-in routine
72 @@ -2568,6 +2562,75 @@ static int callSubroutine(void)
76 +** Before: Prog-> [subrSym], nArgs, next, ...
77 +** Stack-> argN-arg1, next, ...
79 +** After: Prog-> next, ... -- (built-in called subr)
80 +** Stack-> retVal?, next, ...
81 +** or: Prog-> (in called)next, ... -- (macro code called subr)
82 +** Stack-> symN-sym1(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ...
84 +static int callSubroutine(void)
91 + nArgs = PC++->value;
94 + STACKDUMP(nArgs, 3);
96 + return callSubroutineFromSymbol(sym, nArgs);
100 +** Assumes a valid symbol. Invokes callSubroutineFromSymbol(), correcting nArgs
101 +** to match that routine's expectations. This allows a callMS() function to be
102 +** written in macro.c. If the caller has already "consumed" stack elements,
103 +** removeArgs must indicate how many.
106 +int OverlayRoutineFromSymbol(Symbol *sym, int nArgs, int removeArgs)
108 + DataValue *stackTop = StackP + nArgs - removeArgs;
110 + if (removeArgs > 0) {
111 + DataValue *from = StackP + removeArgs;
112 + DataValue *to = StackP;
113 + int n = nArgs - removeArgs;
122 + return callSubroutineFromSymbol(sym, nArgs);
126 +** Assumes a valid prog. Wraps the program in a dummy symbol then calls
127 +** OverlayRoutineFromSymbol(). In this way a piece of compiled code can be
128 +** executed in the caller's context from a function in macro.c.
131 +int OverlayRoutineFromProg(Program *prog, int nArgs, int removeArgs)
135 + sym.type = MACRO_FUNCTION_SYM;
136 + sym.name = prog->name;
137 + sym.value.tag = NO_TAG;
138 + sym.value.val.prog = prog;
141 + return OverlayRoutineFromSymbol(&sym, nArgs, removeArgs);
145 ** This should never be executed, returnVal checks for the presence of this
146 ** instruction at the PC to decide whether to push the function's return
147 ** value, then skips over it without executing.
148 diff --quilt old/source/interpret.h new/source/interpret.h
149 --- old/source/interpret.h
150 +++ new/source/interpret.h
151 @@ -171,6 +171,10 @@ int ExecuteMacro(WindowInfo *window, Pro
152 int ContinueMacro(RestartData *continuation, DataValue *result, char **msg);
153 void RunMacroAsSubrCall(Program *prog);
154 void PreemptMacro(void);
156 +int OverlayRoutineFromProg(Program *prog, int nArgs, int removeArgs);
157 +int OverlayRoutineFromSymbol(Symbol *sym, int nArgs, int removeArgs);
159 char *AllocString(int length);
160 char *AllocStringNCpy(const char *s, int length);
161 char *AllocStringCpy(const char *s);
162 diff --quilt old/source/macro.c new/source/macro.c
163 --- old/source/macro.c
164 +++ new/source/macro.c
165 @@ -416,6 +416,8 @@ static int getStyleAtPosMS(WindowInfo *w
166 DataValue *result, char **errMsg);
167 static int filenameDialogMS(WindowInfo* window, DataValue* argList, int nArgs,
168 DataValue* result, char** errMsg);
169 +static int callMS(WindowInfo *window, DataValue *argList,
170 + int nArgs, DataValue *result, char **errMsg);
172 /* Built-in subroutines and variables for the macro language */
173 static const BuiltInSubrName MacroSubrs[] = {
174 @@ -475,6 +477,7 @@ static const BuiltInSubrName MacroSubrs[
175 { "get_style_by_name", getStyleByNameMS },
176 { "get_style_at_pos", getStyleAtPosMS },
177 { "filename_dialog", filenameDialogMS },
178 + { "call", callMS },
179 { NULL, NULL } /* sentinel */
182 @@ -3493,6 +3496,31 @@ static int filenameDialogMS(WindowInfo*
187 + * call(fnname, arg, ...)
189 +static int callMS(WindowInfo *window, DataValue *argList,
190 + int nArgs, DataValue *result, char **errMsg)
192 + char stringStorage[TYPE_INT_STR_SIZE(int)];
197 + *errMsg = "subroutine %s called without arguments";
200 + if (!readStringArg(argList[0], &fnname, stringStorage, errMsg)) {
203 + sym = LookupSymbol(fnname);
205 + *errMsg = "subroutine name invalid";
208 + return OverlayRoutineFromSymbol(sym, nArgs, 1);
212 static int listDialogMS(WindowInfo *window, DataValue *argList, int nArgs,
213 DataValue *result, char **errMsg)