ArkScript
A small, fast, functional and scripting language for video games
Repl.cpp
Go to the documentation of this file.
1 #include <functional>
2 #include <sstream>
3 #include <cstdio>
4 
5 #include <Ark/REPL/Repl.hpp>
7 
8 
9 namespace Ark
10 {
11  Repl::Repl(uint16_t options, const std::vector<std::string>& libenv) :
12  m_options(options), m_lines(1), m_old_ip(0), m_libenv(libenv)
13  {}
14 
15  int Repl::run()
16  {
18  Ark::VM vm(state);
19  state.setDebug(0);
20  std::string code;
21  bool init = false;
22 
24  cui_setup();
25 
26  while (true)
27  {
28  std::stringstream tmp_code;
29  unsigned open_parentheses = 0;
30  unsigned open_braces = 0;
31 
32  tmp_code << code;
33  while (true)
34  {
35  std::string str_lines = "000";
36  if (std::to_string(m_lines).size() < 3)
37  {
38  std::size_t size = std::to_string(m_lines).size();
39  str_lines.replace((str_lines.size() - size), size, std::to_string(m_lines));
40  }
41  else
42  str_lines = std::to_string(m_lines);
43 
44  std::string prompt = "main:" + str_lines + "> ";
45  char const* buf { nullptr };
46  do
47  {
48  buf = m_repl.input(prompt);
49  } while ((buf == nullptr) && (errno == EAGAIN));
50  std::string line = (buf != nullptr) ? std::string(buf) : "";
51 
52  // line history
53  m_repl.history_add(line);
54  trim_whitespace(line);
55 
56  // specific commands handling
57  if (line == "(quit)" || buf == nullptr)
58  {
59  std::cout << "\nExiting REPL\n";
60  return 1;
61  }
62 
63  if (!line.empty())
64  tmp_code << line << "\n";
65  open_parentheses += count_open_parentheses(line);
66  open_braces += count_open_braces(line);
67 
68  // lines number incrementation
69  ++m_lines;
70  if (open_parentheses == 0 && open_braces == 0)
71  break;
72  }
73 
74  // save a valid ip if execution failed
75  m_old_ip = vm.m_execution_contexts[0]->ip;
76  if (!tmp_code.str().empty())
77  {
78  if (state.doString(tmp_code.str()))
79  {
80  // for only one vm init
81  if (init == false)
82  {
83  vm.init();
84  init = true;
85  }
86  if (vm.safeRun(*vm.m_execution_contexts[0]) == 0)
87  {
88  // save good code
89  code = tmp_code.str();
90  // place ip to end of bytecode intruction (HALT)
91  --vm.m_execution_contexts[0]->ip;
92  }
93  else
94  {
95  // reset ip if execution failed
96  vm.m_execution_contexts[0]->ip = m_old_ip;
97  }
98 
99  state.reset();
100  }
101  else
102  std::cout << "Ark::State::doString failed\n";
103  }
104  }
105 
106  return 0;
107  }
108 
110  {
111  std::printf(
112  "ArkScript REPL -- Version %i.%i.%i [LICENSE: Mozilla Public License 2.0]\n"
113  "Type \"(quit)\" to quit.\n",
117  }
118 
119  int Repl::count_open_parentheses(const std::string& line)
120  {
121  int open_parentheses = 0;
122 
123  for (const char& c : line)
124  {
125  switch (c)
126  {
127  case '(': ++open_parentheses; break;
128  case ')': --open_parentheses; break;
129  }
130  }
131 
132  return open_parentheses;
133  }
134 
135  int Repl::count_open_braces(const std::string& line)
136  {
137  int open_braces = 0;
138 
139  for (const char& c : line)
140  {
141  switch (c)
142  {
143  case '{': ++open_braces; break;
144  case '}': --open_braces; break;
145  }
146  }
147 
148  return open_braces;
149  }
150 
151  void Repl::trim_whitespace(std::string& line)
152  {
153  size_t string_begin = line.find_first_not_of(" \t");
154  if (std::string::npos != string_begin)
155  {
156  size_t string_end = line.find_last_not_of(" \t");
157  line = line.substr(string_begin, string_end - string_begin + 1);
158  }
159  }
160 
162  {
163  using namespace std::placeholders;
164 
165  m_repl.set_completion_callback(std::bind(&hook_completion, _1, _2, std::cref(KeywordsDict)));
166  m_repl.set_highlighter_callback(std::bind(&hook_color, _1, _2, std::cref(ColorsRegexDict)));
167  m_repl.set_hint_callback(std::bind(&hook_hint, _1, _2, _3, std::cref(KeywordsDict)));
168 
169  m_repl.set_word_break_characters(" \t.,-%!;:=*~^'\"/?<>|[](){}");
170  m_repl.set_completion_count_cutoff(128);
171  m_repl.set_double_tab_completion(false);
172  m_repl.set_complete_on_empty(true);
173  m_repl.set_beep_on_ambiguous_completion(false);
174  m_repl.set_no_color(false);
175  }
176 }
constexpr int ARK_VERSION_MAJOR
Definition: Constants.hpp:16
constexpr int ARK_VERSION_PATCH
Definition: Constants.hpp:18
constexpr int ARK_VERSION_MINOR
Definition: Constants.hpp:17
ArkScript REPL - Read Eval Print Loop.
replxx utilities
Replxx::completions_t hook_completion(std::string const &context, int &contextLen, std::vector< std::string > const &user_data)
Definition: Utils.cpp:45
void hook_color(std::string const &str, Replxx::colors_t &colors, std::vector< std::pair< std::string, Replxx::Color >> const &user_data)
Definition: Utils.cpp:69
Replxx::hints_t hook_hint(std::string const &context, int &contextLen, Replxx::Color &color, std::vector< std::string > const &examples)
Definition: Utils.cpp:94
void cui_setup()
Definition: Repl.cpp:161
int run()
Start the REPL.
Definition: Repl.cpp:15
Repl(uint16_t options, const std::vector< std::string > &libenv)
Construct a new Repl object.
Definition: Repl.cpp:11
std::vector< std::string > m_libenv
Definition: Repl.hpp:47
int count_open_braces(const std::string &line)
Definition: Repl.cpp:135
uint16_t m_options
Definition: Repl.hpp:43
void trim_whitespace(std::string &line)
Definition: Repl.cpp:151
int count_open_parentheses(const std::string &line)
Definition: Repl.cpp:119
int m_old_ip
Definition: Repl.hpp:46
Replxx m_repl
Definition: Repl.hpp:44
unsigned m_lines
Definition: Repl.hpp:45
void print_repl_header()
Definition: Repl.cpp:109
Ark state to handle the dirty job of loading and compiling ArkScript code.
Definition: State.hpp:31
void reset() noexcept
Reset State (all member variables related to execution)
Definition: State.cpp:340
void setDebug(unsigned level) noexcept
Set the debug level.
Definition: State.cpp:191
bool doString(const std::string &code)
Compile a string (representing ArkScript code) and store resulting bytecode in m_bytecode.
Definition: State.cpp:151
The ArkScript virtual machine, executing ArkScript bytecode.
Definition: VM.hpp:47
std::vector< std::unique_ptr< internal::ExecutionContext > > m_execution_contexts
Definition: VM.hpp:170
int safeRun(internal::ExecutionContext &context, std::size_t untilFrameCount=0)
Run ArkScript bytecode inside a try catch to retrieve all the exceptions and display a stack trace if...
Definition: VM.cpp:267
void init() noexcept
Initialize the VM according to the parameters.
Definition: VM.cpp:35
Definition: Builtins.hpp:21
const std::vector< std::pair< std::string, Replxx::Color > > ColorsRegexDict
const std::vector< std::string > KeywordsDict