ArkScript
A small, fast, functional and scripting language for video games
Instructions.hpp
Go to the documentation of this file.
1/**
2 * @file Instructions.hpp
3 * @author Alexandre Plateau ([email protected])
4 * @brief The different instructions used by the compiler and virtual machine
5 * @date 2020-10-27
6 *
7 * @copyright Copyright (c) 2020-2025
8 *
9 */
10
11#ifndef ARK_COMPILER_INSTRUCTIONS_HPP
12#define ARK_COMPILER_INSTRUCTIONS_HPP
13
14#include <array>
15
16namespace Ark::internal
17{
18 /**
19 * @brief The different bytecodes are stored here
20 * @par Adding an operator
21 * It must be referenced as well under include/Ark/Compiler/Common.hpp, in
22 * the operators table. The order of the operators below <code>FIRST_OPERATOR</code>
23 * must be the same as the one in the operators table from the aforementioned file.
24 *
25 */
26 enum Instruction : uint8_t
27 {
28 // @role Does nothing, useful for padding
29 NOP = 0x00,
35 FUNC_TYPE = 0xF3,
38
39 // @args symbol id
40 // @role Load a symbol from its ID onto the stack
42
43 // @args stack index
44 // @role Load a symbol from the locals stack by its index (starting from the end of the current scope)
46
47 // @args symbol id
48 // @role Load a constant from its ID onto the stack
49 LOAD_CONST = 0x03,
50
51 // @args absolute address to jump to
52 // @role Jump to the provided address if the last value on the stack was equal to true. Remove the value from the stack no matter what it is
54
55 // @args symbol id
56 // @role Take the value on top of the stack and create a variable in the current scope, named following the given symbol id (cf symbols table)
57 STORE = 0x05,
58
59 // @args symbol id
60 // @role Take the value on top of the stack and put it inside a variable named following the symbol id (cf symbols table), in the nearest scope. Raise an error if it couldn't find a scope where the variable exists
61 SET_VAL = 0x06,
62
63 // @args absolute address to jump to
64 // @role Jump to the provided address if the last value on the stack was equal to false. Remove the value from the stack no matter what it is
66
67 // @args absolute address to jump to
68 // @role Jump to the provided address
69 JUMP = 0x08,
70
71 // @role If in a code segment other than the main one, quit it, and push the value on top of the stack to the new stack; should as well delete the current environment. Otherwise, acts as a #[code HALT]
72 RET = 0x09,
73
74 // @role Stop the Virtual Machine
75 HALT = 0x0a,
76
77 // @args argument count
78 // @role Call function from its symbol id located on top of the stack. Take the given number of arguments from the top of stack and give them to the function (the first argument taken from the stack will be the last one of the function). The stack of the function is now composed of its arguments, from the first to the last one
79 CALL = 0x0b,
80
81 // @args symbol id
82 // @role Tell the Virtual Machine to capture the variable from the current environment. Main goal is to be able to handle closures, which need to save the environment in which they were created
83 CAPTURE = 0x0c,
84
85 // @args builtin id
86 // @role Push the corresponding builtin function object on the stack
87 BUILTIN = 0x0d,
88
89 // @args symbol id
90 // @role Remove a variable/constant named following the given symbol id (cf symbols table)
91 DEL = 0x0e,
92
93 // @args constant id
94 // @role Push a Closure with the page address pointed by the constant, along with the saved scope created by CAPTURE instruction(s)
96
97 // @args symbol id
98 // @role Read the field named following the given symbol id (cf symbols table) of a #[code Closure] stored in TS. Pop TS and push the value of field read on the stack
99 GET_FIELD = 0x10,
100
101 // @args constant id
102 // @role Load a plugin dynamically, plugin name is stored as a string in the constants table
103 PLUGIN = 0x11,
104
105 // @args number of elements
106 // @role Create a list from the N elements pushed on the stack. Follows the function calling convention
107 LIST = 0x12,
108
109 // @args number of elements
110 // @role Append N elements to a list (TS). Elements are stored in TS(1)..TS(N). Follows the function calling convention
111 APPEND = 0x13,
112
113 // @args number of elements
114 // @role Concatenate N lists to a list (TS). Lists to concat to TS are stored in TS(1)..TS(N). Follows the function calling convention
115 CONCAT = 0x14,
116
117 // @args number of elements
118 // @role Append N elements to a reference to a list (TS), the list is being mutated in-place, no new object created. Elements are stored in TS(1)..TS(N). Follows the function calling convention
120
121 // @args number of elements
122 // @role Concatenate N lists to a reference to a list (TS), the list is being mutated in-place, no new object created. Lists to concat to TS are stored in TS(1)..TS(N). Follows the function calling convention
124
125 // @role Remove an element from a list (TS), given an index (TS1). Push a new list without the removed element to the stack
126 POP_LIST = 0x17,
127
128 // @role Remove an element from a reference to a list (TS), given an index (TS1). The list is mutated in-place, no new object created
130
131 // @role Modify a reference to a list or string (TS) by replacing the element at TS1 (must be a number) by the value in TS2. The object is mutated in-place, no new object created
133
134 // @role Modify a reference to a list (TS) by replacing TS[TS2][TS1] by the value in TS3. TS[TS2] can be a string (if it is, TS3 must be a string). The object is mutated in-place, no new object created
136
137 // @role Remove the top of the stack
138 POP = 0x1b,
139
140 // @role Duplicate the top of the stack
141 DUP = 0x1c,
142
143 // @role Create a new local scope
145
146 // @role Reset the current scope so that it is empty
148
149 // @role Destroy the last local scope
150 POP_SCOPE = 0x1f,
151
153
154 // @role Push #[code TS1 + TS]
155 ADD = 0x20,
156
157 // @role Push #[code TS1 - TS]
158 SUB = 0x21,
159
160 // @role Push #[code TS1 * TS]
161 MUL = 0x22,
162
163 // @role Push #[code TS1 / TS]
164 DIV = 0x23,
165
166 // @role Push #[code TS1 > TS]
167 GT = 0x24,
168
169 // @role Push #[code TS1 < TS]
170 LT = 0x25,
171
172 // @role Push #[code TS1 <= TS]
173 LE = 0x26,
174
175 // @role Push #[code TS1 >= TS]
176 GE = 0x27,
177
178 // @role Push #[code TS1 != TS]
179 NEQ = 0x28,
180
181 // @role Push #[code TS1 == TS]
182 EQ = 0x29,
183
184 // @role Push #[code len(TS)], TS must be a list
185 LEN = 0x2a,
186
187 // @role Push #[code empty?(TS)], TS must be a list or string
188 EMPTY = 0x2b,
189
190 // @role Push #[code tail(TS)], all the elements of TS except the first one. TS must be a list or string
191 TAIL = 0x2c,
192
193 // @role Push #[code head(TS)], the first element of TS or nil if empty. TS must be a list or string
194 HEAD = 0x2d,
195
196 // @role Push true if TS is nil, false otherwise
197 ISNIL = 0x2e,
198
199 // @role Throw an exception if TS1 is false, and display TS (must be a string). Do not push anything on the stack
200 ASSERT = 0x2f,
201
202 // @role Convert TS to number (must be a string)
203 TO_NUM = 0x30,
204
205 // @role Convert TS to string
206 TO_STR = 0x31,
207
208 // @role Push the value at index TS (must be a number) in TS1, which must be a list or string
209 AT = 0x32,
210
211 // @role Push the value at index TS (must be a number), inside the list or string at index TS1 (must be a number) in the list at TS2
212 AT_AT = 0x33,
213
214 // @role Push #[code TS1 % TS]
215 MOD = 0x34,
216
217 // @role Push the type of TS as a string
218 TYPE = 0x35,
219
220 // @role Check if TS1 is a closure field of TS. TS must be a Closure, TS1 a String
221 HASFIELD = 0x36,
222
223 // @role Push #[code !TS]
224 NOT = 0x37,
225
226 // @args constant id, constant id
227 // @role Load two consts (#[code primary] then #[code secondary]) on the stack in one instruction
229
230 // @args constant id, symbol id
231 // @role Load const #[code primary] into the symbol #[code secondary] (create a variable)
233
234 // @args constant id, symbol id
235 // @role Load const #[code primary] into the symbol #[code secondary] (search for the variable with the given symbol id)
237
238 // @args symbol id, symbol id
239 // @role Store the value of the symbol #[code primary] into a new variable #[code secondary]
241
242 // @args symbol index, symbol id
243 // @role Store the value of the symbol #[code primary] into a new variable #[code secondary]
245
246 // @args symbol id, symbol id
247 // @role Store the value of the symbol #[code primary] into an existing variable #[code secondary]
249
250 // @args symbol index, symbol id
251 // @role Store the value of the symbol #[code primary] into an existing variable #[code secondary]
253
254 // @args symbol id, count
255 // @role Increment the variable #[code primary] by #[code count] and push its value on the stack
256 INCREMENT = 0x3f,
257
258 // @args symbol index, count
259 // @role Increment the variable #[code primary] by #[code count] and push its value on the stack
261
262 // @args symbol id, count
263 // @role Decrement the variable #[code primary] by #[code count] and push its value on the stack
264 DECREMENT = 0x41,
265
266 // @args symbol index, count
267 // @role Decrement the variable #[code primary] by #[code count] and push its value on the stack
269
270 // @args symbol id, symbol id
271 // @role Load the symbol #[code primary], compute its tail, store it in a new variable #[code secondary]
273
274 // @args symbol index, symbol id
275 // @role Load the symbol #[code primary], compute its tail, store it in a new variable #[code secondary]
277
278 // @args symbol id, symbol id
279 // @role Load the symbol #[code primary], compute its head, store it in a new variable #[code secondary]
281
282 // @args symbol index, symbol id
283 // @role Load the symbol #[code primary], compute its head, store it in a new variable #[code secondary]
285
286 // @args symbol id, symbol id
287 // @role Load the symbol #[code primary], compute its tail, store it in an existing variable #[code secondary]
289
290 // @args symbol index, symbol id
291 // @role Load the symbol #[code primary], compute its tail, store it in an existing variable #[code secondary]
293
294 // @args symbol id, symbol id
295 // @role Load the symbol #[code primary], compute its head, store it in an existing variable #[code secondary]
297
298 // @args symbol index, symbol id
299 // @role Load the symbol #[code primary], compute its head, store it in an existing variable #[code secondary]
301
302 // @args builtin id, argument count
303 // @role Call a builtin by its id in #[code primary], with #[code secondary] arguments. Bypass the stack size check because we do not push IP/PP since builtins calls do not alter the stack
305
307 };
308
309 constexpr std::array InstructionNames = {
310 "NOP",
311 "LOAD_SYMBOL",
312 "LOAD_SYMBOL_BY_INDEX",
313 "LOAD_CONST",
314 "POP_JUMP_IF_TRUE",
315 "STORE",
316 "SET_VAL",
317 "POP_JUMP_IF_FALSE",
318 "JUMP",
319 "RET",
320 "HALT",
321 "CALL",
322 "CAPTURE",
323 "BUILTIN",
324 "DEL",
325 "MAKE_CLOSURE",
326 "GET_FIELD",
327 "PLUGIN",
328 "LIST",
329 "APPEND",
330 "CONCAT",
331 "APPEND_IN_PLACE",
332 "CONCAT_IN_PLACE",
333 "POP_LIST",
334 "POP_LIST_IN_PLACE",
335 "SET_AT_INDEX",
336 "SET_AT_2_INDEX",
337 "POP",
338 "DUP",
339 "CREATE_SCOPE",
340 "RESET_SCOPE",
341 "POP_SCOPE",
342 // operators
343 "ADD",
344 "SUB",
345 "MUL",
346 "DIV",
347 "GT",
348 "LT",
349 "LE",
350 "GE",
351 "NEQ",
352 "EQ",
353 "LEN",
354 "EMPTY",
355 "TAIL",
356 "HEAD",
357 "ISNIL",
358 "ASSERT",
359 "TO_NUM",
360 "TO_STR",
361 "AT",
362 "AT_AT",
363 "MOD",
364 "TYPE",
365 "HASFIELD",
366 "NOT",
367 // super instructions
368 "LOAD_CONST_LOAD_CONST",
369 "LOAD_CONST_STORE",
370 "LOAD_CONST_SET_VAL",
371 "STORE_FROM",
372 "STORE_FROM_INDEX",
373 "SET_VAL_FROM",
374 "SET_VAL_FROM_INDEX",
375 "INCREMENT",
376 "INCREMENT_BY_INDEX",
377 "DECREMENT",
378 "DECREMENT_BY_INDEX",
379 "STORE_TAIL",
380 "STORE_TAIL_BY_INDEX",
381 "STORE_HEAD",
382 "STORE_HEAD_BY_INDEX",
383 "SET_VAL_TAIL",
384 "SET_VAL_TAIL_BY_INDEX",
385 "SET_VAL_HEAD",
386 "SET_VAL_HEAD_BY_INDEX",
387 "CALL_BUILTIN"
388 };
389
390 static_assert(InstructionNames.size() == static_cast<std::size_t>(Instruction::InstructionsCount) && "Some instruction names appear to be missing");
391}
392
393#endif
Instruction
The different bytecodes are stored here.
constexpr std::array InstructionNames