/* This should find the caller's environment (it's a .Internal) and then get the context of the call that owns the environment. As it is, it will restart the wrong function if used in a promise. L.T. */ SEXP attribute_hidden do_restart(SEXP call, SEXP op, SEXP args, SEXP rho) { RCNTXT *cptr; checkArity(op, args); if( !isLogical(CAR(args)) || LENGTH(CAR(args))!= 1 ) return(R_NilValue); for(cptr = R_GlobalContext->nextcontext; cptr!= R_ToplevelContext; cptr = cptr->nextcontext) { if (cptr->callflag & CTXT_FUNCTION) { SET_RESTART_BIT_ON(cptr->callflag); break; } } if( cptr == R_ToplevelContext ) error(_("no function to restart")); return(R_NilValue); }
/* browser(text = "", condition = NULL, expr = TRUE, skipCalls = 0L) * ------- but also called from ./eval.c */ SEXP attribute_hidden do_browser(SEXP call, SEXP op, SEXP args, SEXP rho) { RCNTXT *saveToplevelContext; RCNTXT *saveGlobalContext; RCNTXT thiscontext, returncontext, *cptr; int savestack, browselevel; SEXP ap, topExp, argList; /* argument matching */ PROTECT(ap = list4(R_NilValue, R_NilValue, R_NilValue, R_NilValue)); SET_TAG(ap, install("text")); SET_TAG(CDR(ap), install("condition")); SET_TAG(CDDR(ap), install("expr")); SET_TAG(CDDDR(ap), install("skipCalls")); argList = matchArgs(ap, args, call); UNPROTECT(1); PROTECT(argList); /* substitute defaults */ if(CAR(argList) == R_MissingArg) SETCAR(argList, mkString("")); if(CADR(argList) == R_MissingArg) SETCAR(CDR(argList), R_NilValue); if(CADDR(argList) == R_MissingArg) SETCAR(CDDR(argList), ScalarLogical(1)); if(CADDDR(argList) == R_MissingArg) SETCAR(CDDDR(argList), ScalarInteger(0)); /* return if 'expr' is not TRUE */ if( !asLogical(CADDR(argList)) ) { UNPROTECT(1); return R_NilValue; } /* Save the evaluator state information */ /* so that it can be restored on exit. */ browselevel = countContexts(CTXT_BROWSER, 1); savestack = R_PPStackTop; PROTECT(topExp = R_CurrentExpr); saveToplevelContext = R_ToplevelContext; saveGlobalContext = R_GlobalContext; if (!RDEBUG(rho)) { int skipCalls = asInteger(CADDDR(argList)); cptr = R_GlobalContext; while ( ( !(cptr->callflag & CTXT_FUNCTION) || skipCalls--) && cptr->callflag ) cptr = cptr->nextcontext; Rprintf("Called from: "); int tmp = asInteger(GetOption(install("deparse.max.lines"), R_BaseEnv)); if(tmp != NA_INTEGER && tmp > 0) R_BrowseLines = tmp; if( cptr != R_ToplevelContext ) { PrintValueRec(cptr->call, rho); SET_RDEBUG(cptr->cloenv, 1); } else Rprintf("top level \n"); R_BrowseLines = 0; } R_ReturnedValue = R_NilValue; /* Here we establish two contexts. The first */ /* of these provides a target for return */ /* statements which a user might type at the */ /* browser prompt. The (optional) second one */ /* acts as a target for error returns. */ begincontext(&returncontext, CTXT_BROWSER, call, rho, R_BaseEnv, argList, R_NilValue); if (!SETJMP(returncontext.cjmpbuf)) { begincontext(&thiscontext, CTXT_RESTART, R_NilValue, rho, R_BaseEnv, R_NilValue, R_NilValue); if (SETJMP(thiscontext.cjmpbuf)) { SET_RESTART_BIT_ON(thiscontext.callflag); R_ReturnedValue = R_NilValue; R_Visible = FALSE; } R_GlobalContext = &thiscontext; R_InsertRestartHandlers(&thiscontext, TRUE); R_ReplConsole(rho, savestack, browselevel+1); endcontext(&thiscontext); } endcontext(&returncontext); /* Reset the interpreter state. */ R_CurrentExpr = topExp; UNPROTECT(1); R_PPStackTop = savestack; UNPROTECT(1); R_CurrentExpr = topExp; R_ToplevelContext = saveToplevelContext; R_GlobalContext = saveGlobalContext; return R_ReturnedValue; }