From 00fd962f042c6e5cca28dbb10c35ada3ef7071f7 Mon Sep 17 00:00:00 2001 From: NikolaJelic Date: Fri, 6 Oct 2023 21:27:47 +0200 Subject: [PATCH] Add simple REPL functionality --- examples/CMakeLists.txt | 1 + examples/repl/CMakeLists.txt | 12 ++++++++ examples/repl/repl.cpp | 59 ++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 examples/repl/CMakeLists.txt create mode 100644 examples/repl/repl.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f5bd760..2a869a9 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(quickstart) +add_subdirectory(repl) diff --git a/examples/repl/CMakeLists.txt b/examples/repl/CMakeLists.txt new file mode 100644 index 0000000..37e5ded --- /dev/null +++ b/examples/repl/CMakeLists.txt @@ -0,0 +1,12 @@ +project(kalcy-repl) + +add_executable(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE + kalcy::kalcy + kalcy::kalcy-compile-options +) + +target_sources(${PROJECT_NAME} PRIVATE + repl.cpp +) diff --git a/examples/repl/repl.cpp b/examples/repl/repl.cpp new file mode 100644 index 0000000..6256648 --- /dev/null +++ b/examples/repl/repl.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include + +namespace { +struct Repl { + const std::string_view EXIT_TOKEN{"exit"}; + bool verbose{}; // toggled on with '-v' and off with '-q' + bool is_running{true}; + + auto start() -> bool { + while (is_running) { + std::string text{}; + std::cout << std::format("[{}] > ", verbose ? "verbose" : "quiet"); + std::getline(std::cin, text); + // run kalcy on input expression + if (!run(text)) { return EXIT_FAILURE; } + } + // print epilogue + std::cout << std::format("\n^^ kalcy v{}\n", kalcy::version_v); + } + + auto run(std::string_view const text) -> bool { + try { + // return false when the user enters the exit token + if (text == EXIT_TOKEN) { + is_running = false; + } else if (text == "-v") { + verbose = !verbose; + } else { + // parse text into an expression + auto expr = kalcy::Parser{}.parse(text); + assert(expr != nullptr); + // evaluate parsed expression + // a custom Env can be used and passed, if desired + std::cout << kalcy::evaluate(*expr) << "\n"; + // print AST if verbose + if (verbose) { std::cout << std::format("expression\t: {}\nAST\t\t: {}\n", text, kalcy::to_string(*expr)); } + } + return true; + } catch (kalcy::Error const& err) { + // print error + std::cerr << err.what() << "\n"; + // highlight error location under text + std::cerr << " | " << text << "\n | " << err.build_highlight() << "\n"; + return false; + } + } +}; +} // namespace + +auto main(int argc, char** argv) -> int { + + Repl repl{}; + repl.start(); +}