A common need in R frontends is to provide some sort of read, (parse), evaluate, print loop. However, there are also a number of points where frontends may want to differ from the standard REPL as available e.g. in R_ReplDLLdo1(). First some thoughts on what is needed, and what is already there, or missing. If you want to skip over this, a short summary is provided in the second half, below a line marked "--------": Read stage: - R_ReplDLLdo1() calls ReadConsole to fetch an input buffer. This is not well ideally for some situations. For example, the "Console", and the R process may be running on different machines. Or a frontend may provide several consoles or console-alikes working on the same workspace. Or the frontend may want to differentiate between "submitting code to the backend", and answering requests for input from read.line(). Parse stage: - If (due to the above mentioned aspects, or for some other reason), a frontend does not use R_ReplDLLdo1(), it will have to use R_ParseVector() for parsing. There's nothing wrong with that, except for the fact, that there does not seem to be a way to get at the full error message in case of a parse error, as parseError() is not exported. Evaluate stage: - Frontends may want to evaluate a sequence of statements at once, or one at a time. - A typical requirement of a frontend is for evaluation to be guaranteed to return to the point of code it was called from. - Both of this is available using R_tryEval(). Print stage: - Frontends may want to always print the result of evaluation for some statements, they may want to suppress printing entirely for some (internal) statement, but most importantly, they will probably want to auto-print values for most statements (i.e. print them if and only if R_Visible is TRUE). - There does not seem to be a good way (from the C-API) to do auto-printing of values outside of R_ReplDLLdo1(): R_Visible is not exported any longer, and PrintValueEnv() is neither. Rf_PrintValue() should yield the same results as PrintValueEnv() in most, but probably not all cases. - From R API, withVisible() provides a way to emulate auto-printing, but with the drawback that wrapping all statements inside withVisible() makes potential errors harder to read (you get something like "Error in eval.with.vis(x, parent.frame(), baseenv()) :", unless using extra magic to convert the Error magic back to "normal"). Other things done in R_ReplDLLdo1() / other REPLs: - Frontends may want to set R_LastValueSymbol for most (statement entered by the user directly), but not all statements (so as to keep .Last.value unchanged over internal operations like e.g. updating information on an object in an object browser) - Frontends may want to call toplevel handlers after some statements, but not after others (probably a similar distinction). ---------- In summary, it seems like many frontends can not rely on R_ReplDLLdo1() (let alone running run_Rmainloop()), or at least not exclusively so. The alternative, using R_ParseVector() and R_tryEval() also has drawbacks, most importantly problems getting at parse errors, and auto-printing. Two suggestions, which I hope are not too intrusive: 1) Make parseError() part of the public API. If there is a concern that the details of this function may change, a wrapper like the following should be good enough for most, if not all frontend purposes: void Rf_parseErrorDefault() { parseError(R_NilValue, 0); } 2) Add a simple function to do auto-printing to the public API. E.g.: Rboolean Rf_doAutoPrint(SEXP exp) { if(R_Visible) { printValueEnv(exp, R_GlobalEnv); return TRUE; /* was printed */ } return FALSE; } Another suggestion, which might well be seen as adding too many constraints on future development, but provided for completeness: A more generic version of the EPL-part of R_ReplDLLDo1() with function parameters to determine, which steps are taken/omitted. I'm attaching a sketch of this. It is a copy with minimal modifications of the relevant code sections from R_ReplDLLdo1() and friends, which could then be simplified to use this function, internally. Regards Thomas Friedrichsmeier -------------- next part -------------- /* print mode: 0: print if visible. 1: always print 2: never print */ SEXP R_DLLGenericEplDo1 (unsigned char *buffer, ParseStatus *parse_status, Rboolean set_last_sym_value, int print_mode, Rboolean do_toplevel_callbacks) { int c; ParseStatus status; SEXP value; SEXP rho = R_GlobalEnv; Rboolean wasDisplayed = FALSE; while((c = *buffer++)) { R_IoBufferPutc(c, &R_ConsoleIob); if(c == ';' || c == '\n') break; } R_PPStackTop = 0; R_CurrentExpr = R_Parse1Buffer(&R_ConsoleIob, 0, &status); if(parse_status) *parse_status = status; switch(status) { case PARSE_NULL: R_IoBufferWriteReset(&R_ConsoleIob); break; case PARSE_OK: R_IoBufferReadReset(&R_ConsoleIob); R_CurrentExpr = R_Parse1Buffer(&R_ConsoleIob, 1, &status); R_Visible = FALSE; R_EvalDepth = 0; PROTECT(R_CurrentExpr); R_Busy(1); value = eval(R_CurrentExpr, rho); if(set_last_sym_value) SET_SYMVALUE(R_LastvalueSymbol, value); if ((print_mode==1) || (R_Visible && (print_mode==0))) wasDisplayed = TRUE; PrintValueEnv(R_CurrentExpr, rho); if (R_CollectWarnings) PrintWarnings(); if(do_toplevel_callbacks) { Rf_callToplevelHandlers(R_CurrentExpr, value, TRUE, wasDisplayed); } R_CurrentExpr = value; UNPROTECT(1); R_IoBufferWriteReset(&R_ConsoleIob); R_Busy(0); return value; case PARSE_ERROR: parseError(R_NilValue, 0); R_IoBufferWriteReset(&R_ConsoleIob); break; case PARSE_INCOMPLETE: R_IoBufferReadReset(&R_ConsoleIob); break; case PARSE_EOF: break; } return R_NilValue; } -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : https://stat.ethz.ch/pipermail/r-devel/attachments/20070118/e635bb8a/attachment.bin