ArkScript
A small, fast, functional and scripting language for video games
main.cpp
Go to the documentation of this file.
1 #include <cstdio>
2 #include <iostream>
3 #include <optional>
4 #include <filesystem>
5 #include <limits>
6 
7 #include <clipp.h>
8 #define NOMINMAX
9 #include <termcolor/termcolor.hpp>
10 
11 #include <Ark/Ark.hpp>
12 #include <Ark/REPL/Repl.hpp>
13 #include <Ark/Profiling.hpp>
14 
15 int main(int argc, char** argv)
16 {
17  using namespace clipp;
18 
19 // TODO remove once next major version of ArkScript is available
20 #if ARK_VERSION_MAJOR == 4
21 # error "this code block should be removed from ArkScript 4.x.y"
22 #endif
23  {
24  namespace fs = std::filesystem;
25  fs::path program(argv[0]);
26 
27  if (program.stem() == "ark")
28  std::cout << termcolor::yellow << "Warning" << termcolor::reset << " the command `ark' is being deprecated in favor of `arkscript'" << std::endl;
29  }
30 
31 
32  enum class mode
33  {
34  help,
35  dev_info,
36  bytecode_reader,
37  version,
38  run,
39  repl,
40  compile,
41  eval
42  };
43  mode selected = mode::repl;
44  uint16_t options = Ark::DefaultFeatures;
45 
46  std::string file = "",
47  eval_expresion = "";
48 
49  unsigned debug = 0;
50 
51  constexpr uint16_t max_uint16 = std::numeric_limits<uint16_t>::max();
52 
53  uint16_t bcr_page = max_uint16;
54  uint16_t bcr_start = max_uint16;
55  uint16_t bcr_end = max_uint16;
57 
58  std::vector<std::string> wrong, script_args;
59 
60  std::string libdir = "";
61  std::vector<std::string> libenv;
62 
63  // clang-format off
64  auto cli = (
65  option("-h", "--help").set(selected, mode::help).doc("Display this message")
66  | option("-v", "--version").set(selected, mode::version).doc("Display ArkScript version and exit")
67  | option("--dev-info").set(selected, mode::dev_info).doc("Display development information and exit")
68  | (
69  required("-e", "--eval").set(selected, mode::eval).doc("Evaluate ArkScript expression")
70  & value("expression", eval_expresion)
71  )
72  | (
73  required("-c", "--compile").set(selected, mode::compile).doc("Compile the given program to bytecode, but do not run")
74  & value("file", file)
75  , joinable(repeatable(option("-d", "--debug").call([&]{ debug++; }).doc("Increase debug level (default: 0)")))
76  )
77  | (
78  required("-bcr", "--bytecode-reader").set(selected, mode::bytecode_reader).doc("Launch the bytecode reader")
79  & value("file", file)
80  , (
81  option("-on", "--only-names").set(segment, Ark::BytecodeSegment::HeadersOnly).doc("Display only the bytecode segments names and sizes")
82  | (
83  (
84  option("-a", "--all").set(segment, Ark::BytecodeSegment::All).doc("Display all the bytecode segments (default)")
85  | option("-st", "--symbols").set(segment, Ark::BytecodeSegment::Symbols).doc("Display only the symbols table")
86  | option("-vt", "--values").set(segment, Ark::BytecodeSegment::Values).doc("Display only the values table")
87  )
88  , option("-s", "--slice").doc("Select a slice of instructions in the bytecode")
89  & value("start", bcr_start)
90  & value("end", bcr_end)
91  )
92  | (
93  option("-cs", "--code").set(segment, Ark::BytecodeSegment::Code).doc("Display only the code segments")
94  , option("-p", "--page").doc("Set the bytecode reader code segment to display")
95  & value("page", bcr_page)
96  )
97  )
98  )
99  | (
100  value("file", file).set(selected, mode::run)
101  , (
102  joinable(repeatable(option("-d", "--debug").call([&]{ debug++; })))
103  ,
104  // shouldn't change now, the lib option is fine and working
105  (
106  option("-L", "--lib").doc("Set the location of the ArkScript standard library. Paths can be delimited by ';'")
107  & value("lib_dir", libdir)
108  )
109  )
110  , any_other(script_args)
111  )
112  , any_other(wrong)
113  );
114  // clang-format on
115 
116  auto fmt = doc_formatting {}
117  .first_column(8) // column where usage lines and documentation starts
118  .doc_column(36) // parameter docstring start col
119  .indent_size(2) // indent of documentation lines for children of a documented group
120  .split_alternatives(true) // split usage into several lines for large alternatives
121  .merge_alternative_flags_with_common_prefix(true) // [-fok] [-fno-ok] becomes [-f(ok|no-ok)]
122  ;
123 
124  if (parse(argc, argv, cli) && wrong.empty())
125  {
126  using namespace Ark;
127 
128  if (!libdir.empty())
129  libenv = Utils::splitString(libdir, ';');
130 
131  switch (selected)
132  {
133  case mode::help:
134  // clipp only supports streams
135  std::cout << make_man_page(cli, "arkscript", fmt)
136  .prepend_section("DESCRIPTION", " ArkScript programming language")
137  .append_section("LICENSE", " Mozilla Public License 2.0")
138  << std::endl;
139  break;
140 
141  case mode::version:
142  std::printf("Version %i.%i.%i\n", ARK_VERSION_MAJOR, ARK_VERSION_MINOR, ARK_VERSION_PATCH);
143  break;
144 
145  case mode::dev_info:
146  {
147  std::printf(
148  "Have been compiled with %s, options: %s\n\n"
149  "sizeof(Ark::Value) = %zuB\n"
150  " sizeof(Value_t) = %zuB\n"
151  " sizeof(ValueType) = %zuB\n"
152  " sizeof(ProcType) = %zuB\n"
153  " sizeof(Ark::Closure) = %zuB\n"
154  " sizeof(Ark::UserType) = %zuB\n"
155  "\nVirtual Machine\n"
156  "sizeof(Ark::VM) = %zuB\n"
157  " sizeof(Ark::State) = %zuB\n"
158  " sizeof(Ark::Scope) = %zuB\n"
159  " sizeof(ExecutionContext) = %zuB\n"
160  "\nMisc\n"
161  " sizeof(vector<Ark::Value>) = %zuB\n"
162  " sizeof(std::string) = %zuB\n"
163  " sizeof(String) = %zuB\n"
164  " sizeof(char) = %zuB\n",
166  // value
167  sizeof(Ark::Value),
168  sizeof(Ark::Value::Value_t),
169  sizeof(Ark::ValueType),
170  sizeof(Ark::Value::ProcType),
171  sizeof(Ark::internal::Closure),
172  sizeof(Ark::UserType),
173  // vm
174  sizeof(Ark::VM),
175  sizeof(Ark::State),
176  sizeof(Ark::internal::Scope),
178  // misc
179  sizeof(std::vector<Ark::Value>),
180  sizeof(std::string),
181  sizeof(String),
182  sizeof(char));
183  break;
184  }
185 
186  case mode::repl:
187  {
188  // send default features without FeatureRemoveUnusedVars to avoid deleting code which will be used later on
190  return repl.run();
191  }
192 
193  case mode::compile:
194  {
195  Ark::State state(options, libenv);
196  state.setDebug(debug);
197 
198  if (!state.doFile(file))
199  {
200  std::cerr << "Could not compile file at " << file << "\n";
201  return -1;
202  }
203 
204  break;
205  }
206 
207  case mode::run:
208  {
209  Ark::State state(options, libenv);
210  state.setDebug(debug);
211  state.setArgs(script_args);
212 
213  if (!state.doFile(file))
214  {
215  std::cerr << "Could not run file at " << file << "\n";
216  return -1;
217  }
218 
219  Ark::VM vm(state);
220  int out = vm.run();
221 
222 #ifdef ARK_PROFILER_COUNT
223  std::printf(
224  "\n\nValue\n"
225  "=====\n"
226  "\tCreations: %u\n\tCopies: %u\n\tMoves: %u\n\n\tCopy coeff: %f",
227  Ark::internal::value_creations,
228  Ark::internal::value_copies,
229  Ark::internal::value_moves,
230  static_cast<float>(Ark::internal::value_copies) / Ark::internal::value_creations);
231 #endif
232 
233  return out;
234  }
235 
236  case mode::eval:
237  {
238  Ark::State state(options, libenv);
239  state.setDebug(debug);
240 
241  if (!state.doString(eval_expresion))
242  {
243  std::cerr << "Could not evaluate expression\n";
244  return -1;
245  }
246 
247  Ark::VM vm(state);
248  return vm.run();
249  }
250 
251  case mode::bytecode_reader:
252  {
253  try
254  {
256  bcr.feed(file);
257 
258  if (bcr_page == max_uint16 && bcr_start == max_uint16)
259  bcr.display(segment);
260  else if (bcr_page != max_uint16 && bcr_start == max_uint16)
261  bcr.display(segment, std::nullopt, std::nullopt, bcr_page);
262  else if (bcr_page == max_uint16 && bcr_start != max_uint16)
263  bcr.display(segment, bcr_start, bcr_end);
264  else
265  bcr.display(segment, bcr_start, bcr_end, bcr_page);
266  }
267  catch (const std::exception& e)
268  {
269  std::printf("%s\n", e.what());
270  }
271  break;
272  }
273  }
274  }
275  else
276  {
277  for (const auto& arg : wrong)
278  std::printf("'%s' ins't a valid argument\n", arg.c_str());
279 
280  // clipp only supports streams
281  std::cout << make_man_page(cli, "arkscript", fmt)
282  .prepend_section("DESCRIPTION", " ArkScript programming language")
283  .append_section("LICENSE", " Mozilla Public License 2.0")
284  << std::endl;
285  }
286 
287  return 0;
288 }
Includes the needed files to start using ArkScript.
#define ARK_COMPILER
Definition: Constants.hpp:24
constexpr int ARK_VERSION_MAJOR
Definition: Constants.hpp:16
constexpr int ARK_VERSION_PATCH
Definition: Constants.hpp:18
#define ARK_COMPILATION_OPTIONS
Definition: Constants.hpp:23
constexpr int ARK_VERSION_MINOR
Definition: Constants.hpp:17
ArkScript REPL - Read Eval Print Loop.
This class is just a helper to.
void display(BytecodeSegment segment=BytecodeSegment::All, std::optional< uint16_t > sStart=std::nullopt, std::optional< uint16_t > sEnd=std::nullopt, std::optional< uint16_t > cPage=std::nullopt)
Display the bytecode opcode in a human friendly way.
void feed(const std::string &file)
Construct needed data before displaying information about a given file.
int run()
Start the REPL.
Definition: Repl.cpp:15
Ark state to handle the dirty job of loading and compiling ArkScript code.
Definition: State.hpp:31
void setArgs(const std::vector< std::string > &args) noexcept
Set the script arguments in sys:args.
Definition: State.cpp:181
void setDebug(unsigned level) noexcept
Set the debug level.
Definition: State.cpp:191
bool doFile(const std::string &filename)
Compile a file, and use the resulting bytecode.
Definition: State.cpp:110
bool doString(const std::string &code)
Compile a string (representing ArkScript code) and store resulting bytecode in m_bytecode.
Definition: State.cpp:151
A class to be use C++ objects in ArkScript.
Definition: UserType.hpp:50
The ArkScript virtual machine, executing ArkScript bytecode.
Definition: VM.hpp:47
int run() noexcept
Run the bytecode held in the state.
Definition: VM.cpp:252
Value(*)(std::vector< Value > &, VM *) ProcType
Definition: Value.hpp:74
std::variant< double, String, internal::PageAddr_t, ProcType, internal::Closure, UserType, std::vector< Value >, Value * > Value_t
Definition: Value.hpp:87
Closure management.
Definition: Closure.hpp:45
A class to handle the VM scope more efficiently.
Definition: Scope.hpp:28
int main(int argc, char **argv)
Definition: main.cpp:15
std::vector< std::string > splitString(const std::string &source, char sep)
Cut a string into pieces, given a character separator.
Definition: Utils.hpp:34
Definition: Builtins.hpp:21
constexpr uint16_t DefaultFeatures
Definition: Constants.hpp:51
ValueType
Definition: Value.hpp:40
constexpr uint16_t FeatureRemoveUnusedVars
Definition: Constants.hpp:48