Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
- `STORE_FROM_INDEX` and `SET_VAL_FROM_INDEX` instructions for parity with the super instructions not using load by index
- `INCREMENT_BY_INDEX` and `DECREMENT_BY_INDEX` instructions for parity with the super instructions not using load by index
- `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
- `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`

### Changed
- instructions are on 4 bytes: 1 byte for the instruction, 1 byte of padding, 2 bytes for an immediate argument
Expand Down
96 changes: 50 additions & 46 deletions include/Ark/Compiler/Instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,162 +142,165 @@ namespace Ark::internal
// @role Create a new local scope
CREATE_SCOPE = 0x1d,

// @role Reset the current scope so that it is empty
RESET_SCOPE = 0x1e,

// @role Destroy the last local scope
POP_SCOPE = 0x1e,
POP_SCOPE = 0x1f,

FIRST_OPERATOR = 0x1f,
FIRST_OPERATOR = 0x20,

// @role Push #[code TS1 + TS]
ADD = 0x1f,
ADD = 0x20,

// @role Push #[code TS1 - TS]
SUB = 0x20,
SUB = 0x21,

// @role Push #[code TS1 * TS]
MUL = 0x21,
MUL = 0x22,

// @role Push #[code TS1 / TS]
DIV = 0x22,
DIV = 0x23,

// @role Push #[code TS1 > TS]
GT = 0x23,
GT = 0x24,

// @role Push #[code TS1 < TS]
LT = 0x24,
LT = 0x25,

// @role Push #[code TS1 <= TS]
LE = 0x25,
LE = 0x26,

// @role Push #[code TS1 >= TS]
GE = 0x26,
GE = 0x27,

// @role Push #[code TS1 != TS]
NEQ = 0x27,
NEQ = 0x28,

// @role Push #[code TS1 == TS]
EQ = 0x28,
EQ = 0x29,

// @role Push #[code len(TS)], TS must be a list
LEN = 0x29,
LEN = 0x2a,

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

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

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

// @role Push true if TS is nil, false otherwise
ISNIL = 0x2d,
ISNIL = 0x2e,

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

// @role Convert TS to number (must be a string)
TO_NUM = 0x2f,
TO_NUM = 0x30,

// @role Convert TS to string
TO_STR = 0x30,
TO_STR = 0x31,

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

// @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
AT_AT = 0x32,
AT_AT = 0x33,

// @role Push #[code TS1 % TS]
MOD = 0x33,
MOD = 0x34,

// @role Push the type of TS as a string
TYPE = 0x34,
TYPE = 0x35,

// @role Check if TS1 is a closure field of TS. TS must be a Closure, TS1 a String
HASFIELD = 0x35,
HASFIELD = 0x36,

// @role Push #[code !TS]
NOT = 0x36,
NOT = 0x37,

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

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

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

// @args symbol id, symbol id
// @role Store the value of the symbol #[code primary] into a new variable #[code secondary]
STORE_FROM = 0x3a,
STORE_FROM = 0x3b,

// @args symbol index, symbol id
// @role Store the value of the symbol #[code primary] into a new variable #[code secondary]
STORE_FROM_INDEX = 0x3b,
STORE_FROM_INDEX = 0x3c,

// @args symbol id, symbol id
// @role Store the value of the symbol #[code primary] into an existing variable #[code secondary]
SET_VAL_FROM = 0x3c,
SET_VAL_FROM = 0x3d,

// @args symbol index, symbol id
// @role Store the value of the symbol #[code primary] into an existing variable #[code secondary]
SET_VAL_FROM_INDEX = 0x3d,
SET_VAL_FROM_INDEX = 0x3e,

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

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

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

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

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

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

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

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

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

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

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

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

// @args builtin id, argument count
// @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
CALL_BUILTIN = 0x4a,
CALL_BUILTIN = 0x4b,

InstructionsCount
};
Expand Down Expand Up @@ -333,6 +336,7 @@ namespace Ark::internal
"POP",
"DUP",
"CREATE_SCOPE",
"RESET_SCOPE",
"POP_SCOPE",
// operators
"ADD",
Expand Down
5 changes: 5 additions & 0 deletions include/Ark/VM/ScopeView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ namespace Ark::internal
return m_storage[m_start + m_size - 1 - i];
}

/**
* @brief Reset size, min and max id for the scope, to signify it's empty
*/
void reset() noexcept;

/**
* @brief Return the size of the scope
*
Expand Down
2 changes: 1 addition & 1 deletion lib/std
Submodule std updated 2 files
+27 −1 String.ark
+13 −1 tests/string-tests.ark
4 changes: 4 additions & 0 deletions src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,10 @@ namespace Ark::internal
// push code to page
compileExpression(x.constList()[2], p, true, false);

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

Expand Down
7 changes: 7 additions & 0 deletions src/arkreactor/VM/ScopeView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ namespace Ark::internal
return std::numeric_limits<uint16_t>::max();
}

void ScopeView::reset() noexcept
{
m_size = 0;
m_min_id = std::numeric_limits<uint16_t>::max();
m_max_id = 0;
}

bool operator==(const ScopeView& A, const ScopeView& B) noexcept
{
// if we have two scopes with the same number of elements and starting at the same position,
Expand Down
7 changes: 7 additions & 0 deletions src/arkreactor/VM/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ namespace Ark
&&TARGET_POP,
&&TARGET_DUP,
&&TARGET_CREATE_SCOPE,
&&TARGET_RESET_SCOPE,
&&TARGET_POP_SCOPE,
&&TARGET_ADD,
&&TARGET_SUB,
Expand Down Expand Up @@ -939,6 +940,12 @@ namespace Ark
DISPATCH();
}

TARGET(RESET_SCOPE)
{
context.locals.back().reset();
DISPATCH();
}

TARGET(POP_SCOPE)
{
context.locals.pop_back();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ page_0
BUILTIN 9
CALL 1
POP 0
RESET_SCOPE 0
GOTO L4
.L5:
POP_SCOPE 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ page_1
LOAD_SYMBOL 3
ADD 0
SET_VAL 3
RESET_SCOPE 0
GOTO L0
.L1:
POP_SCOPE 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ page_0
CALL_BUILTIN 24, 2
CALL_BUILTIN 9, 1
POP 0
RESET_SCOPE 0
GOTO L4
.L5:
POP_SCOPE 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ page_1
SET_VAL 2
INCREMENT 3, 1
SET_VAL 3
RESET_SCOPE 0
GOTO L0
.L1:
POP_SCOPE 0
Expand Down
Loading