| 2 |
r |
1 |
/*
|
| 1016 |
maechler |
2 |
* R : A Computer Language for Statistical Data Analysis
|
| 2 |
r |
3 |
* Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka
|
| 87740 |
ripley |
4 |
* Copyright (C) 1998-2025 The R Core Team.
|
| 2 |
r |
5 |
*
|
|
|
6 |
* This program is free software; you can redistribute it and/or modify
|
|
|
7 |
* it under the terms of the GNU General Public License as published by
|
|
|
8 |
* the Free Software Foundation; either version 2 of the License, or
|
|
|
9 |
* (at your option) any later version.
|
|
|
10 |
*
|
|
|
11 |
* This program is distributed in the hope that it will be useful,
|
|
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
14 |
* GNU General Public License for more details.
|
|
|
15 |
*
|
|
|
16 |
* You should have received a copy of the GNU General Public License
|
| 42307 |
ripley |
17 |
* along with this program; if not, a copy is available at
|
| 68947 |
ripley |
18 |
* https://www.R-project.org/Licenses/
|
| 1839 |
ihaka |
19 |
*
|
|
|
20 |
*
|
|
|
21 |
* Contexts:
|
|
|
22 |
*
|
|
|
23 |
* A linked-list of execution contexts is kept so that control-flow
|
|
|
24 |
* constructs like "next", "break" and "return" will work. It is also
|
|
|
25 |
* used for error returns to top-level.
|
|
|
26 |
*
|
|
|
27 |
* context[k] -> context[k-1] -> ... -> context[0]
|
|
|
28 |
* ^ ^
|
|
|
29 |
* R_GlobalContext R_ToplevelContext
|
|
|
30 |
*
|
|
|
31 |
* Contexts are allocated on the stack as the evaluator invokes itself
|
|
|
32 |
* recursively. The memory is reclaimed naturally on return through
|
|
|
33 |
* the recursions (the R_GlobalContext pointer needs adjustment).
|
|
|
34 |
*
|
| 37654 |
ripley |
35 |
* A context contains the following information (and more):
|
| 1839 |
ihaka |
36 |
*
|
|
|
37 |
* nextcontext the next level context
|
|
|
38 |
* cjmpbuf longjump information for non-local return
|
|
|
39 |
* cstacktop the current level of the pointer protection stack
|
|
|
40 |
* callflag the context "type"
|
| 45446 |
ripley |
41 |
* call the call (name of function, or expression to
|
| 37654 |
ripley |
42 |
* get the function) that effected this
|
|
|
43 |
* context if a closure, otherwise often NULL.
|
|
|
44 |
* callfun the function, if this was a closure.
|
| 1839 |
ihaka |
45 |
* cloenv for closures, the environment of the closure.
|
|
|
46 |
* sysparent the environment the closure was called from
|
|
|
47 |
* conexit code for on.exit calls, to be executed in cloenv
|
|
|
48 |
* at exit from the closure (normal or abnormal).
|
|
|
49 |
* cend a pointer to function which executes if there is
|
|
|
50 |
* non-local return (i.e. an error)
|
| 20170 |
duncan |
51 |
* cenddata a void pointer to data for cend to use
|
| 14480 |
luke |
52 |
* vmax the current setting of the R_alloc stack
|
| 48623 |
murdoch |
53 |
* srcref the srcref at the time of the call
|
| 1839 |
ihaka |
54 |
*
|
|
|
55 |
* Context types can be one of:
|
|
|
56 |
*
|
|
|
57 |
* CTXT_TOPLEVEL The toplevel context
|
|
|
58 |
* CTXT_BREAK target for "break"
|
|
|
59 |
* CTXT_NEXT target for "next"
|
|
|
60 |
* CTXT_LOOP target for either "break" or "next"
|
|
|
61 |
* CTXT_RETURN target for "return" (i.e. a closure)
|
| 6191 |
maechler |
62 |
* CTXT_BROWSER target for "return" to exit from browser
|
| 1839 |
ihaka |
63 |
* CTXT_CCODE other functions that need clean up if an error occurs
|
| 6191 |
maechler |
64 |
* CTXT_RESTART a function call to restart was made inside the
|
|
|
65 |
* closure.
|
| 1839 |
ihaka |
66 |
*
|
| 6191 |
maechler |
67 |
* Code (such as the sys.xxx) that looks for CTXT_RETURN must also
|
|
|
68 |
* look for a CTXT_RESTART and CTXT_GENERIC.
|
|
|
69 |
* The mechanism used by restart is to change
|
|
|
70 |
* the context type; error/errorcall then looks for a RESTART and does
|
|
|
71 |
* a long jump there if it finds one.
|
| 6008 |
rgentlem |
72 |
*
|
| 1839 |
ihaka |
73 |
* A context is created with a call to
|
|
|
74 |
*
|
|
|
75 |
* void begincontext(RCNTXT *cptr, int flags,
|
| 6191 |
maechler |
76 |
* SEXP syscall, SEXP env, SEXP
|
| 23486 |
luke |
77 |
* sysp, SEXP promargs, SEXP callfun)
|
| 1839 |
ihaka |
78 |
*
|
|
|
79 |
* which sets up the context pointed to by cptr in the appropriate way.
|
|
|
80 |
* When the context goes "out-of-scope" a call to
|
|
|
81 |
*
|
|
|
82 |
* void endcontext(RCNTXT *cptr)
|
|
|
83 |
*
|
|
|
84 |
* restores the previous context (i.e. it adjusts the R_GlobalContext
|
|
|
85 |
* pointer).
|
|
|
86 |
*
|
|
|
87 |
* The non-local jump to a given context takes place in a call to
|
|
|
88 |
*
|
|
|
89 |
* void findcontext(int mask, SEXP env, SEXP val)
|
|
|
90 |
*
|
| 84246 |
maechler |
91 |
* This causes "val" to be stuffed into a globally accessible place and
|
| 1839 |
ihaka |
92 |
* then a search to take place back through the context list for an
|
|
|
93 |
* appropriate context. The kind of context sort is determined by the
|
|
|
94 |
* value of "mask". The value of mask should be the logical OR of all
|
|
|
95 |
* the context types desired.
|
|
|
96 |
*
|
|
|
97 |
* The value of "mask" is returned as the value of the setjump call at
|
|
|
98 |
* the level longjumped to. This is used to distinguish between break
|
|
|
99 |
* and next actions.
|
|
|
100 |
*
|
|
|
101 |
* Contexts can be used as a wrapper around functions that create windows
|
|
|
102 |
* or open files. These can then be shut/closed gracefully if an error
|
|
|
103 |
* occurs.
|
| 2 |
r |
104 |
*/
|
|
|
105 |
|
| 5187 |
hornik |
106 |
#ifdef HAVE_CONFIG_H
|
| 7701 |
hornik |
107 |
#include <config.h>
|
| 5187 |
hornik |
108 |
#endif
|
|
|
109 |
|
| 57538 |
ripley |
110 |
#define R_USE_SIGNALS 1
|
|
|
111 |
#include <Defn.h>
|
| 60667 |
ripley |
112 |
#include <Internal.h>
|
| 2 |
r |
113 |
|
| 14478 |
luke |
114 |
/* R_run_onexits - runs the conexit/cend code for all contexts from
|
|
|
115 |
R_GlobalContext down to but not including the argument context.
|
|
|
116 |
This routine does not stop at a CTXT_TOPLEVEL--the code that
|
|
|
117 |
determines the argument is responsible for making sure
|
|
|
118 |
CTXT_TOPLEVEL's are not crossed unless appropriate. */
|
|
|
119 |
|
| 83446 |
ripley |
120 |
attribute_hidden void R_run_onexits(RCNTXT *cptr)
|
| 1895 |
ihaka |
121 |
{
|
| 14443 |
luke |
122 |
RCNTXT *c;
|
|
|
123 |
|
|
|
124 |
for (c = R_GlobalContext; c != cptr; c = c->nextcontext) {
|
| 68923 |
ripley |
125 |
// a user embedding R incorrectly triggered this (PR#15420)
|
| 14478 |
luke |
126 |
if (c == NULL)
|
| 63535 |
ripley |
127 |
error("bad target context--should NEVER happen if R was called correctly");
|
| 14478 |
luke |
128 |
if (c->cend != NULL) {
|
| 14561 |
luke |
129 |
void (*cend)(void *) = c->cend;
|
| 14443 |
luke |
130 |
c->cend = NULL; /* prevent recursion */
|
| 25523 |
luke |
131 |
R_HandlerStack = c->handlerstack;
|
|
|
132 |
R_RestartStack = c->restartstack;
|
| 14561 |
luke |
133 |
cend(c->cenddata);
|
| 14443 |
luke |
134 |
}
|
|
|
135 |
if (c->cloenv != R_NilValue && c->conexit != R_NilValue) {
|
|
|
136 |
SEXP s = c->conexit;
|
| 66393 |
murdoch |
137 |
RCNTXT* savecontext = R_ExitContext;
|
|
|
138 |
R_ExitContext = c;
|
| 14443 |
luke |
139 |
c->conexit = R_NilValue; /* prevent recursion */
|
| 73111 |
kalibera |
140 |
/* we are in intermediate jump, so returnValue is undefined */
|
| 86113 |
luke |
141 |
c->returnValue = SEXP_TO_STACKVAL(NULL);
|
| 25523 |
luke |
142 |
R_HandlerStack = c->handlerstack;
|
|
|
143 |
R_RestartStack = c->restartstack;
|
| 14443 |
luke |
144 |
PROTECT(s);
|
| 42875 |
luke |
145 |
/* Since these are run before any jumps rather than after
|
|
|
146 |
jumping to the context where the exit handler was set
|
|
|
147 |
we need to make sure there is enough room on the
|
|
|
148 |
evaluation stack in case the jump is from handling a
|
|
|
149 |
stack overflow. To be safe it is good to also call
|
|
|
150 |
R_CheckStack. LT */
|
|
|
151 |
R_Expressions = R_Expressions_keep + 500;
|
|
|
152 |
R_CheckStack();
|
| 73181 |
luke |
153 |
for (; s != R_NilValue; s = CDR(s)) {
|
|
|
154 |
c->conexit = CDR(s);
|
|
|
155 |
eval(CAR(s), c->cloenv);
|
|
|
156 |
}
|
| 14443 |
luke |
157 |
UNPROTECT(1);
|
| 66393 |
murdoch |
158 |
R_ExitContext = savecontext;
|
| 14443 |
luke |
159 |
}
|
| 66393 |
murdoch |
160 |
if (R_ExitContext == c)
|
|
|
161 |
R_ExitContext = NULL; /* Not necessary? Better safe than sorry. */
|
| 14443 |
luke |
162 |
}
|
| 14478 |
luke |
163 |
}
|
|
|
164 |
|
|
|
165 |
|
| 14479 |
luke |
166 |
/* R_restore_globals - restore global variables from a target context
|
|
|
167 |
before a LONGJMP. The target context itself is not restored here
|
| 70324 |
luke |
168 |
since this is done in R_jumpctxt below. */
|
| 14479 |
luke |
169 |
|
| 70324 |
luke |
170 |
static void R_restore_globals(RCNTXT *cptr)
|
| 14479 |
luke |
171 |
{
|
|
|
172 |
R_PPStackTop = cptr->cstacktop;
|
| 68755 |
luke |
173 |
R_GCEnabled = cptr->gcenabled;
|
| 71390 |
luke |
174 |
R_BCIntActive = cptr->bcintactive;
|
|
|
175 |
R_BCpc = cptr->bcpc;
|
|
|
176 |
R_BCbody = cptr->bcbody;
|
| 86189 |
luke |
177 |
R_BCFrame = cptr->bcframe;
|
| 14479 |
luke |
178 |
R_EvalDepth = cptr->evaldepth;
|
| 14480 |
luke |
179 |
vmaxset(cptr->vmax);
|
| 87816 |
ripley |
180 |
R_interrupts_suspended = (Rboolean) cptr->intsusp;
|
| 25523 |
luke |
181 |
R_HandlerStack = cptr->handlerstack;
|
|
|
182 |
R_RestartStack = cptr->restartstack;
|
| 41992 |
luke |
183 |
while (R_PendingPromises != cptr->prstack) {
|
| 42875 |
luke |
184 |
/* The value 2 installed in PRSEEN 2 allows forcePromise in
|
| 41992 |
luke |
185 |
eval.c to signal a warning when asked to evaluate a promise
|
|
|
186 |
whose evaluation has been interrupted by a jump. */
|
|
|
187 |
SET_PRSEEN(R_PendingPromises->promise, 2);
|
|
|
188 |
R_PendingPromises = R_PendingPromises->next;
|
|
|
189 |
}
|
| 42875 |
luke |
190 |
/* Need to reset R_Expressions in case we are jumping after
|
|
|
191 |
handling a stack overflow. */
|
|
|
192 |
R_Expressions = R_Expressions_keep;
|
| 26026 |
luke |
193 |
R_BCNodeStackTop = cptr->nodestack;
|
| 48623 |
murdoch |
194 |
R_Srcref = cptr->srcref;
|
| 77275 |
luke |
195 |
R_BCProtReset(cptr->bcprottop);
|
| 14479 |
luke |
196 |
}
|
|
|
197 |
|
| 70325 |
luke |
198 |
static RCNTXT *first_jump_target(RCNTXT *cptr, int mask)
|
|
|
199 |
{
|
|
|
200 |
RCNTXT *c;
|
|
|
201 |
|
|
|
202 |
for (c = R_GlobalContext; c && c != cptr; c = c->nextcontext) {
|
| 73866 |
luke |
203 |
if ((c->cloenv != R_NilValue && c->conexit != R_NilValue) ||
|
|
|
204 |
c->callflag == CTXT_UNWIND) {
|
| 70325 |
luke |
205 |
c->jumptarget = cptr;
|
|
|
206 |
c->jumpmask = mask;
|
|
|
207 |
return c;
|
|
|
208 |
}
|
|
|
209 |
}
|
|
|
210 |
return cptr;
|
|
|
211 |
}
|
|
|
212 |
|
| 70324 |
luke |
213 |
/* R_jumpctxt - jump to the named context */
|
| 14479 |
luke |
214 |
|
| 87740 |
ripley |
215 |
NORET attribute_hidden void R_jumpctxt(RCNTXT * targetcptr, int mask, SEXP val)
|
| 14478 |
luke |
216 |
{
|
| 40068 |
ripley |
217 |
Rboolean savevis = R_Visible;
|
| 70325 |
luke |
218 |
RCNTXT *cptr;
|
| 14478 |
luke |
219 |
|
| 70325 |
luke |
220 |
/* find the target for the first jump -- either an intermediate
|
|
|
221 |
context with an on.exit action to run or the final target if
|
|
|
222 |
there are no intermediate on.exit actions */
|
|
|
223 |
cptr = first_jump_target(targetcptr, mask);
|
|
|
224 |
|
|
|
225 |
/* run cend code for all contexts down to but not including
|
|
|
226 |
the first jump target */
|
| 14478 |
luke |
227 |
R_run_onexits(cptr);
|
| 14443 |
luke |
228 |
R_Visible = savevis;
|
|
|
229 |
|
| 1895 |
ihaka |
230 |
R_ReturnedValue = val;
|
| 70324 |
luke |
231 |
R_GlobalContext = cptr;
|
| 19318 |
luke |
232 |
R_restore_globals(R_GlobalContext);
|
|
|
233 |
|
| 70324 |
luke |
234 |
/* if we are in the process of handling a C stack overflow we need
|
|
|
235 |
to restore the C stack limit before the jump */
|
|
|
236 |
if (R_OldCStackLimit != 0) {
|
|
|
237 |
R_CStackLimit = R_OldCStackLimit;
|
|
|
238 |
R_OldCStackLimit = 0;
|
|
|
239 |
}
|
|
|
240 |
|
| 87015 |
luke |
241 |
if (mask == 0)
|
|
|
242 |
mask = 1; // make sure the return value for SETJMP is not zero
|
|
|
243 |
|
| 86210 |
luke |
244 |
LONGJMP(cptr->cjmpbuf, mask);
|
| 1895 |
ihaka |
245 |
}
|
|
|
246 |
|
|
|
247 |
|
| 2 |
r |
248 |
/* begincontext - begin an execution context */
|
| 1839 |
ihaka |
249 |
|
| 38662 |
ripley |
250 |
/* begincontext and endcontext are used in dataentry.c and modules */
|
| 1839 |
ihaka |
251 |
void begincontext(RCNTXT * cptr, int flags,
|
| 23463 |
luke |
252 |
SEXP syscall, SEXP env, SEXP sysp,
|
|
|
253 |
SEXP promargs, SEXP callfun)
|
| 2 |
r |
254 |
{
|
| 1839 |
ihaka |
255 |
cptr->cstacktop = R_PPStackTop;
|
| 68755 |
luke |
256 |
cptr->gcenabled = R_GCEnabled;
|
| 86233 |
luke |
257 |
cptr->relpc = R_BCRelPC(R_BCbody, R_BCpc);
|
| 71390 |
luke |
258 |
cptr->bcpc = R_BCpc;
|
|
|
259 |
cptr->bcbody = R_BCbody;
|
| 86189 |
luke |
260 |
cptr->bcframe = R_BCFrame;
|
| 71390 |
luke |
261 |
cptr->bcintactive = R_BCIntActive;
|
| 8230 |
rgentlem |
262 |
cptr->evaldepth = R_EvalDepth;
|
| 1839 |
ihaka |
263 |
cptr->callflag = flags;
|
|
|
264 |
cptr->call = syscall;
|
|
|
265 |
cptr->cloenv = env;
|
|
|
266 |
cptr->sysparent = sysp;
|
|
|
267 |
cptr->conexit = R_NilValue;
|
|
|
268 |
cptr->cend = NULL;
|
|
|
269 |
cptr->promargs = promargs;
|
| 23463 |
luke |
270 |
cptr->callfun = callfun;
|
| 14480 |
luke |
271 |
cptr->vmax = vmaxget();
|
| 25200 |
luke |
272 |
cptr->intsusp = R_interrupts_suspended;
|
| 25523 |
luke |
273 |
cptr->handlerstack = R_HandlerStack;
|
|
|
274 |
cptr->restartstack = R_RestartStack;
|
| 41992 |
luke |
275 |
cptr->prstack = R_PendingPromises;
|
| 26026 |
luke |
276 |
cptr->nodestack = R_BCNodeStackTop;
|
| 77275 |
luke |
277 |
cptr->bcprottop = R_BCProtTop;
|
| 68923 |
ripley |
278 |
cptr->srcref = R_Srcref;
|
| 63400 |
murdoch |
279 |
cptr->browserfinish = R_GlobalContext->browserfinish;
|
| 62867 |
luke |
280 |
cptr->nextcontext = R_GlobalContext;
|
| 86113 |
luke |
281 |
cptr->returnValue = SEXP_TO_STACKVAL(NULL);
|
| 70325 |
luke |
282 |
cptr->jumptarget = NULL;
|
|
|
283 |
cptr->jumpmask = 0;
|
| 63400 |
murdoch |
284 |
|
| 1839 |
ihaka |
285 |
R_GlobalContext = cptr;
|
| 2 |
r |
286 |
}
|
|
|
287 |
|
| 1839 |
ihaka |
288 |
|
| 2 |
r |
289 |
/* endcontext - end an execution context */
|
| 1839 |
ihaka |
290 |
|
| 2 |
r |
291 |
void endcontext(RCNTXT * cptr)
|
|
|
292 |
{
|
| 79542 |
luke |
293 |
void R_FixupExitingHandlerResult(SEXP); /* defined in error.c */
|
|
|
294 |
SEXP R_UnwindHandlerStack(SEXP); /* defined in error.c */
|
|
|
295 |
R_HandlerStack = R_UnwindHandlerStack(cptr->handlerstack);
|
| 25523 |
luke |
296 |
R_RestartStack = cptr->restartstack;
|
| 73133 |
luke |
297 |
RCNTXT *jumptarget = cptr->jumptarget;
|
| 14878 |
luke |
298 |
if (cptr->cloenv != R_NilValue && cptr->conexit != R_NilValue ) {
|
| 15299 |
luke |
299 |
SEXP s = cptr->conexit;
|
| 40090 |
ripley |
300 |
Rboolean savevis = R_Visible;
|
| 66393 |
murdoch |
301 |
RCNTXT* savecontext = R_ExitContext;
|
| 73111 |
kalibera |
302 |
SEXP saveretval = R_ReturnedValue;
|
| 66393 |
murdoch |
303 |
R_ExitContext = cptr;
|
| 15299 |
luke |
304 |
cptr->conexit = R_NilValue; /* prevent recursion */
|
| 73133 |
luke |
305 |
cptr->jumptarget = NULL; /* in case on.exit expr calls return() */
|
| 73111 |
kalibera |
306 |
PROTECT(saveretval);
|
| 15299 |
luke |
307 |
PROTECT(s);
|
| 73853 |
luke |
308 |
R_FixupExitingHandlerResult(saveretval);
|
| 86113 |
luke |
309 |
SEXP cptr_retval =
|
|
|
310 |
cptr->returnValue.tag == 0 ? cptr->returnValue.u.sxpval : NULL;
|
|
|
311 |
if (cptr_retval) // why is this needed???
|
|
|
312 |
INCREMENT_LINKS(cptr_retval);
|
| 73181 |
luke |
313 |
for (; s != R_NilValue; s = CDR(s)) {
|
|
|
314 |
cptr->conexit = CDR(s);
|
|
|
315 |
eval(CAR(s), cptr->cloenv);
|
|
|
316 |
}
|
| 86113 |
luke |
317 |
if (cptr_retval) // why is this needed???
|
|
|
318 |
DECREMENT_LINKS(cptr_retval);
|
| 73111 |
kalibera |
319 |
R_ReturnedValue = saveretval;
|
|
|
320 |
UNPROTECT(2);
|
| 66393 |
murdoch |
321 |
R_ExitContext = savecontext;
|
| 15299 |
luke |
322 |
R_Visible = savevis;
|
| 14878 |
luke |
323 |
}
|
| 66393 |
murdoch |
324 |
if (R_ExitContext == cptr)
|
| 68923 |
ripley |
325 |
R_ExitContext = NULL;
|
| 84246 |
maechler |
326 |
/* continue jumping if this was reached as an intermediate jump */
|
| 73133 |
luke |
327 |
if (jumptarget)
|
| 73111 |
kalibera |
328 |
/* cptr->returnValue is undefined */
|
| 73133 |
luke |
329 |
R_jumpctxt(jumptarget, cptr->jumpmask, R_ReturnedValue);
|
| 70325 |
luke |
330 |
|
| 1839 |
ihaka |
331 |
R_GlobalContext = cptr->nextcontext;
|
| 2 |
r |
332 |
}
|
|
|
333 |
|
| 1839 |
ihaka |
334 |
|
| 2 |
r |
335 |
/* findcontext - find the correct context */
|
| 1839 |
ihaka |
336 |
|
| 87740 |
ripley |
337 |
NORET attribute_hidden void findcontext(int mask, SEXP env, SEXP val)
|
| 2 |
r |
338 |
{
|
| 1839 |
ihaka |
339 |
RCNTXT *cptr;
|
|
|
340 |
cptr = R_GlobalContext;
|
|
|
341 |
if (mask & CTXT_LOOP) { /* break/next */
|
| 14633 |
luke |
342 |
for (cptr = R_GlobalContext;
|
|
|
343 |
cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
|
|
|
344 |
cptr = cptr->nextcontext)
|
| 13793 |
rgentlem |
345 |
if (cptr->callflag & CTXT_LOOP && cptr->cloenv == env )
|
| 70324 |
luke |
346 |
R_jumpctxt(cptr, mask, val);
|
| 55024 |
murdoch |
347 |
error(_("no loop for break/next, jumping to top level"));
|
| 1839 |
ihaka |
348 |
}
|
|
|
349 |
else { /* return; or browser */
|
| 14633 |
luke |
350 |
for (cptr = R_GlobalContext;
|
|
|
351 |
cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
|
|
|
352 |
cptr = cptr->nextcontext)
|
| 4089 |
rgentlem |
353 |
if ((cptr->callflag & mask) && cptr->cloenv == env)
|
| 70324 |
luke |
354 |
R_jumpctxt(cptr, mask, val);
|
| 33297 |
ripley |
355 |
error(_("no function to return from, jumping to top level"));
|
| 1839 |
ihaka |
356 |
}
|
|
|
357 |
}
|
| 2 |
r |
358 |
|
| 87740 |
ripley |
359 |
NORET attribute_hidden void R_JumpToContext(RCNTXT *target, int mask, SEXP val)
|
| 25520 |
luke |
360 |
{
|
|
|
361 |
RCNTXT *cptr;
|
|
|
362 |
for (cptr = R_GlobalContext;
|
|
|
363 |
cptr != NULL && cptr->callflag != CTXT_TOPLEVEL;
|
| 66393 |
murdoch |
364 |
cptr = cptr->nextcontext) {
|
| 25520 |
luke |
365 |
if (cptr == target)
|
| 70324 |
luke |
366 |
R_jumpctxt(cptr, mask, val);
|
| 68923 |
ripley |
367 |
if (cptr == R_ExitContext)
|
| 66393 |
murdoch |
368 |
R_ExitContext = NULL;
|
|
|
369 |
}
|
| 33297 |
ripley |
370 |
error(_("target context is not on the stack"));
|
| 25520 |
luke |
371 |
}
|
| 2 |
r |
372 |
|
| 25520 |
luke |
373 |
|
| 1839 |
ihaka |
374 |
/* R_sysframe - look back up the context stack until the */
|
|
|
375 |
/* nth closure context and return that cloenv. */
|
|
|
376 |
/* R_sysframe(0) means the R_GlobalEnv environment */
|
|
|
377 |
/* negative n counts back from the current frame */
|
|
|
378 |
/* positive n counts up from the globalEnv */
|
|
|
379 |
|
| 83446 |
ripley |
380 |
attribute_hidden SEXP R_sysframe(int n, RCNTXT *cptr)
|
| 2 |
r |
381 |
{
|
| 1839 |
ihaka |
382 |
if (n == 0)
|
|
|
383 |
return(R_GlobalEnv);
|
| 2 |
r |
384 |
|
| 70927 |
ripley |
385 |
if (n == NA_INTEGER) error(_("NA argument is invalid"));
|
|
|
386 |
|
| 1839 |
ihaka |
387 |
if (n > 0)
|
|
|
388 |
n = framedepth(cptr) - n;
|
|
|
389 |
else
|
|
|
390 |
n = -n;
|
| 2 |
r |
391 |
|
| 1839 |
ihaka |
392 |
if(n < 0)
|
| 71390 |
luke |
393 |
error(_("not that many frames on the stack"));
|
| 2 |
r |
394 |
|
| 1839 |
ihaka |
395 |
while (cptr->nextcontext != NULL) {
|
| 6188 |
rgentlem |
396 |
if (cptr->callflag & CTXT_FUNCTION ) {
|
| 1839 |
ihaka |
397 |
if (n == 0) { /* we need to detach the enclosing env */
|
|
|
398 |
return cptr->cloenv;
|
|
|
399 |
}
|
|
|
400 |
else
|
|
|
401 |
n--;
|
| 2 |
r |
402 |
}
|
| 1839 |
ihaka |
403 |
cptr = cptr->nextcontext;
|
|
|
404 |
}
|
|
|
405 |
if(n == 0 && cptr->nextcontext == NULL)
|
|
|
406 |
return R_GlobalEnv;
|
|
|
407 |
else
|
| 71390 |
luke |
408 |
error(_("not that many frames on the stack"));
|
| 6191 |
maechler |
409 |
return R_NilValue; /* just for -Wall */
|
| 2 |
r |
410 |
}
|
|
|
411 |
|
| 1016 |
maechler |
412 |
|
| 1839 |
ihaka |
413 |
/* We need to find the environment that can be returned by sys.frame */
|
|
|
414 |
/* (so it needs to be on the cloenv pointer of a context) that matches */
|
|
|
415 |
/* the environment where the closure arguments are to be evaluated. */
|
|
|
416 |
/* It would be much simpler if sysparent just returned cptr->sysparent */
|
|
|
417 |
/* but then we wouldn't be compatible with S. */
|
| 2 |
r |
418 |
|
| 87901 |
ripley |
419 |
attribute_hidden int R_sysparent(int n, RCNTXT *cptr)
|
| 2 |
r |
420 |
{
|
| 1839 |
ihaka |
421 |
int j;
|
|
|
422 |
SEXP s;
|
|
|
423 |
if(n <= 0)
|
| 32861 |
ripley |
424 |
errorcall(R_ToplevelContext->call,
|
| 33531 |
ripley |
425 |
_("only positive values of 'n' are allowed"));
|
| 1839 |
ihaka |
426 |
while (cptr->nextcontext != NULL && n > 1) {
|
| 6188 |
rgentlem |
427 |
if (cptr->callflag & CTXT_FUNCTION )
|
| 1839 |
ihaka |
428 |
n--;
|
|
|
429 |
cptr = cptr->nextcontext;
|
|
|
430 |
}
|
|
|
431 |
/* make sure we're looking at a return context */
|
| 6188 |
rgentlem |
432 |
while (cptr->nextcontext != NULL && !(cptr->callflag & CTXT_FUNCTION) )
|
| 1839 |
ihaka |
433 |
cptr = cptr->nextcontext;
|
|
|
434 |
s = cptr->sysparent;
|
|
|
435 |
if(s == R_GlobalEnv)
|
|
|
436 |
return 0;
|
|
|
437 |
j = 0;
|
|
|
438 |
while (cptr != NULL ) {
|
| 6188 |
rgentlem |
439 |
if (cptr->callflag & CTXT_FUNCTION) {
|
| 1839 |
ihaka |
440 |
j++;
|
|
|
441 |
if( cptr->cloenv == s )
|
|
|
442 |
n=j;
|
|
|
443 |
}
|
|
|
444 |
cptr = cptr->nextcontext;
|
|
|
445 |
}
|
|
|
446 |
n = j - n + 1;
|
|
|
447 |
if (n < 0)
|
| 6098 |
pd |
448 |
n = 0;
|
| 1839 |
ihaka |
449 |
return n;
|
| 2 |
r |
450 |
}
|
|
|
451 |
|
| 87901 |
ripley |
452 |
attribute_hidden int framedepth(RCNTXT *cptr)
|
| 2 |
r |
453 |
{
|
| 1839 |
ihaka |
454 |
int nframe = 0;
|
|
|
455 |
while (cptr->nextcontext != NULL) {
|
| 6188 |
rgentlem |
456 |
if (cptr->callflag & CTXT_FUNCTION )
|
| 1839 |
ihaka |
457 |
nframe++;
|
|
|
458 |
cptr = cptr->nextcontext;
|
|
|
459 |
}
|
|
|
460 |
return nframe;
|
| 2 |
r |
461 |
}
|
|
|
462 |
|
| 71390 |
luke |
463 |
static SEXP getCallWithSrcref(RCNTXT *cptr)
|
|
|
464 |
{
|
|
|
465 |
SEXP result;
|
|
|
466 |
|
|
|
467 |
PROTECT(result = shallow_duplicate(cptr->call));
|
|
|
468 |
if (cptr->srcref && !isNull(cptr->srcref)) {
|
|
|
469 |
SEXP sref;
|
|
|
470 |
if (cptr->srcref == R_InBCInterpreter)
|
|
|
471 |
/* FIXME: this is expensive, it might be worth changing sys.call */
|
|
|
472 |
/* to return srcrefs only on request (add `with.source` option) */
|
|
|
473 |
sref = R_findBCInterpreterSrcref(cptr);
|
|
|
474 |
else
|
|
|
475 |
sref = cptr->srcref;
|
|
|
476 |
setAttrib(result, R_SrcrefSymbol, duplicate(sref));
|
|
|
477 |
}
|
|
|
478 |
UNPROTECT(1);
|
|
|
479 |
return result;
|
|
|
480 |
}
|
|
|
481 |
|
| 83446 |
ripley |
482 |
attribute_hidden SEXP R_syscall(int n, RCNTXT *cptr)
|
| 2 |
r |
483 |
{
|
| 1839 |
ihaka |
484 |
/* negative n counts back from the current frame */
|
|
|
485 |
/* positive n counts up from the globalEnv */
|
|
|
486 |
if (n > 0)
|
| 33531 |
ripley |
487 |
n = framedepth(cptr) - n;
|
| 1839 |
ihaka |
488 |
else
|
|
|
489 |
n = - n;
|
| 33531 |
ripley |
490 |
if(n < 0)
|
| 71390 |
luke |
491 |
error(_("not that many frames on the stack"));
|
| 1839 |
ihaka |
492 |
while (cptr->nextcontext != NULL) {
|
| 6188 |
rgentlem |
493 |
if (cptr->callflag & CTXT_FUNCTION ) {
|
| 71390 |
luke |
494 |
if (n == 0)
|
|
|
495 |
return getCallWithSrcref(cptr);
|
|
|
496 |
else
|
| 1839 |
ihaka |
497 |
n--;
|
|
|
498 |
}
|
|
|
499 |
cptr = cptr->nextcontext;
|
|
|
500 |
}
|
| 71390 |
luke |
501 |
if (n == 0 && cptr->nextcontext == NULL)
|
|
|
502 |
return getCallWithSrcref(cptr);
|
|
|
503 |
error(_("not that many frames on the stack"));
|
| 6191 |
maechler |
504 |
return R_NilValue; /* just for -Wall */
|
| 2 |
r |
505 |
}
|
|
|
506 |
|
| 83446 |
ripley |
507 |
attribute_hidden SEXP R_sysfunction(int n, RCNTXT *cptr)
|
| 2 |
r |
508 |
{
|
| 1839 |
ihaka |
509 |
if (n > 0)
|
| 1864 |
ihaka |
510 |
n = framedepth(cptr) - n;
|
| 1839 |
ihaka |
511 |
else
|
|
|
512 |
n = - n;
|
| 33531 |
ripley |
513 |
if (n < 0)
|
| 71390 |
luke |
514 |
error(_("not that many frames on the stack"));
|
| 1839 |
ihaka |
515 |
while (cptr->nextcontext != NULL) {
|
| 6188 |
rgentlem |
516 |
if (cptr->callflag & CTXT_FUNCTION ) {
|
| 23463 |
luke |
517 |
if (n == 0)
|
|
|
518 |
return duplicate(cptr->callfun); /***** do we need to DUP? */
|
| 1839 |
ihaka |
519 |
else
|
|
|
520 |
n--;
|
| 2 |
r |
521 |
}
|
| 1839 |
ihaka |
522 |
cptr = cptr->nextcontext;
|
|
|
523 |
}
|
| 23463 |
luke |
524 |
if (n == 0 && cptr->nextcontext == NULL)
|
|
|
525 |
return duplicate(cptr->callfun); /***** do we need to DUP? */
|
| 71390 |
luke |
526 |
error(_("not that many frames on the stack"));
|
| 6191 |
maechler |
527 |
return R_NilValue; /* just for -Wall */
|
| 2 |
r |
528 |
}
|
| 1016 |
maechler |
529 |
|
| 48598 |
rgentlem |
530 |
/* count how many contexts of the specified type are present on the stack */
|
| 48600 |
rgentlem |
531 |
/* browser contexts are a bit special because they are transient and for */
|
|
|
532 |
/* any closure context with the debug bit set one will be created; so we */
|
|
|
533 |
/* need to count those as well */
|
| 86648 |
luke |
534 |
attribute_hidden int countContexts(int ctxttype, int browser) {
|
| 48598 |
rgentlem |
535 |
int n=0;
|
|
|
536 |
RCNTXT *cptr;
|
|
|
537 |
|
|
|
538 |
cptr = R_GlobalContext;
|
|
|
539 |
while( cptr != R_ToplevelContext) {
|
| 68923 |
ripley |
540 |
if( cptr->callflag == ctxttype )
|
|
|
541 |
n++;
|
|
|
542 |
else if( browser ) {
|
|
|
543 |
if(cptr->callflag & CTXT_FUNCTION && RDEBUG(cptr->cloenv) )
|
|
|
544 |
n++;
|
|
|
545 |
}
|
|
|
546 |
cptr = cptr->nextcontext;
|
| 48598 |
rgentlem |
547 |
}
|
|
|
548 |
return n;
|
|
|
549 |
}
|
| 68923 |
ripley |
550 |
|
|
|
551 |
|
| 48437 |
rgentlem |
552 |
/* functions to support looking up information about the browser */
|
|
|
553 |
/* contexts that are in the evaluation stack */
|
|
|
554 |
|
| 83446 |
ripley |
555 |
attribute_hidden SEXP do_sysbrowser(SEXP call, SEXP op, SEXP args, SEXP rho)
|
| 48437 |
rgentlem |
556 |
{
|
| 48459 |
rgentlem |
557 |
SEXP rval=R_NilValue;
|
| 48437 |
rgentlem |
558 |
RCNTXT *cptr;
|
| 71390 |
luke |
559 |
RCNTXT *prevcptr = NULL;
|
| 48551 |
rgentlem |
560 |
int n;
|
| 48437 |
rgentlem |
561 |
|
|
|
562 |
checkArity(op, args);
|
| 48551 |
rgentlem |
563 |
n = asInteger(CAR(args));
|
|
|
564 |
if(n < 1 ) error(_("number of contexts must be positive"));
|
|
|
565 |
|
| 48437 |
rgentlem |
566 |
/* first find the closest browser context */
|
|
|
567 |
cptr = R_GlobalContext;
|
|
|
568 |
while (cptr != R_ToplevelContext) {
|
| 68923 |
ripley |
569 |
if (cptr->callflag == CTXT_BROWSER) {
|
|
|
570 |
break;
|
|
|
571 |
}
|
|
|
572 |
cptr = cptr->nextcontext;
|
| 48437 |
rgentlem |
573 |
}
|
| 48452 |
rgentlem |
574 |
/* error if not a browser context */
|
| 48437 |
rgentlem |
575 |
|
| 48599 |
rgentlem |
576 |
if( !(cptr->callflag == CTXT_BROWSER) )
|
| 68923 |
ripley |
577 |
error(_("no browser context to query"));
|
| 48452 |
rgentlem |
578 |
|
| 48437 |
rgentlem |
579 |
switch (PRIMVAL(op)) {
|
|
|
580 |
case 1: /* text */
|
|
|
581 |
case 2: /* condition */
|
| 68923 |
ripley |
582 |
/* first rewind to the right place if needed */
|
|
|
583 |
/* note we want n>1, as we have already */
|
|
|
584 |
/* rewound to the first context */
|
|
|
585 |
if( n > 1 ) {
|
|
|
586 |
while (cptr != R_ToplevelContext && n > 0 ) {
|
|
|
587 |
if (cptr->callflag == CTXT_BROWSER) {
|
|
|
588 |
n--;
|
|
|
589 |
break;
|
|
|
590 |
}
|
|
|
591 |
cptr = cptr->nextcontext;
|
|
|
592 |
}
|
|
|
593 |
}
|
|
|
594 |
if( !(cptr->callflag == CTXT_BROWSER) )
|
|
|
595 |
error(_("not that many calls to browser are active"));
|
| 48551 |
rgentlem |
596 |
|
| 68923 |
ripley |
597 |
if( PRIMVAL(op) == 1 )
|
|
|
598 |
rval = CAR(cptr->promargs);
|
|
|
599 |
else
|
|
|
600 |
rval = CADR(cptr->promargs);
|
|
|
601 |
break;
|
| 48551 |
rgentlem |
602 |
case 3: /* turn on debugging n levels up */
|
| 68923 |
ripley |
603 |
while ( (cptr != R_ToplevelContext) && n > 0 ) {
|
|
|
604 |
if (cptr->callflag & CTXT_FUNCTION)
|
|
|
605 |
n--;
|
| 71390 |
luke |
606 |
prevcptr = cptr;
|
| 68923 |
ripley |
607 |
cptr = cptr->nextcontext;
|
|
|
608 |
}
|
|
|
609 |
if( !(cptr->callflag & CTXT_FUNCTION) )
|
| 71390 |
luke |
610 |
error(_("not that many functions on the call stack"));
|
|
|
611 |
if( prevcptr && prevcptr->srcref == R_InBCInterpreter ) {
|
|
|
612 |
if ( TYPEOF(cptr->callfun) == CLOSXP &&
|
|
|
613 |
TYPEOF(BODY(cptr->callfun)) == BCODESXP )
|
|
|
614 |
warning(_("debug flag in compiled function has no effect"));
|
|
|
615 |
else
|
|
|
616 |
warning(_("debug will apply when function leaves "
|
|
|
617 |
"compiled code"));
|
|
|
618 |
}
|
|
|
619 |
SET_RDEBUG(cptr->cloenv, 1);
|
| 68923 |
ripley |
620 |
break;
|
| 48437 |
rgentlem |
621 |
}
|
|
|
622 |
return(rval);
|
|
|
623 |
}
|
|
|
624 |
|
| 4857 |
rgentlem |
625 |
/* An implementation of S's frame access functions. They usually count */
|
|
|
626 |
/* up from the globalEnv while we like to count down from the currentEnv. */
|
|
|
627 |
/* So if the argument is negative count down if positive count up. */
|
| 40192 |
ripley |
628 |
/* We don't want to count the closure that do_sys is contained in, so the */
|
| 4857 |
rgentlem |
629 |
/* indexing is adjusted to handle this. */
|
|
|
630 |
|
| 83979 |
luke |
631 |
/* Return first `CTXT_FUNCTION` context whose execution
|
|
|
632 |
env matches `rho` */
|
|
|
633 |
attribute_hidden RCNTXT *getLexicalContext(SEXP rho)
|
|
|
634 |
{
|
|
|
635 |
RCNTXT *cptr = R_GlobalContext;
|
|
|
636 |
|
|
|
637 |
while (cptr && cptr != R_ToplevelContext) {
|
|
|
638 |
if (cptr->callflag & CTXT_FUNCTION && cptr->cloenv == rho)
|
|
|
639 |
break;
|
|
|
640 |
cptr = cptr->nextcontext;
|
|
|
641 |
}
|
|
|
642 |
|
|
|
643 |
return cptr;
|
|
|
644 |
}
|
|
|
645 |
|
|
|
646 |
/* Return call of the first `CTXT_FUNCTION` context whose
|
|
|
647 |
execution env matches `rho` */
|
|
|
648 |
attribute_hidden SEXP getLexicalCall(SEXP rho)
|
|
|
649 |
{
|
|
|
650 |
RCNTXT *cptr = getLexicalContext(rho);
|
|
|
651 |
if (cptr)
|
|
|
652 |
return cptr->call;
|
|
|
653 |
else
|
|
|
654 |
return R_NilValue;
|
|
|
655 |
}
|
|
|
656 |
|
| 83446 |
ripley |
657 |
attribute_hidden SEXP do_sys(SEXP call, SEXP op, SEXP args, SEXP rho)
|
| 2 |
r |
658 |
{
|
| 40192 |
ripley |
659 |
int i, n = -1, nframe;
|
| 83979 |
luke |
660 |
SEXP rval;
|
| 40192 |
ripley |
661 |
|
|
|
662 |
checkArity(op, args);
|
| 83979 |
luke |
663 |
|
| 1839 |
ihaka |
664 |
/* first find the context that sys.xxx needs to be evaluated in */
|
| 83979 |
luke |
665 |
SEXP t = R_GlobalContext->sysparent;
|
|
|
666 |
RCNTXT *cptr = getLexicalContext(t);
|
| 2 |
r |
667 |
|
| 40192 |
ripley |
668 |
if (length(args) == 1) n = asInteger(CAR(args));
|
| 2 |
r |
669 |
|
| 1839 |
ihaka |
670 |
switch (PRIMVAL(op)) {
|
|
|
671 |
case 1: /* parent */
|
| 33531 |
ripley |
672 |
if(n == NA_INTEGER)
|
| 44512 |
ripley |
673 |
error(_("invalid '%s' argument"), "n");
|
| 41894 |
ripley |
674 |
i = nframe = framedepth(cptr);
|
| 6098 |
pd |
675 |
/* This is a pretty awful kludge, but the alternative would be
|
|
|
676 |
a major redesign of everything... -pd */
|
|
|
677 |
while (n-- > 0)
|
|
|
678 |
i = R_sysparent(nframe - i + 1, cptr);
|
| 41894 |
ripley |
679 |
return ScalarInteger(i);
|
| 1839 |
ihaka |
680 |
case 2: /* call */
|
| 33531 |
ripley |
681 |
if(n == NA_INTEGER)
|
| 44512 |
ripley |
682 |
error(_("invalid '%s' argument"), "which");
|
| 1839 |
ihaka |
683 |
return R_syscall(n, cptr);
|
|
|
684 |
case 3: /* frame */
|
| 33531 |
ripley |
685 |
if(n == NA_INTEGER)
|
| 44512 |
ripley |
686 |
error(_("invalid '%s' argument"), "which");
|
| 1839 |
ihaka |
687 |
return R_sysframe(n, cptr);
|
|
|
688 |
case 4: /* sys.nframe */
|
| 41894 |
ripley |
689 |
return ScalarInteger(framedepth(cptr));
|
| 1839 |
ihaka |
690 |
case 5: /* sys.calls */
|
| 33531 |
ripley |
691 |
nframe = framedepth(cptr);
|
|
|
692 |
PROTECT(rval = allocList(nframe));
|
| 1839 |
ihaka |
693 |
t=rval;
|
| 33531 |
ripley |
694 |
for(i = 1; i <= nframe; i++, t = CDR(t))
|
|
|
695 |
SETCAR(t, R_syscall(i, cptr));
|
| 1839 |
ihaka |
696 |
UNPROTECT(1);
|
|
|
697 |
return rval;
|
|
|
698 |
case 6: /* sys.frames */
|
| 33531 |
ripley |
699 |
nframe = framedepth(cptr);
|
|
|
700 |
PROTECT(rval = allocList(nframe));
|
|
|
701 |
t = rval;
|
|
|
702 |
for(i = 1; i <= nframe; i++, t = CDR(t))
|
|
|
703 |
SETCAR(t, R_sysframe(i, cptr));
|
| 1839 |
ihaka |
704 |
UNPROTECT(1);
|
|
|
705 |
return rval;
|
|
|
706 |
case 7: /* sys.on.exit */
|
| 73310 |
luke |
707 |
{
|
|
|
708 |
SEXP conexit = cptr->conexit;
|
| 73181 |
luke |
709 |
if (conexit == R_NilValue)
|
|
|
710 |
return R_NilValue;
|
|
|
711 |
else if (CDR(conexit) == R_NilValue)
|
|
|
712 |
return CAR(conexit);
|
|
|
713 |
else
|
|
|
714 |
return LCONS(R_BraceSymbol, conexit);
|
|
|
715 |
}
|
| 1839 |
ihaka |
716 |
case 8: /* sys.parents */
|
| 33531 |
ripley |
717 |
nframe = framedepth(cptr);
|
|
|
718 |
rval = allocVector(INTSXP, nframe);
|
|
|
719 |
for(i = 0; i < nframe; i++)
|
|
|
720 |
INTEGER(rval)[i] = R_sysparent(nframe - i, cptr);
|
| 1839 |
ihaka |
721 |
return rval;
|
|
|
722 |
case 9: /* sys.function */
|
| 33531 |
ripley |
723 |
if(n == NA_INTEGER)
|
| 44512 |
ripley |
724 |
error(_("invalid '%s' value"), "which");
|
| 1839 |
ihaka |
725 |
return(R_sysfunction(n, cptr));
|
|
|
726 |
default:
|
| 33531 |
ripley |
727 |
error(_("internal error in 'do_sys'"));
|
| 1839 |
ihaka |
728 |
return R_NilValue;/* just for -Wall */
|
|
|
729 |
}
|
| 2 |
r |
730 |
}
|
| 10583 |
pd |
731 |
|
| 83446 |
ripley |
732 |
attribute_hidden SEXP do_parentframe(SEXP call, SEXP op, SEXP args, SEXP rho)
|
| 10583 |
pd |
733 |
{
|
| 40192 |
ripley |
734 |
checkArity(op, args);
|
| 10583 |
pd |
735 |
|
| 78036 |
luke |
736 |
int n = asInteger(CAR(args));
|
| 10583 |
pd |
737 |
if(n == NA_INTEGER || n < 1 )
|
| 44512 |
ripley |
738 |
error(_("invalid '%s' value"), "n");
|
| 10583 |
pd |
739 |
|
| 78036 |
luke |
740 |
RCNTXT *cptr = R_findParentContext(R_GlobalContext, n);
|
|
|
741 |
|
|
|
742 |
if (cptr)
|
|
|
743 |
return cptr->sysparent;
|
|
|
744 |
else
|
|
|
745 |
return R_GlobalEnv;
|
|
|
746 |
}
|
|
|
747 |
|
|
|
748 |
/* R_findExecContext - Find a context frame older than `cptr` that has
|
|
|
749 |
`envir` as execution environment (the `cloenv` field). */
|
|
|
750 |
attribute_hidden
|
|
|
751 |
RCNTXT *R_findExecContext(RCNTXT *cptr, SEXP envir)
|
|
|
752 |
{
|
|
|
753 |
while (cptr->nextcontext != NULL) {
|
|
|
754 |
if ((cptr->callflag & CTXT_FUNCTION) != 0 && cptr->cloenv == envir)
|
|
|
755 |
return cptr;
|
| 10586 |
pd |
756 |
cptr = cptr->nextcontext;
|
| 10583 |
pd |
757 |
}
|
| 78036 |
luke |
758 |
return NULL;
|
| 10583 |
pd |
759 |
}
|
| 10586 |
pd |
760 |
|
| 78036 |
luke |
761 |
/* R_findParentContext - Find a context frame older than `cptr` whose
|
|
|
762 |
execution environment (`cloenv` field) is the same as cptr's
|
|
|
763 |
calling environment (`sysparent` field). In other words, find the
|
|
|
764 |
frame where `cptr->syscall` was (seemingly) called. This algorithm
|
|
|
765 |
powers `parent.frame()`. */
|
|
|
766 |
attribute_hidden
|
|
|
767 |
RCNTXT *R_findParentContext(RCNTXT *cptr, int n)
|
|
|
768 |
{
|
|
|
769 |
while ((cptr = R_findExecContext(cptr, cptr->sysparent)) != NULL) {
|
|
|
770 |
if (n == 1)
|
|
|
771 |
return cptr;
|
|
|
772 |
n--;
|
|
|
773 |
}
|
|
|
774 |
return NULL;
|
|
|
775 |
}
|
|
|
776 |
|
| 14634 |
luke |
777 |
/* R_ToplevelExec - call fun(data) within a top level context to
|
| 84246 |
maechler |
778 |
insure that this function cannot be left by a LONGJMP. R errors in
|
| 14634 |
luke |
779 |
the call to fun will result in a jump to top level. The return
|
|
|
780 |
value is TRUE if fun returns normally, FALSE if it results in a
|
|
|
781 |
jump to top level. */
|
|
|
782 |
|
| 38196 |
ripley |
783 |
Rboolean R_ToplevelExec(void (*fun)(void *), void *data)
|
| 14634 |
luke |
784 |
{
|
|
|
785 |
RCNTXT thiscontext;
|
|
|
786 |
RCNTXT * volatile saveToplevelContext;
|
| 73171 |
luke |
787 |
volatile SEXP topExp, oldHStack, oldRStack, oldRVal;
|
|
|
788 |
volatile Rboolean oldvis;
|
| 14634 |
luke |
789 |
Rboolean result;
|
|
|
790 |
|
|
|
791 |
|
|
|
792 |
PROTECT(topExp = R_CurrentExpr);
|
| 52909 |
luke |
793 |
PROTECT(oldHStack = R_HandlerStack);
|
| 73171 |
luke |
794 |
PROTECT(oldRStack = R_RestartStack);
|
|
|
795 |
PROTECT(oldRVal = R_ReturnedValue);
|
|
|
796 |
oldvis = R_Visible;
|
| 52909 |
luke |
797 |
R_HandlerStack = R_NilValue;
|
| 73171 |
luke |
798 |
R_RestartStack = R_NilValue;
|
| 14634 |
luke |
799 |
saveToplevelContext = R_ToplevelContext;
|
|
|
800 |
|
|
|
801 |
begincontext(&thiscontext, CTXT_TOPLEVEL, R_NilValue, R_GlobalEnv,
|
| 37654 |
ripley |
802 |
R_BaseEnv, R_NilValue, R_NilValue);
|
| 14634 |
luke |
803 |
if (SETJMP(thiscontext.cjmpbuf))
|
|
|
804 |
result = FALSE;
|
|
|
805 |
else {
|
|
|
806 |
R_GlobalContext = R_ToplevelContext = &thiscontext;
|
|
|
807 |
fun(data);
|
|
|
808 |
result = TRUE;
|
|
|
809 |
}
|
|
|
810 |
endcontext(&thiscontext);
|
|
|
811 |
|
|
|
812 |
R_ToplevelContext = saveToplevelContext;
|
|
|
813 |
R_CurrentExpr = topExp;
|
| 52909 |
luke |
814 |
R_HandlerStack = oldHStack;
|
| 73171 |
luke |
815 |
R_RestartStack = oldRStack;
|
|
|
816 |
R_ReturnedValue = oldRVal;
|
|
|
817 |
R_Visible = oldvis;
|
|
|
818 |
UNPROTECT(4);
|
| 14634 |
luke |
819 |
|
|
|
820 |
return result;
|
|
|
821 |
}
|
| 17021 |
duncan |
822 |
|
| 76368 |
urbaneks |
823 |
/* Return the current environment. */
|
| 88921 |
luke |
824 |
/* The _current environment_ is taken to be the top closure call
|
|
|
825 |
environment on the context stack, or .GlobalEnv if there is none.
|
|
|
826 |
An alternative would be the environment in which a .Call or similar
|
|
|
827 |
expression is evaluated. This is currently not recorded; doing so
|
|
|
828 |
would incur some overhead that does not seem warranted.
|
|
|
829 |
*/
|
| 82931 |
ripley |
830 |
SEXP R_GetCurrentEnv(void) {
|
| 88921 |
luke |
831 |
RCNTXT *cptr = R_GlobalContext;
|
|
|
832 |
while (cptr->nextcontext != NULL) {
|
|
|
833 |
if ((cptr->callflag & CTXT_FUNCTION) != 0)
|
|
|
834 |
return cptr->cloenv;
|
|
|
835 |
else cptr = cptr->nextcontext;
|
|
|
836 |
}
|
|
|
837 |
return R_GlobalEnv;
|
| 76368 |
urbaneks |
838 |
}
|
| 17021 |
duncan |
839 |
|
|
|
840 |
|
|
|
841 |
/*
|
|
|
842 |
This is a simple interface for evaluating R expressions
|
| 45446 |
ripley |
843 |
from C with a guarantee that one will return to the
|
| 40779 |
ripley |
844 |
point in the code from which the call was made (if it does
|
|
|
845 |
return at all).
|
| 17021 |
duncan |
846 |
This uses R_TopleveExec to do this. It is important
|
| 45446 |
ripley |
847 |
in applications that embed R or wish to make general
|
| 17021 |
duncan |
848 |
callbacks to R with error handling.
|
|
|
849 |
|
|
|
850 |
It is currently hidden with a data structure definition
|
|
|
851 |
and C routine visible only here. The R_tryEval() is the
|
|
|
852 |
only visible aspect. This can be lifted into the header
|
|
|
853 |
files if necessary. (DTL)
|
| 40779 |
ripley |
854 |
|
|
|
855 |
R_tryEval is in Rinternals.h (so public), but not in the API.
|
| 17021 |
duncan |
856 |
*/
|
|
|
857 |
typedef struct {
|
|
|
858 |
SEXP expression;
|
|
|
859 |
SEXP val;
|
|
|
860 |
SEXP env;
|
|
|
861 |
} ProtectedEvalData;
|
|
|
862 |
|
|
|
863 |
static void
|
|
|
864 |
protectedEval(void *d)
|
|
|
865 |
{
|
|
|
866 |
ProtectedEvalData *data = (ProtectedEvalData *)d;
|
|
|
867 |
SEXP env = R_GlobalEnv;
|
|
|
868 |
if(data->env) {
|
|
|
869 |
env = data->env;
|
|
|
870 |
}
|
| 45446 |
ripley |
871 |
data->val = eval(data->expression, env);
|
| 78127 |
kalibera |
872 |
R_PreserveObject(data->val);
|
| 17021 |
duncan |
873 |
}
|
|
|
874 |
|
|
|
875 |
SEXP
|
|
|
876 |
R_tryEval(SEXP e, SEXP env, int *ErrorOccurred)
|
|
|
877 |
{
|
| 25523 |
luke |
878 |
Rboolean ok;
|
|
|
879 |
ProtectedEvalData data;
|
| 17021 |
duncan |
880 |
|
| 25523 |
luke |
881 |
data.expression = e;
|
|
|
882 |
data.val = NULL;
|
|
|
883 |
data.env = env;
|
| 17021 |
duncan |
884 |
|
| 25523 |
luke |
885 |
ok = R_ToplevelExec(protectedEval, &data);
|
|
|
886 |
if (ErrorOccurred) {
|
|
|
887 |
*ErrorOccurred = (ok == FALSE);
|
|
|
888 |
}
|
|
|
889 |
if (ok == FALSE)
|
|
|
890 |
data.val = NULL;
|
|
|
891 |
else
|
| 78127 |
kalibera |
892 |
R_ReleaseObject(data.val);
|
| 17021 |
duncan |
893 |
|
| 25523 |
luke |
894 |
return(data.val);
|
| 17021 |
duncan |
895 |
}
|
| 52910 |
luke |
896 |
|
|
|
897 |
/* Temporary hack to suppress error message printing around a
|
|
|
898 |
R_tryEval call for use in methods_list_dispatch.c; should be
|
|
|
899 |
replaced once we have a way of establishing error handlers from C
|
|
|
900 |
code (probably would want a calling handler if we want to allow
|
|
|
901 |
user-defined calling handlers to enter a debugger, for
|
|
|
902 |
example). LT */
|
|
|
903 |
SEXP R_tryEvalSilent(SEXP e, SEXP env, int *ErrorOccurred)
|
|
|
904 |
{
|
|
|
905 |
SEXP val;
|
| 87816 |
ripley |
906 |
int oldshow = R_ShowErrorMessages;
|
| 52910 |
luke |
907 |
R_ShowErrorMessages = FALSE;
|
|
|
908 |
val = R_tryEval(e, env, ErrorOccurred);
|
|
|
909 |
R_ShowErrorMessages = oldshow;
|
|
|
910 |
return val;
|
|
|
911 |
}
|
| 64091 |
luke |
912 |
|
|
|
913 |
SEXP R_ExecWithCleanup(SEXP (*fun)(void *), void *data,
|
|
|
914 |
void (*cleanfun)(void *), void *cleandata)
|
|
|
915 |
{
|
|
|
916 |
RCNTXT cntxt;
|
|
|
917 |
SEXP result;
|
|
|
918 |
|
|
|
919 |
begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
|
|
|
920 |
R_NilValue, R_NilValue);
|
|
|
921 |
cntxt.cend = cleanfun;
|
|
|
922 |
cntxt.cenddata = cleandata;
|
|
|
923 |
|
| 78063 |
luke |
924 |
PROTECT(result = fun(data));
|
| 64091 |
luke |
925 |
cleanfun(cleandata);
|
| 78127 |
kalibera |
926 |
endcontext(&cntxt);
|
| 78063 |
luke |
927 |
UNPROTECT(1);
|
| 64091 |
luke |
928 |
|
|
|
929 |
return result;
|
|
|
930 |
}
|
| 73866 |
luke |
931 |
|
|
|
932 |
|
|
|
933 |
/* Unwind-protect mechanism to support C++ stack unwinding. */
|
|
|
934 |
|
|
|
935 |
typedef struct {
|
|
|
936 |
int jumpmask;
|
|
|
937 |
RCNTXT *jumptarget;
|
|
|
938 |
} unwind_cont_t;
|
|
|
939 |
|
| 82931 |
ripley |
940 |
SEXP R_MakeUnwindCont(void)
|
| 73866 |
luke |
941 |
{
|
|
|
942 |
return CONS(R_NilValue, allocVector(RAWSXP, sizeof(unwind_cont_t)));
|
|
|
943 |
}
|
|
|
944 |
|
| 74412 |
luke |
945 |
#define RAWDATA(x) ((void *) RAW0(x))
|
| 73866 |
luke |
946 |
|
| 83454 |
ripley |
947 |
NORET void R_ContinueUnwind(SEXP cont)
|
| 73866 |
luke |
948 |
{
|
|
|
949 |
SEXP retval = CAR(cont);
|
| 74412 |
luke |
950 |
unwind_cont_t *u = RAWDATA(CDR(cont));
|
| 73866 |
luke |
951 |
R_jumpctxt(u->jumptarget, u->jumpmask, retval);
|
|
|
952 |
}
|
|
|
953 |
|
|
|
954 |
SEXP R_UnwindProtect(SEXP (*fun)(void *data), void *data,
|
|
|
955 |
void (*cleanfun)(void *data, Rboolean jump),
|
|
|
956 |
void *cleandata, SEXP cont)
|
|
|
957 |
{
|
|
|
958 |
RCNTXT thiscontext;
|
| 86217 |
luke |
959 |
volatile SEXP result;
|
| 73866 |
luke |
960 |
Rboolean jump;
|
|
|
961 |
|
| 84246 |
maechler |
962 |
/* Allow simple usage with a NULL continuation token. This _could_
|
| 74256 |
luke |
963 |
result in a failure in allocation or exceeding the PROTECT
|
|
|
964 |
stack limit before calling fun(), so fun() and cleanfun should
|
|
|
965 |
be written accordingly. */
|
|
|
966 |
if (cont == NULL) {
|
|
|
967 |
PROTECT(cont = R_MakeUnwindCont());
|
|
|
968 |
result = R_UnwindProtect(fun, data, cleanfun, cleandata, cont);
|
|
|
969 |
UNPROTECT(1);
|
|
|
970 |
return result;
|
|
|
971 |
}
|
|
|
972 |
|
| 73866 |
luke |
973 |
begincontext(&thiscontext, CTXT_UNWIND, R_NilValue, R_GlobalEnv,
|
|
|
974 |
R_BaseEnv, R_NilValue, R_NilValue);
|
|
|
975 |
if (SETJMP(thiscontext.cjmpbuf)) {
|
|
|
976 |
jump = TRUE;
|
|
|
977 |
SETCAR(cont, R_ReturnedValue);
|
| 74412 |
luke |
978 |
unwind_cont_t *u = RAWDATA(CDR(cont));
|
| 73866 |
luke |
979 |
u->jumpmask = thiscontext.jumpmask;
|
|
|
980 |
u->jumptarget = thiscontext.jumptarget;
|
|
|
981 |
thiscontext.jumptarget = NULL;
|
|
|
982 |
}
|
|
|
983 |
else {
|
|
|
984 |
result = fun(data);
|
|
|
985 |
SETCAR(cont, result);
|
|
|
986 |
jump = FALSE;
|
|
|
987 |
}
|
|
|
988 |
endcontext(&thiscontext);
|
|
|
989 |
|
|
|
990 |
cleanfun(cleandata, jump);
|
|
|
991 |
|
|
|
992 |
if (jump)
|
|
|
993 |
R_ContinueUnwind(cont);
|
|
|
994 |
|
|
|
995 |
return result;
|
|
|
996 |
}
|