Skip to content

Commit 8ebcbb2

Browse files
committed
feat(compiler, vm, scopes): adding RESET_SCOPE instruction to be able to reuse a scope inside while loops
1 parent 3d9ea4b commit 8ebcbb2

File tree

9 files changed

+76
-46
lines changed

9 files changed

+76
-46
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
- `STORE_FROM_INDEX` and `SET_VAL_FROM_INDEX` instructions for parity with the super instructions not using load by index
4242
- `INCREMENT_BY_INDEX` and `DECREMENT_BY_INDEX` instructions for parity with the super instructions not using load by index
4343
- `STORE_TAIL_BY_INDEX`, `STORE_HEAD_BY_INDEX`, `SET_VAL_TAIL_BY_INDEX`, `SET_VAL_HEAD_BY_INDEX` super instructions added for parity with the super instructions not using load by index
44+
- `RESET_SCOPE` instruction emitted at the end of a while loop to reset a scope so that we can create multiple variables and use `LOAD_SYMBOL_BY_INDEX`
4445

4546
### Changed
4647
- instructions are on 4 bytes: 1 byte for the instruction, 1 byte of padding, 2 bytes for an immediate argument

include/Ark/Compiler/Instructions.hpp

Lines changed: 50 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -142,162 +142,165 @@ namespace Ark::internal
142142
// @role Create a new local scope
143143
CREATE_SCOPE = 0x1d,
144144

145+
// @role Reset the current scope so that it is empty
146+
RESET_SCOPE = 0x1e,
147+
145148
// @role Destroy the last local scope
146-
POP_SCOPE = 0x1e,
149+
POP_SCOPE = 0x1f,
147150

148-
FIRST_OPERATOR = 0x1f,
151+
FIRST_OPERATOR = 0x20,
149152

150153
// @role Push #[code TS1 + TS]
151-
ADD = 0x1f,
154+
ADD = 0x20,
152155

153156
// @role Push #[code TS1 - TS]
154-
SUB = 0x20,
157+
SUB = 0x21,
155158

156159
// @role Push #[code TS1 * TS]
157-
MUL = 0x21,
160+
MUL = 0x22,
158161

159162
// @role Push #[code TS1 / TS]
160-
DIV = 0x22,
163+
DIV = 0x23,
161164

162165
// @role Push #[code TS1 > TS]
163-
GT = 0x23,
166+
GT = 0x24,
164167

165168
// @role Push #[code TS1 < TS]
166-
LT = 0x24,
169+
LT = 0x25,
167170

168171
// @role Push #[code TS1 <= TS]
169-
LE = 0x25,
172+
LE = 0x26,
170173

171174
// @role Push #[code TS1 >= TS]
172-
GE = 0x26,
175+
GE = 0x27,
173176

174177
// @role Push #[code TS1 != TS]
175-
NEQ = 0x27,
178+
NEQ = 0x28,
176179

177180
// @role Push #[code TS1 == TS]
178-
EQ = 0x28,
181+
EQ = 0x29,
179182

180183
// @role Push #[code len(TS)], TS must be a list
181-
LEN = 0x29,
184+
LEN = 0x2a,
182185

183186
// @role Push #[code empty?(TS)], TS must be a list or string
184-
EMPTY = 0x2a,
187+
EMPTY = 0x2b,
185188

186189
// @role Push #[code tail(TS)], all the elements of TS except the first one. TS must be a list or string
187-
TAIL = 0x2b,
190+
TAIL = 0x2c,
188191

189192
// @role Push #[code head(TS)], the first element of TS or nil if empty. TS must be a list or string
190-
HEAD = 0x2c,
193+
HEAD = 0x2d,
191194

192195
// @role Push true if TS is nil, false otherwise
193-
ISNIL = 0x2d,
196+
ISNIL = 0x2e,
194197

195198
// @role Throw an exception if TS1 is false, and display TS (must be a string). Do not push anything on the stack
196-
ASSERT = 0x2e,
199+
ASSERT = 0x2f,
197200

198201
// @role Convert TS to number (must be a string)
199-
TO_NUM = 0x2f,
202+
TO_NUM = 0x30,
200203

201204
// @role Convert TS to string
202-
TO_STR = 0x30,
205+
TO_STR = 0x31,
203206

204207
// @role Push the value at index TS (must be a number) in TS1, which must be a list or string
205-
AT = 0x31,
208+
AT = 0x32,
206209

207210
// @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
208-
AT_AT = 0x32,
211+
AT_AT = 0x33,
209212

