ArkScript
A small, fast, functional and scripting language for video games
Compiler.hpp
Go to the documentation of this file.
1/**
2 * @file Compiler.hpp
3 * @author Alexandre Plateau ([email protected])
4 * @brief ArkScript compiler is in charge of transforming the AST into bytecode
5 * @version 2.1
6 * @date 2020-10-27
7 *
8 * @copyright Copyright (c) 2020-2024
9 *
10 */
11
12#ifndef ARK_COMPILER_COMPILER_HPP
13#define ARK_COMPILER_COMPILER_HPP
14
15#include <vector>
16#include <string>
17#include <cinttypes>
18#include <optional>
19
20#include <Ark/Platform.hpp>
22#include <Ark/Compiler/Word.hpp>
25
26namespace Ark
27{
28 class State;
29 class Welder;
30
31 /**
32 * @brief The ArkScript bytecode compiler
33 *
34 */
36 {
37 public:
38 /**
39 * @brief Construct a new Compiler object
40 *
41 * @param debug the debug level
42 */
43 explicit Compiler(unsigned debug);
44
45 /**
46 * @brief Start the compilation
47 *
48 * @param ast
49 */
50 void process(const internal::Node& ast);
51
52 /**
53 * @brief Return the constructed bytecode object
54 *
55 * @return const bytecode_t&
56 */
57 [[nodiscard]] const bytecode_t& bytecode() const noexcept;
58
59 friend class State;
60 friend class Welder;
61
62 private:
63 // tables: symbols, values, plugins and codes
64 std::vector<internal::Node> m_symbols;
65 std::vector<std::string> m_defined_symbols;
66 std::vector<std::string> m_plugins;
67 std::vector<internal::ValTableElem> m_values;
68 std::vector<std::vector<internal::Word>> m_code_pages;
69 std::vector<std::vector<internal::Word>> m_temp_pages; ///< we need temporary code pages for some compilations passes
70
72 unsigned m_debug; ///< the debug level of the compiler
73
74 /**
75 * @brief Push the file headers (magic, version used, timestamp)
76 *
77 */
78 void pushFileHeader() noexcept;
79
80 /**
81 * @brief Push the symbols and values tables
82 *
83 */
84 void pushSymAndValTables();
85
86 /**
87 * @brief helper functions to get a temp or finalized code page
88 *
89 * @param i page index, if negative, refers to a temporary code page
90 * @return std::vector<internal::Word>&
91 */
92 std::vector<internal::Word>& page(const int i) noexcept
93 {
94 if (i >= 0)
95 return m_code_pages[i];
96 return m_temp_pages[-i - 1];
97 }
98
99 /**
100 * @brief helper functions to get a temp or finalized code page
101 *
102 * @param i page index, if negative, refers to a temporary code page
103 * @return std::vector<internal::Word>*
104 */
105 std::vector<internal::Word>* page_ptr(const int i) noexcept
106 {
107 if (i >= 0)
108 return &m_code_pages[i];
109 return &m_temp_pages[-i - 1];
110 }
111
112 /**
113 * @brief Checking if a symbol is an operator
114 *
115 * @param name symbol name
116 * @return std::optional<std::size_t> position in the operators' list
117 */
118 static std::optional<std::size_t> getOperator(const std::string& name) noexcept;
119
120 /**
121 * @brief Checking if a symbol is a builtin
122 *
123 * @param name symbol name
124 * @return std::optional<std::size_t> position in the builtins' list
125 */
126 static std::optional<std::size_t> getBuiltin(const std::string& name) noexcept;
127
128 /**
129 * @brief Check if a symbol needs to be compiled to a specific instruction
130 *
131 * @param name
132 * @return std::optional<internal::Instruction> corresponding instruction if it exists
133 */
134 static std::optional<internal::Instruction> getSpecific(const std::string& name) noexcept
135 {
136 if (name == "list")
137 return internal::Instruction::LIST;
138 if (name == "append")
139 return internal::Instruction::APPEND;
140 if (name == "concat")
141 return internal::Instruction::CONCAT;
142 if (name == "append!")
143 return internal::Instruction::APPEND_IN_PLACE;
144 if (name == "concat!")
145 return internal::Instruction::CONCAT_IN_PLACE;
146 if (name == "pop")
147 return internal::Instruction::POP_LIST;
148 if (name == "pop!")
149 return internal::Instruction::POP_LIST_IN_PLACE;
150
151 return std::nullopt;
152 }
153
154 /**
155 * @brief Check if a given instruction is unary (takes only one argument)
156 *
157 * @param inst
158 * @return true the instruction is unary
159 * @return false
160 */
161 static bool isUnaryInst(internal::Instruction inst) noexcept;
162
163 /**
164 * @brief Compute specific instruction argument count
165 *
166 * @param inst
167 * @param previous
168 */
169 static uint16_t computeSpecificInstArgc(internal::Instruction inst, uint16_t previous) noexcept;
170
171 /**
172 * @brief Checking if a symbol may be coming from a plugin
173 *
174 * @param name symbol name
175 * @return true the symbol may be from a plugin, loaded at runtime
176 * @return false
177 */
178 bool mayBeFromPlugin(const std::string& name) noexcept;
179
180 /**
181 * @brief Display a warning message
182 *
183 * @param message
184 * @param node
185 */
186 static void compilerWarning(const std::string& message, const internal::Node& node);
187
188 /**
189 * @brief Throw a nice error message
190 *
191 * @param message
192 * @param node
193 */
194 [[noreturn]] static void throwCompilerError(const std::string& message, const internal::Node& node);
195
196 /**
197 * @brief Compile an expression (a node) recursively
198 *
199 * @param x the internal::Node to compile
200 * @param p the current page number we're on
201 * @param is_result_unused
202 * @param is_terminal
203 * @param var_name
204 */
205 void compileExpression(const internal::Node& x, int p, bool is_result_unused, bool is_terminal, const std::string& var_name = "");
206
207 void compileSymbol(const internal::Node& x, int p, bool is_result_unused);
208 void compileSpecific(const internal::Node& c0, const internal::Node& x, int p, bool is_result_unused);
209 void compileIf(const internal::Node& x, int p, bool is_result_unused, bool is_terminal, const std::string& var_name);
210 void compileFunction(const internal::Node& x, int p, bool is_result_unused, const std::string& var_name);
211 void compileLetMutSet(internal::Keyword n, const internal::Node& x, int p);
212 void compileWhile(const internal::Node& x, int p);
213 void compilePluginImport(const internal::Node& x, int p);
214 void handleCalls(const internal::Node& x, int p, bool is_result_unused, bool is_terminal, const std::string& var_name);
215
216 /**
217 * @brief Register a given node in the symbol table
218 * @details Can throw if the table is full
219 *
220 * @param sym
221 * @return uint16_t
222 */
223 uint16_t addSymbol(const internal::Node& sym);
224
225 /**
226 * @brief Register a given node in the value table
227 * @details Can throw if the table is full
228 *
229 * @param x
230 * @return uint16_t
231 */
232 uint16_t addValue(const internal::Node& x);
233
234 /**
235 * @brief Register a page id (function reference) in the value table
236 * @details Can throw if the table is full
237 *
238 * @param page_id
239 * @param current A reference to the current node, for context
240 * @return std::size_t
241 */
242 uint16_t addValue(std::size_t page_id, const internal::Node& current);
243
244 /**
245 * @brief Register a symbol as defined, so that later we can throw errors on undefined symbols
246 *
247 * @param sym
248 */
249 void addDefinedSymbol(const std::string& sym);
250
251 /**
252 * @brief Checks for undefined symbols, not present in the defined symbols table
253 *
254 */
255 void checkForUndefinedSymbol();
256
257 /**
258 * @brief Suggest a symbol of what the user may have meant to input
259 *
260 * @param str the string
261 * @return std::string
262 */
263 std::string offerSuggestion(const std::string& str) const;
264 };
265}
266
267#endif
The different instructions used by the compiler and virtual machine.
#define ARK_API
Definition: Module.hpp:28
AST node used by the parser, optimizer and compiler.
ArkScript configuration macros.
The basic value type handled by the compiler.
Describe an instruction and its immediate argument.
The ArkScript bytecode compiler.
Definition: Compiler.hpp:36
std::vector< std::vector< internal::Word > > m_code_pages
Definition: Compiler.hpp:68
std::vector< internal::Word > * page_ptr(const int i) noexcept
helper functions to get a temp or finalized code page
Definition: Compiler.hpp:105
std::vector< std::string > m_defined_symbols
Definition: Compiler.hpp:65
std::vector< std::string > m_plugins
Definition: Compiler.hpp:66
unsigned m_debug
the debug level of the compiler
Definition: Compiler.hpp:72
std::vector< internal::ValTableElem > m_values
Definition: Compiler.hpp:67
std::vector< std::vector< internal::Word > > m_temp_pages
we need temporary code pages for some compilations passes
Definition: Compiler.hpp:69
static std::optional< internal::Instruction > getSpecific(const std::string &name) noexcept
Check if a symbol needs to be compiled to a specific instruction.
Definition: Compiler.hpp:134
std::vector< internal::Node > m_symbols
Definition: Compiler.hpp:64
bytecode_t m_bytecode
Definition: Compiler.hpp:71
Ark state to handle the dirty job of loading and compiling ArkScript code.
Definition: State.hpp:31
A node of an Abstract Syntax Tree for ArkScript.
Definition: Node.hpp:30
Keyword
The different keywords available.
Definition: Common.hpp:56
Instruction
The different bytecodes are stored here.
Definition: Builtins.hpp:21
std::vector< uint8_t > bytecode_t
Definition: Common.hpp:21