17 using namespace internal;
18 using namespace replxx;
20 Repl::Repl(
const std::vector<std::filesystem::path>& lib_env) :
21 m_line_count(1), m_running(true),
22 m_old_ip(0), m_lib_env(lib_env),
23 m_state(m_lib_env), m_vm(m_state), m_has_init_vm(false),
31 fmt::println(R
"(Type "quit" to quit. Try "help" for more information)");
35 if (
const char* arkrc = std::getenv(
"ARKSCRIPT_REPL_STARTUP"))
36 m_code = fmt::format(
"## Loaded via ARKSCRIPT_REPL_STARTUP environment variable: ##\n{}\n## END ##\n",
Utils::readFile(arkrc));
44 if (maybe_block.has_value() && !maybe_block.value().empty())
46 std::string new_code =
m_code + maybe_block.value();
68 fmt::println(
"{}", fmt::styled(maybe_value->
toString(
m_vm), fmt::fg(fmt::color::chocolate)));
87 m_repl.set_completion_callback([
this](
const std::string& ctx,
int& len) {
90 m_repl.set_highlighter_callback([
this](
const std::string& ctx, Replxx::colors_t&
colors) {
93 m_repl.set_hint_callback([
this](
const std::string& ctx,
int& len, Replxx::Color& color) {
97 m_repl.set_word_break_characters(
" \t.,-%!;:=*~^'\"/?<>|[](){}");
98 m_repl.set_completion_count_cutoff(128);
99 m_repl.set_double_tab_completion(
true);
100 m_repl.set_complete_on_empty(
true);
101 m_repl.set_beep_on_ambiguous_completion(
false);
102 m_repl.set_no_color(
false);
104 m_repl.bind_key_internal(Replxx::KEY::HOME,
"move_cursor_to_begining_of_line");
105 m_repl.bind_key_internal(Replxx::KEY::END,
"move_cursor_to_end_of_line");
106 m_repl.bind_key_internal(Replxx::KEY::TAB,
"complete_line");
107 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::LEFT),
"move_cursor_one_word_left");
108 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::RIGHT),
"move_cursor_one_word_right");
109 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::UP),
"hint_previous");
110 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::DOWN),
"hint_next");
111 m_repl.bind_key_internal(Replxx::KEY::control(
'R'),
"history_incremental_search");
112 m_repl.bind_key_internal(Replxx::KEY::control(
'W'),
"kill_to_begining_of_word");
113 m_repl.bind_key_internal(Replxx::KEY::control(
'U'),
"kill_to_begining_of_line");
114 m_repl.bind_key_internal(Replxx::KEY::control(
'K'),
"kill_to_end_of_line");
115 m_repl.bind_key_internal(Replxx::KEY::control(
'L'),
"clear_screen");
116 m_repl.bind_key_internal(Replxx::KEY::control(
'D'),
"send_eof");
117 m_repl.bind_key_internal(Replxx::KEY::control(
'C'),
"abort_line");
118 m_repl.bind_key_internal(Replxx::KEY::control(
'T'),
"transpose_characters");
123 m_state.
loadFunction(
"repl:history", [
this]([[maybe_unused]] std::vector<Value>&, [[maybe_unused]]
VM*) {
134 std::ofstream history_file(n[0].
string());
146 const std::string path = n[0].string();
148 throw Error(fmt::format(
"`repl:load` expected a valid path to a file. {} doesn't exist, or can't be reached (try with an absolute path?)", path));
158 const std::string prompt = fmt::format(
"main:{:0>3}{} ",
m_line_count, continuation ?
":" :
">");
160 const char* buf {
nullptr };
163 buf =
m_repl.input(prompt);
164 }
while ((buf ==
nullptr) && (errno == EAGAIN));
165 std::string line = (buf !=
nullptr) ? std::string(buf) :
"";
172 if (line ==
"quit" || buf ==
nullptr)
174 fmt::println(
"\nExiting REPL");
181 fmt::println(
"Available commands:");
182 fmt::println(
" help -- display this message");
183 fmt::println(
" quit -- quit the REPL");
184 fmt::println(
" save -- save the history to disk");
185 fmt::println(
" history -- print saved code");
186 fmt::println(
" reset -- reset the VM state");
187 fmt::println(
"Available builtins:");
188 fmt::println(
" (repl:history): returns the REPL history as a string");
189 fmt::println(
" (repl:save filename): saves the REPL history to a file");
190 fmt::println(
" (repl:load filename): loads code from a file in the REPL");
196 std::ofstream history_file(
"arkscript_repl_history.ark");
197 m_repl.history_save(history_file);
199 fmt::println(
"Saved {} lines of history to arkscript_repl_history.ark",
m_line_count);
202 if (line ==
"history")
204 fmt::println(
"\n{}",
m_code);
221 std::string code_block;
222 long open_parentheses = 0;
223 long open_braces = 0;
227 const bool unfinished_block = open_parentheses != 0 || open_braces != 0;
229 auto maybe_line =
getLine(unfinished_block);
230 if (!maybe_line.has_value() && !unfinished_block)
233 if (maybe_line.has_value() && !maybe_line.value().empty())
235 code_block += maybe_line.value() +
"\n";
241 if (open_parentheses == 0 && open_braces == 0)
Host the declaration of all the ArkScript builtins.
constexpr std::string_view ARK_FULL_VERSION
Lots of utilities about the filesystem.
ArkScript REPL - Read Eval Print Loop.
std::vector< std::pair< std::string, replxx::Replxx::Color > > m_words_colors
std::vector< std::string > m_keywords
void cuiSetup()
Configure replxx.
std::optional< std::string > getCodeBlock()
Prompt the user to enter a complete code block and handle the prompt modifications until the code blo...
std::string m_temp_additional_code
Repl(const std::vector< std::filesystem::path > &lib_env)
Construct a new Repl object.
std::optional< std::string > getLine(bool continuation)
Get a line via replxx and handle commands.
void reset() noexcept
Reset State (all member variables related to execution)
void loadFunction(const std::string &name, Procedure::CallbackType &&function) noexcept
Register a function in the virtual machine.
bool doString(const std::string &code, uint16_t features=DefaultFeatures)
Compile a string (representing ArkScript code) and store resulting bytecode in m_bytecode.
The ArkScript virtual machine, executing ArkScript bytecode.
internal::ExecutionContext * getDefaultContext()
Return a pointer to the first execution context, for the main thread of the app.
std::vector< std::unique_ptr< internal::ExecutionContext > > m_execution_contexts
Value * peekAndResolveAsPtr(internal::ExecutionContext &context)
Return a pointer to the top of the stack without consuming it, and resolve it if possible.
bool forceReloadPlugins() const
Used by the REPL to force reload all the plugins and their bound methods.
int safeRun(internal::ExecutionContext &context, std::size_t untilFrameCount=0, bool fail_with_exception=false)
Run ArkScript bytecode inside a try catch to retrieve all the exceptions and display a stack trace if...
void init() noexcept
Initialize the VM according to the parameters.
ValueType valueType() const noexcept
std::string toString(VM &vm, bool show_as_code=false) const noexcept
std::string readFile(const std::string &name)
Helper to read a file.
bool fileExists(const std::string &name) noexcept
Checks if a file exists.
std::vector< std::string > getAllKeywords()
Compute a list of all the language keywords and builtins.
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)
constexpr std::array colors
replxx::Replxx::completions_t hookCompletion(const std::vector< std::string > &words, const std::string &context, int &length)
std::vector< std::pair< std::string, replxx::Replxx::Color > > getColorPerKeyword()
Compute a list of pairs (word -> color) to be used for coloration by the REPL.
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.
bool check(const std::vector< Value > &args, Ts... types)
Helper to see if a builtin has been given a wanted set of types.
constexpr uint16_t DefaultFeatures
const auto Nil
ArkScript Nil value.
A contract is a list of typed arguments that a function can follow.
A type definition within a contract.