210213
// @role Push #[code TS1 % TS]
211-
MOD = 0x33,
214+
MOD = 0x34,
212215

213216
// @role Push the type of TS as a string
214-
TYPE = 0x34,
217+
TYPE = 0x35,
215218

216219
// @role Check if TS1 is a closure field of TS. TS must be a Closure, TS1 a String
217-
HASFIELD = 0x35,
220+
HASFIELD = 0x36,
218221

219222
// @role Push #[code !TS]
220-
NOT = 0x36,
223+
NOT = 0x37,
221224

222225
// @args constant id, constant id
223226
// @role Load two consts (#[code primary] then #[code secondary]) on the stack in one instruction
224-
LOAD_CONST_LOAD_CONST = 0x37,
227+
LOAD_CONST_LOAD_CONST = 0x38,
225228

226229
// @args constant id, symbol id
227230
// @role Load const #[code primary] into the symbol #[code secondary] (create a variable)
228-
LOAD_CONST_STORE = 0x38,
231+
LOAD_CONST_STORE = 0x39,
229232

230233
// @args constant id, symbol id
231234
// @role Load const #[code primary] into the symbol #[code secondary] (search for the variable with the given symbol id)
232-
LOAD_CONST_SET_VAL = 0x39,
235+
LOAD_CONST_SET_VAL = 0x3a,
233236

234237
// @args symbol id, symbol id
235238
// @role Store the value of the symbol #[code primary] into a new variable #[code secondary]
236-
STORE_FROM = 0x3a,
239+
STORE_FROM = 0x3b,
237240

238241
// @args symbol index, symbol id
239242
// @role Store the value of the symbol #[code primary] into a new variable #[code secondary]
240-
STORE_FROM_INDEX = 0x3b,
243+
STORE_FROM_INDEX = 0x3c,
241244

242245
// @args symbol id, symbol id
243246
// @role Store the value of the symbol #[code primary] into an existing variable #[code secondary]
244-
SET_VAL_FROM = 0x3c,
247+
SET_VAL_FROM = 0x3d,
245248

246249
// @args symbol index, symbol id
247250
// @role Store the value of the symbol #[code primary] into an existing variable #[code secondary]
248-
SET_VAL_FROM_INDEX = 0x3d,
251+
SET_VAL_FROM_INDEX = 0x3e,
249252

250253
// @args symbol id, count
251254
// @role Increment the variable #[code primary] by #[code count] and push its value on the stack
252-
INCREMENT = 0x3e,
255+
INCREMENT = 0x3f,
253256

254257
// @args symbol index, count
255258
// @role Increment the variable #[code primary] by #[code count] and push its value on the stack
256-
INCREMENT_BY_INDEX = 0x3f,
259+
INCREMENT_BY_INDEX = 0x40,
257260

258261
// @args symbol id, count
259262
// @role Decrement the variable #[code primary] by #[code count] and push its value on the stack
260-
DECREMENT = 0x40,
263+
DECREMENT = 0x41,
261264

262265
// @args symbol index, count
263266
// @role Decrement the variable #[code primary] by #[code count] and push its value on the stack
264-
DECREMENT_BY_INDEX = 0x41,
267+
DECREMENT_BY_INDEX = 0x42,
265268

266269
// @args symbol id, symbol id
267270
// @role Load the symbol #[code primary], compute its tail, store it in a new variable #[code secondary]
268-
STORE_TAIL = 0x42,
271+
STORE_TAIL = 0x43,
269272

270273
// @args symbol index, symbol id
271274
// @role Load the symbol #[code primary], compute its tail, store it in a new variable #[code secondary]
272-
STORE_TAIL_BY_INDEX = 0x43,
275+
STORE_TAIL_BY_INDEX = 0x44,
273276

274277
// @args symbol id, symbol id
275278
// @role Load the symbol #[code primary], compute its head, store it in a new variable #[code secondary]
276-
STORE_HEAD = 0x44,
279+
STORE_HEAD = 0x45,
277280

278281
// @args symbol index, symbol id
279282
// @role Load the symbol #[code primary], compute its head, store it in a new variable #[code secondary]
280-
STORE_HEAD_BY_INDEX = 0x45,
283+
STORE_HEAD_BY_INDEX = 0x46,
281284

282285
// @args symbol id, symbol id
283286
// @role Load the symbol #[code primary], compute its tail, store it in an existing variable #[code secondary]
284-
SET_VAL_TAIL = 0x46,
287+
SET_VAL_TAIL = 0x47,
285288

