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
15int 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")
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.push_back(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 "\nMisc\n"
160 " sizeof(vector<Ark::Value>) = %zuB\n"
161 " sizeof(std::string) = %zuB\n"
162 " sizeof(String) = %zuB\n"
163 " sizeof(char) = %zuB\n",
165 // value
166 sizeof(Ark::Value),
167 sizeof(Ark::Value::Value_t),
168 sizeof(Ark::ValueType),
169 sizeof(Ark::Value::ProcType),
171 sizeof(Ark::UserType),
172 // vm
173 sizeof(Ark::VM),
174 sizeof(Ark::State),
175 sizeof(Ark::internal::Scope),
176 // misc
177 sizeof(std::vector<Ark::Value>),
178 sizeof(std::string),
179 sizeof(String),
180 sizeof(char));
181 break;
182 }
183
184 case mode::repl:
185 {
186 // send default features without FeatureRemoveUnusedVars to avoid deleting code which will be used later on
188 return repl.run();
189 }
190
191 case mode::compile:
192 {
193 Ark::State state(options, libenv);
194 state.setDebug(debug);
195
196 if (!state.doFile(file))
197 {
198 std::cerr << "Could not compile file at " << file << "\n";
199 return -1;
200 }
201
202 break;
203 }
204
205 case mode::run:
206 {
207 Ark::State state(options, libenv);
208 state.setDebug(debug);
209 state.setArgs(script_args);
210
211 if (!state.doFile(file))
212 {
213 std::cerr << "Could not run file at " << file << "\n";
214 return -1;
215 }
216
217 Ark::VM vm(state);
218 int out = vm.run();
219
220#ifdef ARK_PROFILER_COUNT
221 std::printf(
222 "\n\nValue\n"
223 "=====\n"
224 "\tCreations: %u\n\tCopies: %u\n\tMoves: %u\n\n\tCopy coeff: %f",
225 Ark::internal::value_creations,
226 Ark::internal::value_copies,
227 Ark::internal::value_moves,
228 static_cast<float>(Ark::internal::value_copies) / Ark::internal::value_creations);
229#endif
230
231 return out;
232 }
233
234 case mode::eval:
235 {
236 Ark::State state(options, libenv);
237 state.setDebug(debug);
238
239 if (!state.doString(eval_expresion))
240 {
241 std::cerr << "Could not evaluate expression\n";
242 return -1;
243 }
244
245 Ark::VM vm(state);
246 return vm.run();
247 }
248
249 case mode::bytecode_reader:
250 {
251 try
252 {
254 bcr.feed(file);
255
256 if (bcr_page == max_uint16 && bcr_start == max_uint16)
257 bcr.display(segment);
258 else if (bcr_page != max_uint16 && bcr_start == max_uint16)
259 bcr.display(segment, std::nullopt, std::nullopt, bcr_page);
260 else if (bcr_page == max_uint16 && bcr_start != max_uint16)
261 bcr.display(segment, bcr_start, bcr_end);
262 else
263 bcr.display(segment, bcr_start, bcr_end, bcr_page);
264 }
265 catch (const std::exception& e)
266 {
267 std::printf("%s\n", e.what());
268 }
269 break;
270 }
271 }
272 }
273 else
274 {
275 for (const auto& arg : wrong)
276 std::printf("'%s' ins't a valid argument\n", arg.c_str());
277
278 // clipp only supports streams
279 std::cout << make_man_page(cli, "arkscript", fmt)
280 .prepend_section("DESCRIPTION", " ArkScript programming language")
281 .append_section("LICENSE", " Mozilla Public License 2.0")
282 << std::endl;
283 }
284
285 return 0;
286}
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:46
int run() noexcept
Run the bytecode held in the state.
Definition: VM.cpp:196
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:40
A class to handle the VM scope more efficiently.
Definition: Scope.hpp:28
int main(int argc, char **argv)
Definition: main.cpp:15
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