diff --git a/.gitignore b/.gitignore index 900b95f..c1dc307 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ **/build /.vscode /cpm_modules -.DS_Store \ No newline at end of file +.DS_Store +.idea \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b84c2dd --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,97 @@ +cmake_minimum_required(VERSION 3.16 FATAL_ERROR) + +# ---- Project ---- + +# Note: update this to your new project's name and version +project(xbasic VERSION 1.0 LANGUAGES CXX) + +# ---- Include guards ---- + +if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) + message(FATAL_ERROR "In-source builds not allowed. + Please make a new directory (called a build directory) and run CMake from there.") +endif () + +set(EXECUTABLE_NAME xbasic) + +# Configuration +# ============= + +include(GNUInstallDirs) +# We generate the kernel.json file, given the installation prefix and the executable name +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/share/jupyter/kernels/xbasic/kernel.json.in" + "${CMAKE_CURRENT_SOURCE_DIR}/share/jupyter/kernels/xbasic/kernel.json") + +option(XEUS_STATIC_DEPENDENCIES "link statically with xeus dependencies" OFF) +if (XEUS_STATIC_DEPENDENCIES) + set(xeus_target "xeus-static") +else () + set(xeus_target "xeus") +endif () + +# Dependencies +# ============ + +# Be sure to use recent versions +set(xeus_REQUIRED_VERSION 0.19.1) +set(cppzmq_REQUIRED_VERSION 4.3.0) + +find_package(xeus ${xeus_REQUIRED_VERSION} REQUIRED) +find_package(cppzmq ${cppzmq_REQUIRED_VERSION} REQUIRED) +find_package(Threads) + + +# Flags +# ===== + +include(CheckCXXCompilerFlag) + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") + CHECK_CXX_COMPILER_FLAG("-std=c++17" HAS_CPP17_FLAG) + if (HAS_CPP17_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") + else () + message(FATAL_ERROR "Unsupported compiler -- xeus requires C++17 support!") + endif () +endif () + +# Target and link +# =============== + +if (NOT TARGET basic) + add_subdirectory(libs/basic) +endif () + +# My kernel executable +add_executable(${EXECUTABLE_NAME} "") +target_sources(${EXECUTABLE_NAME} PRIVATE src/main.cc src/xbasic_interpreter.cpp) +target_include_directories(${EXECUTABLE_NAME} + PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include ${CMAKE_CURRENT_LIST_DIR}/libs/basic/include) +target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${xeus_target} Threads::Threads basic) + +if (APPLE) + set_target_properties(${EXECUTABLE_NAME} PROPERTIES MACOSX_RPATH ON) +else () + set_target_properties(${EXECUTABLE_NAME} PROPERTIES + BUILD_WITH_INSTALL_RPATH 1 + SKIP_BUILD_RPATH FALSE) +endif () + +set_target_properties(${EXECUTABLE_NAME} PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) + +# Installation +# ============ + +# Install xbasic +install(TARGETS ${EXECUTABLE_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +# Configuration and data directories for jupyter and xbasic +set(XJUPYTER_DATA_DIR "share/jupyter" CACHE STRING "Jupyter data directory") + +# Install Jupyter kernelspecs +set(xbasicSPEC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/share/jupyter/kernels) +install(DIRECTORY ${xbasicSPEC_DIR} + DESTINATION ${XJUPYTER_DATA_DIR} + PATTERN "*.in" EXCLUDE) diff --git a/include/xbasic/xbasic_interpreter.hpp b/include/xbasic/xbasic_interpreter.hpp new file mode 100644 index 0000000..fdf0044 --- /dev/null +++ b/include/xbasic/xbasic_interpreter.hpp @@ -0,0 +1,40 @@ +#ifndef XBASIC_INTERPRETER_HPP_ +#define XBASIC_INTERPRETER_HPP_ + +#include "basic/basic.hpp" +#include "nlohmann/json.hpp" +#include "xeus/xinterpreter.hpp" + + +using xeus::xinterpreter; +namespace nl = nlohmann; + +namespace xbasic { + + class xbasic_interpreter : public xinterpreter { + private: + basic code_runner; + public: + xbasic_interpreter() = default; + + virtual ~xbasic_interpreter() = default; + + 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; + }; +} // namespace xbasic + +#endif // XBASIC_INTERPRETER_HPP_ \ No newline at end of file diff --git a/share/jupyter/kernels/xbasic/kernel.json b/share/jupyter/kernels/xbasic/kernel.json new file mode 100644 index 0000000..1a8ea48 --- /dev/null +++ b/share/jupyter/kernels/xbasic/kernel.json @@ -0,0 +1,9 @@ +{ + "display_name": "xbasic", + "argv": [ + "/home/avinal/miniconda3/envs/vkurlnel/bin/xbasic", + "-f", + "{connection_file}" + ], + "language": "basic" +} diff --git a/share/jupyter/kernels/xbasic/kernel.json.in b/share/jupyter/kernels/xbasic/kernel.json.in new file mode 100644 index 0000000..d3a4a4e --- /dev/null +++ b/share/jupyter/kernels/xbasic/kernel.json.in @@ -0,0 +1,9 @@ +{ + "display_name": "xbasic", + "argv": [ + "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/@EXECUTABLE_NAME@", + "-f", + "{connection_file}" + ], + "language": "basic" +} \ No newline at end of file diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..bee368e --- /dev/null +++ b/src/main.cc @@ -0,0 +1,19 @@ +#include + +#include "xbasic/xbasic_interpreter.hpp" +#include "xeus/xkernel.hpp" +#include "xeus/xkernel_configuration.hpp" +int main(int argc, char const *argv[]) { + // Load configuration file + std::string file_name = (argc == 1) ? "connection.json" : argv[2]; + xeus::xconfiguration config = xeus::load_configuration(file_name); + + // Create interpreter instance + using interpreter_ptr = std::unique_ptr; + interpreter_ptr interpreter = std::make_unique(); + + // Create kernel instance and start it + xeus::xkernel kernel(config, xeus::get_user_name(), std::move(interpreter)); + kernel.start(); + return 0; +} diff --git a/src/xbasic_interpreter.cpp b/src/xbasic_interpreter.cpp new file mode 100644 index 0000000..651d290 --- /dev/null +++ b/src/xbasic_interpreter.cpp @@ -0,0 +1,90 @@ +#include "xbasic/xbasic_interpreter.hpp" + +std::string basic::output = ""; + +namespace xbasic { + + nl::json xbasic_interpreter::execute_request_impl(int execution_counter, const std::string &code, + bool silent, bool store_history, + nl::json user_expressions, bool allow_stdin) { + auto ok = []() { + nl::json result; + result["status"] = "ok"; + return result; + }; + + std::vector traceback; + auto handle_exception = [&](std::string what) { + nl::json result; + result["status"] = "error"; + result["ename"] = "Error"; + result["evalue"] = what; + traceback.push_back((std::string)result["ename"] + ": " + what); + publish_execution_error(result["ename"], result["evalue"], traceback); + traceback.clear(); + return result; + }; + + nl::json pub_data; + try { + if (code_runner.evaluate_line(code)) { + pub_data["text/plain"] = code_runner.run(); + code_runner.clear_output(); + publish_execution_result(execution_counter, std::move(pub_data), nl::json::object()); + return ok(); + } else { + throw(code_runner.get_error()); + } + } catch (const std::exception &err) { + return handle_exception(err.what()); + } + return ok(); + } + + nl::json xbasic_interpreter::complete_request_impl(const std::string &code, int cursor_pos) { + nl::json result; + result["status"] = "ok"; + return result; + } + + nl::json xbasic_interpreter::inspect_request_impl(const std::string &code, int cursor_pos, + int detail_level) { + nl::json result; + result["status"] = "ok"; + return result; + } + + nl::json xbasic_interpreter::is_complete_request_impl(const std::string &code) { + nl::json result; + result["status"] = "complete"; + return result; + } + + void xbasic_interpreter::configure_impl() {} + + nl::json xbasic_interpreter::kernel_info_request_impl() { + nl::json info; + info["implementation"] = "xbasic"; + info["implementation_version"] = "0.1.0"; + std::string banner = R"V0G0N( + `7MM***Yy. db .M***by. `7MMF' .g8***bg. + MM Yb ;MM: ,MI `Y MM .dP' `M + `7M' `MF' MM .P ,V^MM. `MMb. MM dM' ` + `VA ,V' MMooon* ,M `MM `YMMNq. MM MM + XMX MM `Y. AbmmmqMA . `MM MM MM. + ,V' VA. MM ,9 A' VML Mb dM MM `Mb. .' + .AM. .MA..JMMonal.AMA. .AMMA.`*Ybmmd* .JMML. `*bMond^ + + xeus-basic: a Jupyter Kernel for BASIC Language + xBASIC Version: 0.1.0")V0G0N"; + info["banner"] = banner; + info["language_info"]["name"] = "basic"; + info["langauge_info"]["codemirror_mode"] = "vb"; + info["language_info"]["version"] = "0.1.0"; + info["language_info"]["mimetype"] = "text/x-vb"; + info["language_info"]["file_extension"] = ".bas"; + return info; + } + + void xbasic_interpreter::shutdown_request_impl() {} +} // namespace xbasic