See More

#include #include #include #ifdef _WIN32 # include # define fileno _fileno # define dup _dup # define dup2 _dup2 # define close _close # include #else # include #endif #include #include #include #include #include #include #include #include #include #include #include namespace nl = nlohmann; namespace LFortran { class RedirectStdout { public: RedirectStdout(std::string &out) : _out{out} { stdout_fileno = fileno(stdout); std::cout << std::flush; fflush(stdout); saved_stdout = dup(stdout_fileno); #ifdef _WIN32 if (_pipe(out_pipe, 65536, O_BINARY) != 0) { #else if (pipe(out_pipe) != 0) { #endif throw LFortranException("pipe() failed"); } dup2(out_pipe[1], stdout_fileno); close(out_pipe[1]); printf("X"); } ~RedirectStdout() { fflush(stdout); read(out_pipe[0], buffer, MAX_LEN); dup2(saved_stdout, stdout_fileno); _out = std::string(&buffer[1]); } private: std::string &_out; static const size_t MAX_LEN=1024; char buffer[MAX_LEN+1] = {0}; int out_pipe[2]; int saved_stdout; int stdout_fileno; }; class custom_interpreter : public xeus::xinterpreter { private: FortranEvaluator e; public: custom_interpreter() : e{CompilerOptions()} {} virtual ~custom_interpreter() = default; private: void configure_impl() override; nl::json execute_request_impl(int execution_counter, const std::string& code, bool silent, bool store_history, nl::json user_expressions, bool allow_stdin) override; nl::json complete_request_impl(const std::string& code, int cursor_pos) override; nl::json inspect_request_impl(const std::string& code, int cursor_pos, int detail_level) override; nl::json is_complete_request_impl(const std::string& code) override; nl::json kernel_info_request_impl() override; void shutdown_request_impl() override; }; nl::json custom_interpreter::execute_request_impl(int execution_counter, // Typically the cell number const std::string& code, // Code to execute bool /*silent*/, bool /*store_history*/, nl::json /*user_expressions*/, bool /*allow_stdin*/) { FortranEvaluator::EvalResult r; std::string std_out; std::string code0; CompilerOptions cu; try { if (startswith(code, "%%showast")) { code0 = code.substr(code.find("\n")+1); LocationManager lm; diag::Diagnostics diagnostics; Result<:string> res = e.get_ast(code0, lm, diagnostics); nl::json result; if (res.ok) { publish_stream("stdout", res.result); result["status"] = "ok"; result["payload"] = nl::json::array(); result["user_expressions"] = nl::json::object(); } else { std::string msg = diagnostics.render(code0, lm, cu); publish_stream("stderr", msg); result["status"] = "error"; result["ename"] = "CompilerError"; result["evalue"] = msg; result["traceback"] = nl::json::array(); } return result; } if (startswith(code, "%%showasr")) { code0 = code.substr(code.find("\n")+1); LocationManager lm; diag::Diagnostics diagnostics; Result<:string> res = e.get_asr(code0, lm, diagnostics); nl::json result; if (res.ok) { publish_stream("stdout", res.result); result["status"] = "ok"; result["payload"] = nl::json::array(); result["user_expressions"] = nl::json::object(); } else { std::string msg = diagnostics.render(code0, lm, cu); publish_stream("stderr", msg); result["status"] = "error"; result["ename"] = "CompilerError"; result["evalue"] = msg; result["traceback"] = nl::json::array(); } return result; } if (startswith(code, "%%showllvm")) { code0 = code.substr(code.find("\n")+1); LocationManager lm; diag::Diagnostics diagnostics; Result<:string> res = e.get_llvm(code0, lm, diagnostics); nl::json result; if (res.ok) { publish_stream("stdout", res.result); result["status"] = "ok"; result["payload"] = nl::json::array(); result["user_expressions"] = nl::json::object(); } else { std::string msg = diagnostics.render(code0, lm, cu); publish_stream("stderr", msg); result["status"] = "error"; result["ename"] = "CompilerError"; result["evalue"] = msg; result["traceback"] = nl::json::array(); } return result; } if (startswith(code, "%%showasm")) { code0 = code.substr(code.find("\n")+1); LocationManager lm; diag::Diagnostics diagnostics; Result<:string> res = e.get_asm(code0, lm, diagnostics); nl::json result; if (res.ok) { publish_stream("stdout", res.result); result["status"] = "ok"; result["payload"] = nl::json::array(); result["user_expressions"] = nl::json::object(); } else { std::string msg = diagnostics.render(code0, lm, cu); publish_stream("stderr", msg); result["status"] = "error"; result["ename"] = "CompilerError"; result["evalue"] = msg; result["traceback"] = nl::json::array(); } return result; } if (startswith(code, "%%showcpp")) { code0 = code.substr(code.find("\n")+1); LocationManager lm; diag::Diagnostics diagnostics; Result<:string> res = e.get_cpp(code0, lm, diagnostics); nl::json result; if (res.ok) { publish_stream("stdout", res.result); result["status"] = "ok"; result["payload"] = nl::json::array(); result["user_expressions"] = nl::json::object(); } else { std::string msg = diagnostics.render(code0, lm, cu); publish_stream("stderr", msg); result["status"] = "error"; result["ename"] = "CompilerError"; result["evalue"] = msg; result["traceback"] = nl::json::array(); } return result; } if (startswith(code, "%%showfmt")) { code0 = code.substr(code.find("\n")+1); LocationManager lm; diag::Diagnostics diagnostics; Result<:string> res = e.get_fmt(code0, lm, diagnostics); nl::json result; if (res.ok) { publish_stream("stdout", res.result); result["status"] = "ok"; result["payload"] = nl::json::array(); result["user_expressions"] = nl::json::object(); } else { std::string msg = diagnostics.render(code0, lm, cu); publish_stream("stderr", msg); result["status"] = "error"; result["ename"] = "CompilerError"; result["evalue"] = msg; result["traceback"] = nl::json::array(); } return result; } RedirectStdout s(std_out); code0 = code; LocationManager lm; diag::Diagnostics diagnostics; Result<:evalresult> res = e.evaluate(code0, false, lm, diagnostics); if (res.ok) { r = res.result; } else { std::string msg = diagnostics.render(code0, lm, cu); publish_stream("stderr", msg); nl::json result; result["status"] = "error"; result["ename"] = "CompilerError"; result["evalue"] = msg; result["traceback"] = nl::json::array(); return result; } } catch (const LFortranException &e) { publish_stream("stderr", "LFortran Exception: " + e.msg()); nl::json result; result["status"] = "error"; result["ename"] = "LFortranException"; result["evalue"] = e.msg(); result["traceback"] = nl::json::array(); return result; } if (std_out.size() > 0) { publish_stream("stdout", std_out); } switch (r.type) { case (LFortran::FortranEvaluator::EvalResult::integer4) : { nl::json pub_data; pub_data["text/plain"] = std::to_string(r.i32); publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); break; } case (LFortran::FortranEvaluator::EvalResult::integer8) : { nl::json pub_data; pub_data["text/plain"] = std::to_string(r.i64); publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); break; } case (LFortran::FortranEvaluator::EvalResult::real4) : { nl::json pub_data; pub_data["text/plain"] = std::to_string(r.f32); publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); break; } case (LFortran::FortranEvaluator::EvalResult::real8) : { nl::json pub_data; pub_data["text/plain"] = std::to_string(r.f64); publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); break; } case (LFortran::FortranEvaluator::EvalResult::complex4) : { nl::json pub_data; pub_data["text/plain"] = "(" + std::to_string(r.c32.re) + ", " + std::to_string(r.c32.im) + ")"; publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); break; } case (LFortran::FortranEvaluator::EvalResult::complex8) : { nl::json pub_data; pub_data["text/plain"] = "(" + std::to_string(r.c64.re) + ", " + std::to_string(r.c64.im) + ")"; publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); break; } case (LFortran::FortranEvaluator::EvalResult::statement) : { break; } case (LFortran::FortranEvaluator::EvalResult::none) : { break; } default : throw LFortranException("Return type not supported"); } nl::json result; result["status"] = "ok"; result["payload"] = nl::json::array(); result["user_expressions"] = nl::json::object(); return result; } void custom_interpreter::configure_impl() { // Perform some operations } nl::json custom_interpreter::complete_request_impl(const std::string& code, int cursor_pos) { nl::json result; // Code starts with 'H', it could be the following completion if (code[0] == 'H') { result["status"] = "ok"; result["matches"] = {"Hello", "Hey", "Howdy"}; result["cursor_start"] = 5; result["cursor_end"] = cursor_pos; } // No completion result else { result["status"] = "ok"; result["matches"] = nl::json::array(); result["cursor_start"] = cursor_pos; result["cursor_end"] = cursor_pos; } return result; } nl::json custom_interpreter::inspect_request_impl(const std::string& code, int /*cursor_pos*/, int /*detail_level*/) { nl::json result; if (code.compare("print") == 0) { result["found"] = true; result["text/plain"] = "Print objects to the text stream file, [...]"; } else { result["found"] = false; } result["status"] = "ok"; return result; } nl::json custom_interpreter::is_complete_request_impl(const std::string& /*code*/) { nl::json result; // if (is_complete(code)) // { result["status"] = "complete"; // } // else // { // result["status"] = "incomplete"; // result["indent"] = 4; //} return result; } nl::json custom_interpreter::kernel_info_request_impl() { nl::json result; std::string version = LFORTRAN_VERSION; std::string banner = "" "LFortran " + version + "\n" "Jupyter kernel for Fortran"; result["banner"] = banner; result["implementation"] = "LFortran"; result["implementation_version"] = version; result["language_info"]["name"] = "fortran"; result["language_info"]["version"] = "2018"; result["language_info"]["mimetype"] = "text/x-fortran"; result["language_info"]["file_extension"] = ".f90"; return result; } void custom_interpreter::shutdown_request_impl() { std::cout << "Bye!!" << std::endl; } int run_kernel(const std::string &connection_filename) { // Load configuration file xeus::xconfiguration config = xeus::load_configuration(connection_filename); // Create interpreter instance using interpreter_ptr = std::unique_ptr; interpreter_ptr interpreter = interpreter_ptr(new custom_interpreter()); // Create kernel instance and start it xeus::xkernel kernel(config, xeus::get_user_name(), std::move(interpreter)); kernel.start(); return 0; } }