18 using namespace internal;
19 using namespace replxx;
21 Repl::Repl(
const std::vector<std::filesystem::path>& lib_env) :
22 m_line_count(1), m_running(true),
23 m_old_ip(0), m_lib_env(lib_env),
24 m_state(m_lib_env), m_vm(m_state), m_has_init_vm(false),
36 ▓▒▓ █▒█ █▒█ █▓▓███████▓█ ██ █▓██ ▓▒█
37 █▒▓ █▒█ █▒█ ▓▒▓ ▓▒█ ▓▓ █▒█ ▓▒▓
38 ▓▒█ █▒█ █▒█ ▓▒▒▒▓▓▓▓▓▓▓▓█ ▓▓ █▓▒▓ ▓▒▓
39 █▓▓ █▒█ ████▒▒▒█ ▓▒▒▓▓▓▓▓▒▓ ▓▓ █▒▓▓▓ █▒█
40 █▓█ █▒▒▓██████████▒█ ▓▒▓ █▒█ ▓▒▓▓█ █▓█ █▓█
41 █▓██ █▓▓▓ █▓█ █▓█ █▓███ █▓█ █▓██ ███
44 fmt::println(R
"(Type "quit" to quit. Try "help" for more information)");
48 if (
const char* arkrc = std::getenv(
"ARKSCRIPT_REPL_STARTUP"))
49 m_code = fmt::format(
"## Loaded via ARKSCRIPT_REPL_STARTUP environment variable: ##\n{}\n## END ##\n",
Utils::readFile(arkrc));
57 if (maybe_block.has_value() && !maybe_block.value().empty())
59 std::string new_code =
m_code + maybe_block.value();
81 fmt::println(
"{}", fmt::styled(maybe_value->
toString(
m_vm), fmt::fg(fmt::color::chocolate)));
100 m_repl.set_completion_callback([
this](
const std::string& ctx,
int& len) {
103 m_repl.set_highlighter_callback([
this](
const std::string& ctx, Replxx::colors_t&
colors) {
106 m_repl.set_hint_callback([
this](
const std::string& ctx,
int& len, Replxx::Color& color) {
110 m_repl.set_word_break_characters(
" \t.,-%!;:=*~^'\"/?<>|[](){}");
111 m_repl.set_completion_count_cutoff(128);
112 m_repl.set_double_tab_completion(
true);
113 m_repl.set_complete_on_empty(
true);
114 m_repl.set_beep_on_ambiguous_completion(
false);
115 m_repl.set_no_color(
false);
117 m_repl.bind_key_internal(Replxx::KEY::HOME,
"move_cursor_to_begining_of_line");
118 m_repl.bind_key_internal(Replxx::KEY::END,
"move_cursor_to_end_of_line");
119 m_repl.bind_key_internal(Replxx::KEY::TAB,
"complete_line");
120 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::LEFT),
"move_cursor_one_word_left");
121 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::RIGHT),
"move_cursor_one_word_right");
122 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::UP),
"hint_previous");
123 m_repl.bind_key_internal(Replxx::KEY::control(Replxx::KEY::DOWN),
"hint_next");
124 m_repl.bind_key_internal(Replxx::KEY::control(
'R'),
"history_incremental_search");
125 m_repl.bind_key_internal(Replxx::KEY::control(
'W'),
"kill_to_begining_of_word");
126 m_repl.bind_key_internal(Replxx::KEY::control(
'U'),
"kill_to_begining_of_line");
127 m_repl.bind_key_internal(Replxx::KEY::control(
'K'),
"kill_to_end_of_line");
128 m_repl.bind_key_internal(Replxx::KEY::control(
'L'),
"clear_screen");
129 m_repl.bind_key_internal(Replxx::KEY::control(
'D'),
"send_eof");
130 m_repl.bind_key_internal(Replxx::KEY::control(
'C'),
"abort_line");
131 m_repl.bind_key_internal(Replxx::KEY::control(
'T'),
"transpose_characters");
136 m_state.
loadFunction(
"repl:history", [
this]([[maybe_unused]]
const std::vector<Value>&, [[maybe_unused]]
VM*) {
147 std::ofstream history_file(n[0].
string());
159 const std::string path = n[0].string();
161 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));
171 const std::string prompt = fmt::format(
"main:{:0>3}{} ",
m_line_count, continuation ?
":" :
">");
173 const char* buf {
nullptr };
176 buf =
m_repl.input(prompt);
177 }
while ((buf ==
nullptr) && (errno == EAGAIN));
178 std::string line = (buf !=
nullptr) ? std::string(buf) :
"";
185 if (line ==
"quit" || buf ==
nullptr)
187 fmt::println(
"\nExiting REPL");
194 fmt::println(
"Available commands:");
195 fmt::println(
" help -- display this message");
196 fmt::println(
" quit -- quit the REPL");
197 fmt::println(
" save -- save the history to disk");
198 fmt::println(
" history -- print saved code");
199 fmt::println(
" reset -- reset the VM state");
200 fmt::println(
"Available builtins:");
201 fmt::println(
" (repl:history): returns the REPL history as a string");
202 fmt::println(
" (repl:save filename): saves the REPL history to a file");
203 fmt::println(
" (repl:load filename): loads code from a file in the REPL");
209 std::ofstream history_file(
"arkscript_repl_history.ark");
210 m_repl.history_save(history_file);
212 fmt::println(
"Saved {} lines of history to arkscript_repl_history.ark",
m_line_count);
215 if (line ==
"history")
217 fmt::println(
"\n{}",
m_code);
234 std::string code_block;
235 long open_parentheses = 0;
236 long open_braces = 0;
240 const bool unfinished_block = open_parentheses != 0 || open_braces != 0;
242 auto maybe_line =
getLine(unfinished_block);
243 if (!maybe_line.has_value() && !unfinished_block)
246 if (maybe_line.has_value() && !maybe_line.value().empty())
248 code_block += maybe_line.value() +
"\n";
254 if (open_parentheses == 0 && open_braces == 0)
Lots of utilities about string, filesystem and more.
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.
bool doString(const std::string &code, uint16_t features=DefaultFeatures, std::ostream *stream=nullptr)
Compile a string (representing ArkScript code) and store resulting bytecode in m_bytecode.
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.
The ArkScript virtual machine, executing ArkScript bytecode.
std::vector< std::unique_ptr< internal::ExecutionContext > > m_execution_contexts
ARK_ALWAYS_INLINE Value * peekAndResolveAsPtr(internal::ExecutionContext &context, std::size_t offset=0)
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.
internal::ExecutionContext * getDefaultContext() const
Return a pointer to the first execution context, for the main thread of the app.
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.
ARK_API long countOpenEnclosures(const std::string &line, char open, char close)
Count the open enclosure and its counterpart: (), {}, [].
ARK_API void trimWhitespace(std::string &line)
Remove whitespaces at the start and end of a string.
std::vector< std::string > getAllKeywords()
Compute a list of all the language keywords and builtins.
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)
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.