Skip to content

Commit

Permalink
feat(vm, compiler): new operator '@@' to get element in 2D list
Browse files Browse the repository at this point in the history
  • Loading branch information
SuperFola committed Dec 17, 2024
1 parent b1a49fd commit ad8dd4a
Show file tree
Hide file tree
Showing 14 changed files with 136 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
- added in place list mutation: `(@= list|string index new_value)`, `(@@= list|list<string> index1 index2 new_value|char)` (bound checked)
- compile time argument count check for `and` and `or`
- basic dead code elimination in the AST optimizer
- new operator `@@` to get elements in list of lists / list of strings

### Changed
- instructions are on 4 bytes: 1 byte for the instruction, 1 byte of padding, 2 bytes for an immediate argument
Expand Down
4 changes: 2 additions & 2 deletions include/Ark/Compiler/Common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,13 @@ namespace Ark::internal
// This list is related to include/Ark/Compiler/Instructions.hpp
// from FIRST_OPERATOR, to LAST_OPERATOR
// The order is very important
constexpr std::array<std::string_view, 23> operators = {
constexpr std::array<std::string_view, 24> operators = {
"+", "-", "*", "/",
">", "<", "<=", ">=", "!=", "=",
"len", "empty?", "tail", "head",
"nil?", "assert",
"toNumber", "toString",
"@", "mod",
"@", "@@", "mod",
"type", "hasField",
"not"
};
Expand Down
9 changes: 9 additions & 0 deletions include/Ark/Compiler/Compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ namespace Ark::internal
*/
static bool isUnaryInst(Instruction inst) noexcept;

/**
* @brief Check if a given instruction is ternary (takes three arguments)
*
* @param inst
* @return true the instruction is ternary
* @return false
*/
static bool isTernaryInst(Instruction inst) noexcept;

/**
* @brief Display a warning message
*
Expand Down
34 changes: 18 additions & 16 deletions include/Ark/Compiler/Instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,23 +84,24 @@ namespace Ark::internal
TO_NUM = 0x2e,
TO_STR = 0x2f,
AT = 0x30,
MOD = 0x31,
TYPE = 0x32,
HASFIELD = 0x33,
NOT = 0x34,
AT_AT = 0x31,
MOD = 0x32,
TYPE = 0x33,
HASFIELD = 0x34,
NOT = 0x35,

LOAD_CONST_LOAD_CONST = 0x35,
LOAD_CONST_STORE = 0x36,
LOAD_CONST_SET_VAL = 0x37,
STORE_FROM = 0x38,
SET_VAL_FROM = 0x39,
INCREMENT = 0x3a,
DECREMENT = 0x3b,
STORE_TAIL = 0x3c,
STORE_HEAD = 0x3d,
SET_VAL_TAIL = 0x3e,
SET_VAL_HEAD = 0x3f,
CALL_BUILTIN = 0x40
LOAD_CONST_LOAD_CONST = 0x36,
LOAD_CONST_STORE = 0x37,
LOAD_CONST_SET_VAL = 0x38,
STORE_FROM = 0x39,
SET_VAL_FROM = 0x3a,
INCREMENT = 0x3b,
DECREMENT = 0x3c,
STORE_TAIL = 0x3d,
STORE_HEAD = 0x3e,
SET_VAL_TAIL = 0x3f,
SET_VAL_HEAD = 0x40,
CALL_BUILTIN = 0x41
};

constexpr std::array InstructionNames = {
Expand Down Expand Up @@ -154,6 +155,7 @@ namespace Ark::internal
"TO_NUM",
"TO_STR",
"AT",
"AT_AT",
"MOD",
"TYPE",
"HASFIELD",
Expand Down
23 changes: 21 additions & 2 deletions src/arkreactor/Compiler/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ namespace Ark::internal
}
}

bool Compiler::isTernaryInst(const Instruction inst) noexcept
{
switch (inst)
{
case AT_AT:
return true;

default:
return false;
}
}

void Compiler::compilerWarning(const std::string& message, const Node& node)
{
fmt::println("{} {}", fmt::styled("Warning", fmt::fg(fmt::color::dark_orange)), Diagnostics::makeContextWithNode(message, node));
Expand Down Expand Up @@ -562,7 +574,7 @@ namespace Ark::internal

// in order to be able to handle things like (op A B C D...)
// which should be transformed into A B op C op D op...
if (exp_count >= 2)
if (exp_count >= 2 && !isTernaryInst(op))
page(p).emplace_back(op);
}

Expand All @@ -572,6 +584,12 @@ namespace Ark::internal
throwCompilerError(fmt::format("Operator needs one argument, but was called with {}", exp_count), x.constList()[0]);
page(p).emplace_back(op);
}
else if (isTernaryInst(op))
{
if (exp_count != 3)
throwCompilerError(fmt::format("Operator needs three arguments, but was called with {}", exp_count), x.constList()[0]);
page(p).emplace_back(op);
}
else if (exp_count <= 1)
throwCompilerError(fmt::format("Operator needs two arguments, but was called with {}", exp_count), x.constList()[0]);

Expand All @@ -585,7 +603,8 @@ namespace Ark::internal
case SUB: [[fallthrough]];
case MUL: [[fallthrough]];
case DIV: [[fallthrough]];
case MOD:
case MOD: [[fallthrough]];
case AT_AT:
break;

default:
Expand Down
46 changes: 46 additions & 0 deletions src/arkreactor/VM/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ namespace Ark
&&TARGET_TO_NUM,
&&TARGET_TO_STR,
&&TARGET_AT,
&&TARGET_AT_AT,
&&TARGET_MOD,
&&TARGET_TYPE,
&&TARGET_HASFIELD,
Expand Down Expand Up @@ -1169,6 +1170,51 @@ namespace Ark
DISPATCH();
}

TARGET(AT_AT)
{
{
Value* x = popAndResolveAsPtr(context);
Value* y = popAndResolveAsPtr(context);
Value list = *popAndResolveAsPtr(context); // be careful, it's not a pointer

if (y->valueType() != ValueType::Number || x->valueType() != ValueType::Number ||
list.valueType() != ValueType::List)
types::generateError(
"@@",
{ { types::Contract {
{ types::Typedef("src", ValueType::List),
types::Typedef("y", ValueType::Number),
types::Typedef("x", ValueType::Number) } } } },
{ list, *y, *x });

long idx_y = static_cast<long>(y->number());
idx_y = idx_y < 0 ? static_cast<long>(list.list().size()) + idx_y : idx_y;
if (std::cmp_greater_equal(idx_y, list.list().size()))
throwVMError(
ErrorKind::Index,
fmt::format("@@ index ({}) out of range (list size: {})", idx_y, list.list().size()));

const bool is_list = list.list()[static_cast<std::size_t>(idx_y)].valueType() == ValueType::List;
const std::size_t size =
is_list
? list.list()[static_cast<std::size_t>(idx_y)].list().size()
: list.list()[static_cast<std::size_t>(idx_y)].stringRef().size();

long idx_x = static_cast<long>(x->number());
idx_x = idx_x < 0 ? static_cast<long>(size) + idx_x : idx_x;
if (std::cmp_greater_equal(idx_x, size))
throwVMError(
ErrorKind::Index,
fmt::format("@@ index (x: {}) out of range (inner indexable size: {})", idx_x, size));

if (is_list)
push(list.list()[static_cast<std::size_t>(idx_y)].list()[static_cast<std::size_t>(idx_x)], context);
else
push(Value(std::string(1, list.list()[static_cast<std::size_t>(idx_y)].stringRef()[static_cast<std::size_t>(idx_x)])), context);
}
DISPATCH();
}

TARGET(MOD)
{
Value *b = popAndResolveAsPtr(context), *a = popAndResolveAsPtr(context);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(let lst [[0 1 2 3] [4 5 6 7] [8 9 0 1]])
(print (@@ lst 1))
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
At @@ @ 2:9
1 | (let lst [[0 1 2 3] [4 5 6 7] [8 9 0 1]])
2 | (print (@@ lst 1))
| ^~
3 |
Operator needs three arguments, but was called with 2
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(let lst [[0 1 2 3] [4 5 6 7] [8 9 0 1]])
(print (@@ lst 0 6))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
IndexError: @@ index (x: 6) out of range (inner indexable size: 4)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(let lst [[0 1 2 3] [4 5 6 7] [8 9 0 1]])
(print (@@ lst 3 1))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
IndexError: @@ index (3) out of range (list size: 3)
9 changes: 9 additions & 0 deletions tests/unittests/resources/LangSuite/list-tests.ark
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@
(test:eq (list:setAt [0 1 2 3] 3 9) [0 1 2 9])
(test:eq (list:setAt [0 1 2 9] -1 9) [0 1 2 9]) })

(test:case "get element in 2D list" {
(let nested_list [[0 1 2] [3 4 5] [6 7 8]])
(test:eq 0 (@@ nested_list 0 0))
(test:eq 2 (@@ nested_list 0 -1))
(test:eq 1 (@@ nested_list 0 -2))
(test:eq 8 (@@ nested_list -1 -1))
(test:eq 4 (@@ nested_list 1 1))
(test:eq 4 (@@ nested_list -2 1)) })

(test:case "in place mutation with @=" {
(mut numbers [0 1 2 3 4])
(@= numbers 2 5)
Expand Down
16 changes: 16 additions & 0 deletions tests/unittests/resources/LangSuite/string-tests.ark
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@
(test:eq (string:find "abcdefghijkl" "defghijkl") 3)
(test:eq (string:find "abcdabcdabcd" "abcd" 2) 4) })

(test:case "get char in string" {
(test:eq "a" (@ "abc" 0))
(test:eq "c" (@ "abc" -1))
(test:eq "b" (@ "abc" -2))
(test:eq "b" (@ "abc" 1)) })

(test:case "get char in list of strings" {
(let nested_strings ["abc" "def" "ijk"])
(test:eq "a" (@@ nested_strings 0 0))
(test:eq "b" (@@ nested_strings -3 1))
(test:eq "c" (@@ nested_strings 0 -1))
(test:eq "k" (@@ nested_strings -1 -1))
(test:eq "i" (@@ nested_strings 2 0))
(test:eq "e" (@@ nested_strings 1 1))
(test:eq "e" (@@ nested_strings 1 -2)) })

(test:case "update string" {
(test:eq (string:setAt "hello" 0 "a") "aello")
(test:eq (string:setAt "hello" -1 "a") "hella")
Expand Down

0 comments on commit ad8dd4a

Please sign in to comment.