14 using namespace internal;
15 using namespace replxx;
17 Repl::Repl(
const std::vector<std::filesystem::path>& lib_env) :
18 m_line_count(1), m_running(true),
19 m_old_ip(0), m_lib_env(lib_env),
20 m_state(m_lib_env), m_vm(m_state), m_has_init_vm(false)
22 m_keywords.reserve(
keywords.size() + Language::listInstructions.size() + Language::operators.size() + Builtins::builtins.size() + 2);
23 for (
auto keyword : keywords)
24 m_keywords.emplace_back(keyword);
25 for (
auto inst : Language::listInstructions)
26 m_keywords.emplace_back(inst);
27 for (
auto op : Language::operators)
28 m_keywords.emplace_back(op);
29 for (
const auto& builtin : std::ranges::views::keys(Builtins::builtins))
30 m_keywords.push_back(builtin);
31 m_keywords.emplace_back(
"and");
32 m_keywords.emplace_back(
"or");
34 m_words_colors.reserve(
keywords.size() + Language::listInstructions.size() + Language::operators.size() + Builtins::builtins.size() + 4);
35 for (
auto keyword : keywords)
36 m_words_colors.emplace_back(keyword, Replxx::Color::BRIGHTRED);
37 for (
auto inst : Language::listInstructions)
38 m_words_colors.emplace_back(inst, Replxx::Color::GREEN);
39 for (
auto op : Language::operators)
41 auto safe_op = std::string(op);
42 if (
const auto it = safe_op.find_first_of(R
"(-+=/*<>[]()?")"); it != std::string::npos)
43 safe_op.insert(it, "\\");
44 m_words_colors.emplace_back(safe_op, Replxx::Color::BRIGHTBLUE);
46 for (
const auto& builtin : std::ranges::views::keys(Builtins::builtins))
47 m_words_colors.emplace_back(builtin, Replxx::Color::GREEN);
49 m_words_colors.emplace_back(
"and", Replxx::Color::BRIGHTBLUE);
50 m_words_colors.emplace_back(
"or", Replxx::Color::BRIGHTBLUE);
51 m_words_colors.emplace_back(
"[\\-|+]?[0-9]+(\\.[0-9]+)?", Replxx::Color::YELLOW);
52 m_words_colors.emplace_back(
"\".*\"", Replxx::Color::MAGENTA);
57 fmt::print(
"ArkScript REPL -- Version {} [LICENSE: Mozilla Public License 2.0]\nType \"quit\" to quit. Try \"help\" for more information\n",
ARK_FULL_VERSION);
62 auto maybe_block = getCodeBlock();
65 m_old_ip = m_vm.m_execution_contexts[0]->ip;
66 if (maybe_block.has_value() && !maybe_block.value().empty())
68 std::string new_code = m_code + maybe_block.value();
69 if (m_state.doString(new_code))
78 std::ignore = m_vm.forceReloadPlugins();
80 if (m_vm.safeRun(*m_vm.m_execution_contexts[0]) == 0)
85 m_vm.m_execution_contexts[0]->ip -= 4;
90 m_vm.m_execution_contexts[0]->ip = m_old_ip;
96 fmt::println(
"\nCouldn't run code");
103 void Repl::cuiSetup()
105 m_repl.set_completion_callback([
this](
const std::string& ctx,
int& len) {
108 m_repl.set_highlighter_callback([
this](
const std::string& ctx, Replxx::colors_t& colors) {
109 return hookColor(m_words_colors, ctx, colors);
111 m_repl.set_hint_callback([
this](
const std::string& ctx,
int& len, Replxx::Color& color) {
112 return hookHint(m_keywords, ctx, len, color);
115 m_repl.set_word_break_characters(
" \t.,-%!;:=*~^'\"/?<>|[](){}");
116 m_repl.set_completion_count_cutoff(128);
117 m_repl.set_double_tab_completion(
true);
118 m_repl.set_complete_on_empty(
true);
119 m_repl.set_beep_on_ambiguous_completion(
false);
120 m_repl.set_no_color(
false);
122 m_repl.bind_key_internal(Replxx::KEY::HOME,
"move_cursor_to_begining_of_line");
123 m_repl.bind_key_internal(Replxx::KEY::END,
"move_cursor_to_end_of_line");
124 m_repl.bind_key_internal(Replxx::KEY::TAB,
"complete_line");
125 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::LEFT),
"move_cursor_one_word_left");
126 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::RIGHT),
"move_cursor_one_word_right");
127 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::UP),
"hint_previous");
128 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::DOWN),
"hint_next");
129 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::ENTER),
"commit_line");
130 m_repl.bind_key_internal(Replxx::KEY::control(
'R'),
"history_incremental_search");
131 m_repl.bind_key_internal(Replxx::KEY::control(
'W'),
"kill_to_begining_of_word");
132 m_repl.bind_key_internal(Replxx::KEY::control(
'U'),
"kill_to_begining_of_line");
133 m_repl.bind_key_internal(Replxx::KEY::control(
'K'),
"kill_to_end_of_line");
134 m_repl.bind_key_internal(Replxx::KEY::control(
'Y'),
"yank");
135 m_repl.bind_key_internal(Replxx::KEY::control(
'L'),
"clear_screen");
136 m_repl.bind_key_internal(Replxx::KEY::control(
'D'),
"send_eof");
137 m_repl.bind_key_internal(Replxx::KEY::control(
'C'),
"abort_line");
138 m_repl.bind_key_internal(Replxx::KEY::control(
'T'),
"transpose_characters");
141 std::optional<std::string> Repl::getLine(
const bool continuation)
143 const std::string prompt = fmt::format(
"main:{:0>3}{} ", m_line_count, continuation ?
":" :
">");
145 const char* buf {
nullptr };
148 buf = m_repl.input(prompt);
149 }
while ((buf ==
nullptr) && (errno == EAGAIN));
150 std::string line = (buf !=
nullptr) ? std::string(buf) :
"";
153 m_repl.history_add(line);
157 if (line ==
"quit" || buf ==
nullptr)
159 fmt::println(
"\nExiting REPL");
166 fmt::println(
"Available commands:");
167 fmt::println(
" help -- display this message");
168 fmt::println(
" quit -- quit the REPL");
169 fmt::println(
" save -- save the history to disk");
170 fmt::println(
" history -- print saved code");
171 fmt::println(
" reset -- reset the VM state");
177 std::ofstream history_file(
"arkscript_repl_history.ark");
178 m_repl.history_save(history_file);
180 fmt::println(
"Saved {} lines of history to arkscript_repl_history.ark", m_line_count);
183 if (line ==
"history")
185 fmt::println(
"\n{}", m_code);
191 m_has_init_vm =
false;
200 std::optional<std::string> Repl::getCodeBlock()
202 std::string code_block;
203 long open_parentheses = 0;
204 long open_braces = 0;
208 const bool unfinished_block = open_parentheses != 0 || open_braces != 0;
210 auto maybe_line = getLine(unfinished_block);
211 if (!maybe_line.has_value() && !unfinished_block)
214 if (maybe_line.has_value() && !maybe_line.value().empty())
216 code_block += maybe_line.value() +
"\n";
222 if (open_parentheses == 0 && open_braces == 0)
Host the declaration of all the ArkScript builtins.
Common code for the compiler.
constexpr std::string_view ARK_FULL_VERSION
ArkScript REPL - Read Eval Print Loop.
Repl(const std::vector< std::filesystem::path > &lib_env)
Construct a new Repl object.
long countOpenEnclosures(const std::string &line, char open, char close)
Count the open enclosure and its counterpart: (), {}, [].
void hookColor(const std::vector< std::pair< std::string, replxx::Replxx::Color > > &words_colors, const std::string &context, replxx::Replxx::colors_t &colors)
replxx::Replxx::completions_t hookCompletion(const std::vector< std::string > &words, const std::string &context, int &length)
replxx::Replxx::hints_t hookHint(const std::vector< std::string > &words, const std::string &context, int &length, replxx::Replxx::Color &color)
void trimWhitespace(std::string &line)
Remove whitespaces at the start and end of a string.
constexpr std::array< std::string_view, 9 > keywords
List of available keywords in ArkScript.