Skip to content

Commit

Permalink
evaluate expressions, and print() with visibility handling (#8)
Browse files Browse the repository at this point in the history
* eval and print all expressions

* SPACE

* handle stop()
  • Loading branch information
romainfrancois authored Oct 9, 2023
1 parent acc134a commit 8a77f39
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 11 deletions.
2 changes: 2 additions & 0 deletions include/xeus-r/xinterpreter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ namespace xeus_r
interpreter(int argc, char* argv[]);
virtual ~interpreter() = default;

std::stringstream capture_stream;

protected:

void configure_impl() override;
Expand Down
70 changes: 59 additions & 11 deletions src/xinterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include "R_ext/Parse.h"
#include "Rinterface.h"

extern Rboolean R_Visible;

namespace xeus_r {

static interpreter* p_interpreter = nullptr;
Expand All @@ -40,6 +42,15 @@ void WriteConsoleEx(const char *buf, int buflen, int otype) {
}
}

void capture_WriteConsoleEx(const char *buf, int buflen, int otype) {
std::string output(buf, buflen);
if (otype == 1) {
// do nothing
} else {
p_interpreter->capture_stream << output;
}
}

namespace {

SEXP try_parse(const std::string& code, int execution_counter) {
Expand Down Expand Up @@ -99,9 +110,7 @@ SEXP try_parse(const std::string& code, int execution_counter) {
nl::json /*user_expressions*/,
bool /*allow_stdin*/)
{

nl::json kernel_res;

// First we need to parse the code
SEXP parsed = PROTECT(try_parse(code, execution_counter));
if (Rf_inherits(parsed, "error")) {
auto err_msg = CHAR(STRING_ELT(VECTOR_ELT(parsed, 0),0));
Expand All @@ -111,14 +120,53 @@ SEXP try_parse(const std::string& code, int execution_counter) {
return xeus::create_error_reply();
}

// TODO: wrap in a tryCatch
// TODO: eval not just the first, but all
SEXP out = PROTECT(Rf_eval(VECTOR_ELT(parsed, 0), R_GlobalEnv));

// echo the code for now
nl::json pub_data;
pub_data["text/plain"] = "bonjour"; // REAL(out)[0];
// publish_execution_result(execution_counter, std::move(pub_data), nl::json::object());
R_xlen_t n = XLENGTH(parsed);
int ErrorOccurred;
SEXP smb_withVisible = Rf_install("withVisible");

for (R_xlen_t i = 0; i < n; i++) {
// wrap the call in a `withVisible()` so that we can figure out
// its visibility. It seems we cannot use the internal R way of
// doing this with the R_Visible extern variable :shrug:
SEXP expr = PROTECT(Rf_lang2(smb_withVisible, VECTOR_ELT(parsed, i)));
SEXP result = PROTECT(R_tryEval(expr, R_GlobalEnv, &ErrorOccurred));

if (!ErrorOccurred) {
// We get a list of two things:
// 1) the result: can be any R object
SEXP value = PROTECT(VECTOR_ELT(result, 0));

// 2) whether it is visible: a scalar LGLSXP
bool visible = LOGICAL(VECTOR_ELT(result, 1))[0];

if (visible) {
// the code did not generate an uncaught error and
// the rsult is visible, so we need to display it
//
// For now, this means print() it which we do by
// calling the internal print() function Rf_PrintValue
// and intercept what would be printed in the console
// using capture_WriteConsoleEx instead of the regular
// WriteConsoleEx
capture_stream.str("");
ptr_R_WriteConsoleEx = capture_WriteConsoleEx;
R_ToplevelExec([](void* value) {
Rf_PrintValue((SEXP)value);
}, (void*)value);

// restore the normal printing to the console
ptr_R_WriteConsoleEx = WriteConsoleEx;

nl::json pub_data;
pub_data["text/plain"] = capture_stream.str();
publish_execution_result(execution_counter, std::move(pub_data), nl::json::object());
}

UNPROTECT(1); // value
}

UNPROTECT(2); // expr, result
}

UNPROTECT(2); // parsed, out

Expand Down

0 comments on commit 8a77f39

Please sign in to comment.