|
| 1 | +#include <kalcy/kalcy.hpp> |
| 2 | +#include <cassert> |
| 3 | +#include <format> |
| 4 | +#include <iomanip> |
| 5 | +#include <iostream> |
| 6 | +#include <sstream> |
| 7 | + |
| 8 | +namespace { |
| 9 | +struct Repl { |
| 10 | + bool verbose{}; // toggled on with '-v' and off with '-q' |
| 11 | + bool is_running{true}; |
| 12 | + kalcy::Parser parser{}; |
| 13 | + |
| 14 | + auto print_help() const -> void { |
| 15 | + std::cout << "Usage: [OPTION] | [EXPRESSION]\n"; |
| 16 | + std::cout << "\nDescription:\n\n"; |
| 17 | + std::cout << std::format(" {:<15} {}\n", "-h, --help", "Display this help message, providing information about available options."); |
| 18 | + std::cout << std::format(" {:<15} {}\n", "-v, --verbose", "Toggle verbose mode to control the level of detail in the output."); |
| 19 | + std::cout << std::format(" {:<15} {}\n\n", "exit", "Terminate the REPL input loop."); |
| 20 | + } |
| 21 | + |
| 22 | + auto start() -> void { |
| 23 | + while (is_running) { |
| 24 | + auto text = std::string{}; |
| 25 | + std::cout << std::format("{} > ", verbose ? "[verbose]" : ""); |
| 26 | + std::getline(std::cin, text); |
| 27 | + // run kalcy on input expression |
| 28 | + if (!text.empty()) { |
| 29 | + run(text); |
| 30 | + } else { |
| 31 | + print_help(); |
| 32 | + } |
| 33 | + } |
| 34 | + // print epilogue |
| 35 | + std::cout << std::format("\n^^ kalcy v{}\n", kalcy::version_v); |
| 36 | + } |
| 37 | + |
| 38 | + auto run(std::string_view const text) -> bool { |
| 39 | + try { |
| 40 | + if (text == "exit") { |
| 41 | + is_running = false; |
| 42 | + return true; |
| 43 | + } |
| 44 | + |
| 45 | + if (text == "-h" || text == "--help") { |
| 46 | + print_help(); |
| 47 | + return true; |
| 48 | + } |
| 49 | + |
| 50 | + if (text == "-v" || text == "--verbose") { |
| 51 | + verbose = !verbose; |
| 52 | + return true; |
| 53 | + } |
| 54 | + // parse text into an expression |
| 55 | + auto expr = parser.parse(text); |
| 56 | + assert(expr != nullptr); |
| 57 | + // evaluate parsed expression |
| 58 | + // a custom Env can be used and passed, if desired |
| 59 | + std::cout << kalcy::evaluate(*expr) << "\n"; |
| 60 | + // print AST if verbose |
| 61 | + if (verbose) { std::cout << std::format("expression\t: {}\nAST\t\t: {}\n", text, kalcy::to_string(*expr)); } |
| 62 | + return true; |
| 63 | + |
| 64 | + } catch (kalcy::Error const& err) { |
| 65 | + // print error |
| 66 | + std::cerr << err.what() << "\n"; |
| 67 | + // highlight error location under text |
| 68 | + std::cerr << " | " << text << "\n | " << err.build_highlight() << "\n"; |
| 69 | + return false; |
| 70 | + } |
| 71 | + } |
| 72 | +}; |
| 73 | +} // namespace |
| 74 | + |
| 75 | +auto main() -> int { |
| 76 | + |
| 77 | + Repl repl{}; |
| 78 | + try { |
| 79 | + repl.start(); |
| 80 | + } catch (std::exception const& e) { std::cerr << e.what() << "\n"; } |
| 81 | +} |
0 commit comments