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 * @version 0.1
6 * @date 2020-10-27
7 *
8 * @copyright Copyright (c) 2020-2024
9 *
10 */
11
12#ifndef ARK_COMPILER_INSTRUCTIONS_HPP
13#define ARK_COMPILER_INSTRUCTIONS_HPP
14
15#include <array>
16
17namespace Ark::internal
18{
19 /**
20 * @brief The different bytecodes are stored here
21 * @par Adding an operator
22 * It must be referenced as well under include/Ark/Compiler/Common.hpp, in
23 * the operators table. The order of the operators below <code>FIRST_OPERATOR</code>
24 * must be the same as the one in the operators table from the aforementioned file.
25 *
26 */
27 enum Instruction : uint8_t
28 {
29 // @role Does nothing, useful for padding
30 NOP = 0x00,
35 FUNC_TYPE = 0x03,
37
38 // @args symbol id
39 // @role Load a symbol from its ID onto the stack
41
42 // @args symbol id
43 // @role Load a constant from its ID onto the stack
44 LOAD_CONST = 0x02,
45
46 // @args absolute address to jump to
47 // @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
49
50 // @args symbol id
51 // @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)
52 STORE = 0x04,
53
54 // @args symbol id
55 // @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
56 SET_VAL = 0x05,
57
58 // @args absolute address to jump to
59 // @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
61
62 // @args absolute address to jump to
63 // @role Jump to the provided address
64 JUMP = 0x07,
65
66 // @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]
67 RET = 0x08,
68
69 // @role Stop the Virtual Machine
70 HALT = 0x09,
71
72 // @args argument count
73 // @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
74 CALL = 0x0a,
75
76 // @args symbol id
77 // @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
78 CAPTURE = 0x0b,
79
80 // @args builtin id
81 // @role Push the corresponding builtin function object on the stack
82 BUILTIN = 0x0c,
83
84 // @args symbol id
85 // @role Remove a variable/constant named following the given symbol id (cf symbols table)
86 DEL = 0x0d,
87
88 // @args constant id
89 // @role Push a Closure with the page address pointed by the constant, along with the saved scope created by CAPTURE instruction(s)
91
92 // @args symbol id
93 // @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
94 GET_FIELD = 0x0f,
95
96 // @args constant id
97 // @role Load a plugin dynamically, plugin name is stored as a string in the constants table
98 PLUGIN = 0x10,
99
100 // @args number of elements
101 // @role Create a list from the N elements pushed on the stack. Follows the function calling convention
102 LIST = 0x11,
103
104 // @args number of elements
105 // @role Append N elements to a list (TS). Elements are stored in TS(1)..TS(N). Follows the function calling convention
106 APPEND = 0x12,
107
108 // @args number of elements
109 // @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
110 CONCAT = 0x13,
111
112 // @args number of elements
113 // @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
115
116 // @args number of elements
117 // @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
119
120 // @role Remove an element from a list (TS), given an index (TS1). Push a new list without the removed element to the stack
121 POP_LIST = 0x16,
122
123 // @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
125
126 // @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
128
129 // @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
131
132 // @role Remove the top of the stack
133 POP = 0x1a,
134
135 // @role Duplicate the top of the stack
136 DUP = 0x1b,
137
138 // @role Create a new local scope
140
141 // @role Destroy the last local scope
142 POP_SCOPE = 0x1d,
143
145
146 // @role Push #[code TS1 + TS]
147 ADD = 0x1e,
148
149 // @role Push #[code TS1 - TS]
150 SUB = 0x1f,
151
152 // @role Push #[code TS1 * TS]
153 MUL = 0x20,
154
155 // @role Push #[code TS1 / TS]
156 DIV = 0x21,
157
158 // @role Push #[code TS1 > TS]
159 GT = 0x22,
160
161 // @role Push #[code TS1 < TS]
162 LT = 0x23,
163
164 // @role Push #[code TS1 <= TS]
165 LE = 0x24,
166
167 // @role Push #[code TS1 >= TS]
168 GE = 0x25,
169
170 // @role Push #[code TS1 != TS]
171 NEQ = 0x26,
172
173 // @role Push #[code TS1 == TS]
174 EQ = 0x27,
175
176 // @role Push #[code len(TS)], TS must be a list
177 LEN = 0x28,
178
179 // @role Push #[code empty?(TS)], TS must be a list or string
180 EMPTY = 0x29,
181
182 // @role Push #[code tail(TS)], all the elements of TS except the first one. TS must be a list or string
183 TAIL = 0x2a,
184
185 // @role Push #[code head(TS)], the first element of TS or nil if empty. TS must be a list or string
186 HEAD = 0x2b,
187
188 // @role Push true if TS is nil, false otherwise
189 ISNIL = 0x2c,
190
191 // @role Throw an exception if TS1 is false, and display TS (must be a string). Do not push anything on the stack
192 ASSERT = 0x2d,
193
194 // @role Convert TS to number (must be a string)
195 TO_NUM = 0x2e,
196
197 // @role Convert TS to string
198 TO_STR = 0x2f,
199
200 // @role Push the value at index TS (must be a number) in TS1, which must be a list or string
201 AT = 0x30,
202
203 // @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
204 AT_AT = 0x31,
205
206 // @role Push #[code TS1 % TS]
207 MOD = 0x32,
208
209 // @role Push the type of TS as a string
210 TYPE = 0x33,
211
212 // @role Check if TS1 is a closure field of TS. TS must be a Closure, TS1 a String
213 HASFIELD = 0x34,
214
215 // @role Push #[code !TS]
216 NOT = 0x35,
217
218 // @args constant id, constant id
219 // @role Load two consts (#[code primary] then #[code secondary]) on the stack in one instruction
221
222 // @args constant id, symbol id
223 // @role Load const #[code primary] into the symbol #[code secondary] (create a variable)
225
226 // @args constant id, symbol id
227 // @role Load const #[code primary] into the symbol #[code secondary] (search for the variable with the given symbol id)
229
230 // @args symbol id, symbol id
231 // @role Store the value of the symbol #[code primary] into a new variable #[code secondary]
233
234 // @args symbol id, symbol id
235 // @role Store the value of the symbol #[code primary] into an existing variable #[code secondary]
237
238 // @args symbol id, count
239 // @role Increment the variable #[code primary] by #[code count] and push its value on the stack
240 INCREMENT = 0x3b,
241
242 // @args symbol id, count
243 // @role Decrement the variable #[code primary] by #[code count] and push its value on the stack
244 DECREMENT = 0x3c,
245
246 // @args symbol id, symbol id
247 // @role Load the symbol #[code primary], compute its tail, store it in a new variable #[code secondary]
249
250 // @args symbol id, symbol id
251 // @role Load the symbol #[code primary], compute its head, store it in a new variable #[code secondary]
253
254 // @args symbol id, symbol id
255 // @role Load the symbol #[code primary], compute its tail, store it in an existing variable #[code secondary]
257
258 // @args symbol id, symbol id
259 // @role Load the symbol #[code primary], compute its head, store it in an existing variable #[code secondary]
261
262 // @args builtin id, argument count
263 // @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
264 CALL_BUILTIN = 0x41
265 };
266
267 constexpr std::array InstructionNames = {
268 "NOP",
269 "LOAD_SYMBOL",
270 "LOAD_CONST",
271 "POP_JUMP_IF_TRUE",
272 "STORE",
273 "SET_VAL",
274 "POP_JUMP_IF_FALSE",
275 "JUMP",
276 "RET",
277 "HALT",
278 "CALL",
279 "CAPTURE",
280 "BUILTIN",
281 "DEL",
282 "MAKE_CLOSURE",
283 "GET_FIELD",
284 "PLUGIN",
285 "LIST",
286 "APPEND",
287 "CONCAT",
288 "APPEND_IN_PLACE",
289 "CONCAT_IN_PLACE",
290 "POP_LIST",
291 "POP_LIST_IN_PLACE",
292 "SET_AT_INDEX",
293 "SET_AT_2_INDEX",
294 "POP",
295 "DUP",
296 "CREATE_SCOPE",
297 "POP_SCOPE",
298 // operators
299 "ADD",
300 "SUB",
301 "MUL",
302 "DIV",
303 "GT",
304 "LT",
305 "LE",
306 "GE",
307 "NEQ",
308 "EQ",
309 "LEN",
310 "EMPTY",
311 "TAIL",
312 "HEAD",
313 "ISNIL",
314 "ASSERT",
315 "TO_NUM",
316 "TO_STR",
317 "AT",
318 "AT_AT",
319 "MOD",
320 "TYPE",
321 "HASFIELD",
322 "NOT",
323 // super instructions
324 "LOAD_CONST_LOAD_CONST",
325 "LOAD_CONST_STORE",
326 "LOAD_CONST_SET_VAL",
327 "STORE_FROM",
328 "SET_VAL_FROM",
329 "INCREMENT",
330 "DECREMENT",
331 "STORE_TAIL",
332 "STORE_HEAD",
333 "SET_VAL_TAIL",
334 "SET_VAL_HEAD",
335 "CALL_BUILTIN"
336 };
337}
338
339#endif
Instruction
The different bytecodes are stored here.
constexpr std::array InstructionNames