Skip to content

Commit 3f5cc6f

Browse files
authored
Add simple REPL functionality (#5)
* Add simple REPL functionality * Fix: add return statement to start() * Add -help and use instructions * Refactor code and resolve PR change requests * fix: crash on exit bug solved * refactor help message and input options
1 parent 1d3d361 commit 3f5cc6f

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

examples/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
add_subdirectory(quickstart)
2+
add_subdirectory(repl)

examples/repl/CMakeLists.txt

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
project(kalcy-repl)
2+
3+
add_executable(${PROJECT_NAME})
4+
5+
target_link_libraries(${PROJECT_NAME} PRIVATE
6+
kalcy::kalcy
7+
kalcy::kalcy-compile-options
8+
)
9+
10+
target_sources(${PROJECT_NAME} PRIVATE
11+
repl.cpp
12+
)

examples/repl/repl.cpp

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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

Comments
 (0)