286289
// @args symbol index, symbol id
287290
// @role Load the symbol #[code primary], compute its tail, store it in an existing variable #[code secondary]
288-
SET_VAL_TAIL_BY_INDEX = 0x47,
291+
SET_VAL_TAIL_BY_INDEX = 0x48,
289292

290293
// @args symbol id, symbol id
291294
// @role Load the symbol #[code primary], compute its head, store it in an existing variable #[code secondary]
292-
SET_VAL_HEAD = 0x48,
295+
SET_VAL_HEAD = 0x49,
293296

294297
// @args symbol index, symbol id
295298
// @role Load the symbol #[code primary], compute its head, store it in an existing variable #[code secondary]
296-
SET_VAL_HEAD_BY_INDEX = 0x49,
299+
SET_VAL_HEAD_BY_INDEX = 0x4a,
297300

298301
// @args builtin id, argument count
299302
// @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
300-
CALL_BUILTIN = 0x4a,
303+
CALL_BUILTIN = 0x4b,
301304

302305
InstructionsCount
303306
};
@@ -333,6 +336,7 @@ namespace Ark::internal
333336
"POP",
334337
"DUP",
335338
"CREATE_SCOPE",
339+
"RESET_SCOPE",
336340
"POP_SCOPE",
337341
// operators
338342
"ADD",

include/Ark/VM/ScopeView.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ namespace Ark::internal
111111
return m_storage[m_start + m_size - 1 - i];
112112
}
113113

114+
/**
115+
* @brief Reset size, min and max id for the scope, to signify it's empty
116+
*/
117+
inline void reset() noexcept
118+
{
119+
m_size = 0;
120+
m_min_id = std::numeric_limits<uint16_t>::max();
121+
m_max_id = 0;
122+
}
123+
114124
/**
115125
* @brief Return the size of the scope
116126
*

src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,10 @@ namespace Ark::internal
440440
// push code to page
441441
compileExpression(x.constList()[2], p, true, false);
442442

443+
// reset the scope at the end of the loop so that indices are still valid
444+
// otherwise, (while true { (let a 5) (print a) (let b 6) (print b) })
445+
// would print 5, 6, then only 6 as we emit LOAD_SYMBOL_FROM_INDEX 0 and b is the last in the scope
446+
page(p).emplace_back(RESET_SCOPE);
443447
// loop, jump to the condition
444448
page(p).emplace_back(IR::Entity::Goto(label_loop));
445449

src/arkreactor/VM/VM.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ namespace Ark
391391
&&TARGET_POP,
392392
&&TARGET_DUP,
393393
&&TARGET_CREATE_SCOPE,
394+
&&TARGET_RESET_SCOPE,
394395
&&TARGET_POP_SCOPE,
395396
&&TARGET_ADD,
396397
&&TARGET_SUB,
@@ -939,6 +940,12 @@ namespace Ark
939940
DISPATCH();
940941
}
941942

943+
TARGET(RESET_SCOPE)
944+
{
945+
context.locals.back().reset();
946+
DISPATCH();
947+
}
948+
942949
TARGET(POP_SCOPE)
943950
{
944951
context.locals.pop_back();

tests/unittests/resources/CompilerSuite/ir/99bottles.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ page_0
4949
BUILTIN 9
5050
CALL 1
5151
POP 0
52+
RESET_SCOPE 0
5253
GOTO L4
5354
.L5:
5455
POP_SCOPE 0

tests/unittests/resources/CompilerSuite/ir/factorial.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ page_1
2929
LOAD_SYMBOL 3
3030
ADD 0
3131
SET_VAL 3
32+
RESET_SCOPE 0
3233
GOTO L0
3334
.L1:
3435
POP_SCOPE 0

tests/unittests/resources/CompilerSuite/optimized_ir/99bottles.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ page_0
4242
CALL_BUILTIN 24, 2
4343
CALL_BUILTIN 9, 1
4444
POP 0
45+
RESET_SCOPE 0
4546
GOTO L4
4647
.L5:
4748
POP_SCOPE 0

tests/unittests/resources/CompilerSuite/optimized_ir/factorial.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ page_1
2222
SET_VAL 2
2323
INCREMENT 3, 1
2424
SET_VAL 3
25+
RESET_SCOPE 0
2526
GOTO L0
2627
.L1:
2728
POP_SCOPE 0

0 commit comments

Comments
 (0)