|
| 1 | +#include <filesystem> |
| 2 | +#include <fstream> |
1 | 3 | #include <iostream> |
2 | 4 | #include <lbd/repl.h> |
3 | | - |
4 | | -#include "lbd/fe/lexer.h" |
5 | | -#include "lbd/fe/parser.h" |
6 | | -#include "lbd/intp/interpreter.h" |
7 | | - |
8 | | -// TODO: Implement loading a file to repl |
9 | | -// syntax: :load <filepath> or :l <filepath> |
| 5 | +#include <lbd/fe/lexer.h> |
| 6 | +#include <lbd/fe/parser.h> |
| 7 | +#include <lbd/intp/interpreter.h> |
10 | 8 |
|
11 | 9 | namespace repl { |
12 | 10 | static bool force_on_env_dump = false; |
13 | 11 | static bool debug_enabled = false; |
14 | 12 |
|
| 13 | + static std::optional<std::string> read_file(const std::string &filepath) { |
| 14 | + std::ifstream file(filepath); |
| 15 | + if (!file) { |
| 16 | + // Could not open file |
| 17 | + return std::nullopt; |
| 18 | + } |
| 19 | + return std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); |
| 20 | + } |
| 21 | + |
| 22 | + static void process_load_command(const std::string &arg, |
| 23 | + std::optional<std::shared_ptr<intp::interp::Env> > &shared_env) { |
| 24 | + try { |
| 25 | + const std::string filepath = arg; |
| 26 | + if (!std::filesystem::exists(filepath)) { |
| 27 | + std::cerr << "error: filepath " |
| 28 | + << filepath << " does not exist" |
| 29 | + << std::endl; |
| 30 | + return; |
| 31 | + } |
| 32 | + fe::lexer::Lexer lexer(filepath, fe::lexer::FromFile{}); |
| 33 | + const auto tokens = lexer.lex_all(); |
| 34 | + // TODO: Accept Options and Add a debug flag for printing Lexed Tokens |
| 35 | + fe::parser::Parser parser(tokens); |
| 36 | + const std::optional<std::shared_ptr<intp::interp::Env> > temp_env = shared_env; |
| 37 | + // Merge loaded_env into shared_env |
| 38 | + if (const auto [loaded_env, _] = intp::interp::interpret(parser.program, temp_env, {.own_expr = true}); |
| 39 | + loaded_env) { |
| 40 | + if (!shared_env) { |
| 41 | + shared_env = loaded_env; |
| 42 | + } else { |
| 43 | + // Merge all Bindings from loaded_env into shared_env |
| 44 | + for (const auto &[fst, snd]: loaded_env->table) { |
| 45 | + (*shared_env)->bind(fst, snd); |
| 46 | + } |
| 47 | + } |
| 48 | + } |
| 49 | + std::cout << "info: file loaded: " << filepath << std::endl; |
| 50 | + } catch (const std::exception &ex) { |
| 51 | + std::cerr << "error: could not load file: " << ex.what() << std::endl; |
| 52 | + } |
| 53 | + } |
| 54 | + |
15 | 55 | static void help() { |
16 | 56 | std::cout |
17 | 57 | << "available REPL commands:\n" |
18 | 58 | << " general:\n" |
19 | | - << " :q, :quit, :exit Exit the REPL\n" |
20 | | - << " :c, :clear, :cls Clear the screen\n" |
21 | | - << " :h, :help, :? Show this help message\n" |
22 | | - << " :r, :reload Reset environment (forget all bindings)\n" |
23 | | - << " :d, :debug Toggle debug mode\n" |
| 59 | + << " :q, :quit, :exit Exit the REPL\n" |
| 60 | + << " :c, :clear, :cls Clear the screen\n" |
| 61 | + << " :h, :help, :? Show this help message\n" |
| 62 | + << " :l <filepath>, :load <filepath> Load file into REPL\n" |
| 63 | + << " :r, :reload Reset environment (forget all bindings)\n" |
| 64 | + << " :d, :debug Toggle debug mode\n" |
24 | 65 | << " inspection:\n" |
25 | | - << " :e, :env Show all variables in current environment\n" |
26 | | - << " :force Toggle forcing evaluation when dumping env\n" |
| 66 | + << " :e, :env Show all variables in current environment\n" |
| 67 | + << " :force Toggle forcing evaluation when dumping env\n" |
27 | 68 | << "current options:\n" |
28 | | - << " debug [" << (debug_enabled ? "on " : "off") << "] (use :debug to toggle)\n" |
29 | | - << " force-on-env-dump [" << (force_on_env_dump ? "on " : "off") << "] (use :force to toggle)" |
| 69 | + << " debug [" << (debug_enabled ? "on " : "off") << |
| 70 | + "] (use :debug to toggle)\n" |
| 71 | + << " force-on-env-dump [" << (force_on_env_dump ? "on " : "off") << |
| 72 | + "] (use :force to toggle)" |
30 | 73 | << std::endl; |
31 | 74 | } |
32 | 75 |
|
@@ -78,6 +121,14 @@ namespace repl { |
78 | 121 | force_on_env_dump = !force_on_env_dump; |
79 | 122 | continue; |
80 | 123 | } |
| 124 | + if (line.rfind(":load ", 0) == 0) { |
| 125 | + process_load_command(line.substr(6), shared_global_env); |
| 126 | + continue; |
| 127 | + } |
| 128 | + if (line.rfind(":l ", 0) == 0) { |
| 129 | + process_load_command(line.substr(3), shared_global_env); |
| 130 | + continue; |
| 131 | + } |
81 | 132 | if (line.empty()) { |
82 | 133 | continue; |
83 | 134 | } |
|
0 commit comments