Skip to content

Commit ad8dd4a

Browse files
committed
feat(vm, compiler): new operator '@@' to get element in 2D list
1 parent b1a49fd commit ad8dd4a

File tree

14 files changed

+136
-20
lines changed

14 files changed

+136
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- added in place list mutation: `(@= list|string index new_value)`, `(@@= list|list<string> index1 index2 new_value|char)` (bound checked)
3636
- compile time argument count check for `and` and `or`
3737
- basic dead code elimination in the AST optimizer
38+
- new operator `@@` to get elements in list of lists / list of strings
3839

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

include/Ark/Compiler/Common.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ namespace Ark::internal
132132
// This list is related to include/Ark/Compiler/Instructions.hpp
133133
// from FIRST_OPERATOR, to LAST_OPERATOR
134134
// The order is very important
135-
constexpr std::array<std::string_view, 23> operators = {
135+
constexpr std::array<std::string_view, 24> operators = {
136136
"+", "-", "*", "/",
137137
">", "<", "<=", ">=", "!=", "=",
138138
"len", "empty?", "tail", "head",
139139
"nil?", "assert",
140140
"toNumber", "toString",
141-
"@", "mod",
141+
"@", "@@", "mod",
142142
"type", "hasField",
143143
"not"
144144
};

include/Ark/Compiler/Compiler.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@ namespace Ark::internal
142142
*/
143143
static bool isUnaryInst(Instruction inst) noexcept;
144144

145+
/**
146+
* @brief Check if a given instruction is ternary (takes three arguments)
147+
*
148+
* @param inst
149+
* @return true the instruction is ternary
150+
* @return false
151+
*/
152+
static bool isTernaryInst(Instruction inst) noexcept;
153+
145154
/**
146155
* @brief Display a warning message
147156
*

include/Ark/Compiler/Instructions.hpp

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,23 +84,24 @@ namespace Ark::internal
8484
TO_NUM = 0x2e,
8585
TO_STR = 0x2f,
8686
AT = 0x30,
87-
MOD = 0x31,
88-
TYPE = 0x32,
89-
HASFIELD = 0x33,
90-
NOT = 0x34,
87+
AT_AT = 0x31,
88+
MOD = 0x32,
89+
TYPE = 0x33,
90+
HASFIELD = 0x34,
91+
NOT = 0x35,
9192

92-
LOAD_CONST_LOAD_CONST = 0x35,
93-
LOAD_CONST_STORE = 0x36,
94-
LOAD_CONST_SET_VAL = 0x37,
95-
STORE_FROM = 0x38,
96-
SET_VAL_FROM = 0x39,
97-
INCREMENT = 0x3a,
98-
DECREMENT = 0x3b,
99-
STORE_TAIL = 0x3c,
100-
STORE_HEAD = 0x3d,
101-
SET_VAL_TAIL = 0x3e,
102-
SET_VAL_HEAD = 0x3f,
103-
CALL_BUILTIN = 0x40
93+
LOAD_CONST_LOAD_CONST = 0x36,
94+
LOAD_CONST_STORE = 0x37,
95+
LOAD_CONST_SET_VAL = 0x38,
96+
STORE_FROM = 0x39,
97+
SET_VAL_FROM = 0x3a,
98+
INCREMENT = 0x3b,
99+
DECREMENT = 0x3c,
100+
STORE_TAIL = 0x3d,
101+
STORE_HEAD = 0x3e,
102+
SET_VAL_TAIL = 0x3f,
103+
SET_VAL_HEAD = 0x40,
104+
CALL_BUILTIN = 0x41
104105
};
105106

106107
constexpr std::array InstructionNames = {
@@ -154,6 +155,7 @@ namespace Ark::internal
154155
"TO_NUM",
155156
"TO_STR",
156157
"AT",
158+
"AT_AT",
157159
"MOD",
158160
"TYPE",
159161
"HASFIELD",

src/arkreactor/Compiler/Compiler.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,18 @@ namespace Ark::internal
107107
}
108108
}
109109

110+
bool Compiler::isTernaryInst(const Instruction inst) noexcept
111+
{
112+
switch (inst)
113+
{
114+
case AT_AT:
115+
return true;
116+
117+
default:
118+
return false;
119+
}
120+
}
121+
110122
void Compiler::compilerWarning(const std::string& message, const Node& node)
111123
{
112124
fmt::println("{} {}", fmt::styled("Warning", fmt::fg(fmt::color::dark_orange)), Diagnostics::makeContextWithNode(message, node));
@@ -562,7 +574,7 @@ namespace Ark::internal
562574

563575
// in order to be able to handle things like (op A B C D...)
564576
// which should be transformed into A B op C op D op...
565-
if (exp_count >= 2)
577+
if (exp_count >= 2 && !isTernaryInst(op))
566578
page(p).emplace_back(op);
567579
}
568580

@@ -572,6 +584,12 @@ namespace Ark::internal
572584
throwCompilerError(fmt::format("Operator needs one argument, but was called with {}", exp_count), x.constList()[0]);
573585
page(p).emplace_back(op);
574586
}
587+
else if (isTernaryInst(op))
588+
{
589+
if (exp_count != 3)
590+
throwCompilerError(fmt::format("Operator needs three arguments, but was called with {}", exp_count), x.constList()[0]);
591+
page(p).emplace_back(op);
592+
}
575593
else if (exp_count <= 1)
576594
throwCompilerError(fmt::format("Operator needs two arguments, but was called with {}", exp_count), x.constList()[0]);
577595

@@ -585,7 +603,8 @@ namespace Ark::internal
585603
case SUB: [[fallthrough]];
586604
case MUL: [[fallthrough]];
587605
case DIV: [[fallthrough]];
588-
case MOD:
606+
case MOD: [[fallthrough]];
607+
case AT_AT:
589608
break;
590609

591610
default:

src/arkreactor/VM/VM.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ namespace Ark
404404
&&TARGET_TO_NUM,
405405
&&TARGET_TO_STR,
406406
&&TARGET_AT,
407+
&&TARGET_AT_AT,
407408
&&TARGET_MOD,
408409
&&TARGET_TYPE,
409410
&&TARGET_HASFIELD,
@@ -1169,6 +1170,51 @@ namespace Ark
11691170
DISPATCH();
11701171
}
11711172

1173+
TARGET(AT_AT)
1174+
{
1175+
{
1176+
Value* x = popAndResolveAsPtr(context);
1177+
Value* y = popAndResolveAsPtr(context);
1178+
Value list = *popAndResolveAsPtr(context); // be careful, it's not a pointer
1179+
1180+
if (y->valueType() != ValueType::Number || x->valueType() != ValueType::Number ||
1181+
list.valueType() != ValueType::List)
1182+
types::generateError(
1183+
"@@",
1184+
{ { types::Contract {
1185+
{ types::Typedef("src", ValueType::List),
1186+
types::Typedef("y", ValueType::Number),
1187+
types::Typedef("x", ValueType::Number) } } } },
1188+
{ list, *y, *x });
1189+
1190+
long idx_y = static_cast<long>(y->number());
1191+
idx_y = idx_y < 0 ? static_cast<long>(list.list().size()) + idx_y : idx_y;
1192+
if (std::cmp_greater_equal(idx_y, list.list().size()))
1193+
throwVMError(
1194+
ErrorKind::Index,
1195+
fmt::format("@@ index ({}) out of range (list size: {})", idx_y, list.list().size()));
1196+
1197+
const bool is_list = list.list()[static_cast<std::size_t>(idx_y)].valueType() == ValueType::List;
1198+
const std::size_t size =
1199+
is_list
1200+
? list.list()[static_cast<std::size_t>(idx_y)].list().size()
1201+
: list.list()[static_cast<std::size_t>(idx_y)].stringRef().size();
1202+
1203+
long idx_x = static_cast<long>(x->number());
1204+
idx_x = idx_x < 0 ? static_cast<long>(size) + idx_x : idx_x;
1205+
if (std::cmp_greater_equal(idx_x, size))
1206+
throwVMError(
1207+
ErrorKind::Index,
1208+
fmt::format("@@ index (x: {}) out of range (inner indexable size: {})", idx_x, size));
1209+
1210+
if (is_list)
1211+
push(list.list()[static_cast<std::size_t>(idx_y)].list()[static_cast<std::size_t>(idx_x)], context);
1212+
else
1213+
push(Value(std::string(1, list.list()[static_cast<std::size_t>(idx_y)].stringRef()[static_cast<std::size_t>(idx_x)])), context);
1214+
}
1215+
DISPATCH();
1216+
}
1217+
11721218
TARGET(MOD)
11731219
{
11741220
Value *b = popAndResolveAsPtr(context), *a = popAndResolveAsPtr(context);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
(let lst [[0 1 2 3] [4 5 6 7] [8 9 0 1]])
2+
(print (@@ lst 1))
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
At @@ @ 2:9
2+
1 | (let lst [[0 1 2 3] [4 5 6 7] [8 9 0 1]])
3+
2 | (print (@@ lst 1))
4+
| ^~
5+
3 |
6+
Operator needs three arguments, but was called with 2
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
(let lst [[0 1 2 3] [4 5 6 7] [8 9 0 1]])
2+
(print (@@ lst 0 6))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
IndexError: @@ index (x: 6) out of range (inner indexable size: 4)

0 commit comments

Comments
 (0)