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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ __arkscript__/
/*.ark
*.ark.ir
!tests/unittests/resources/BytecodeReaderSuite/*.arkc
tools/*_hash.py

# Generated files
include/Ark/Constants.hpp
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

### Added
- added new macro `$gensym`, to generate a unique symbol identifier to use in macros
- `append`, `concat`, and `pop` can be use as values

### Changed
- all paths inside `if` should return a value, when used as an expression. If an `else` branch is missing, `nil` will be returned
- new compile time error when trying to use `append!`, `concat!`, `pop!`, `@=` and `@@=` as values

### Removed

Expand Down
3 changes: 3 additions & 0 deletions include/Ark/Builtins/Builtins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ namespace Ark::internal::Builtins
ARK_BUILTIN(at);
ARK_BUILTIN(atAt);
ARK_BUILTIN(type);
ARK_BUILTIN(append_list);
ARK_BUILTIN(concat_list);
ARK_BUILTIN(pop_list);
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/arkreactor/Builtins/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ namespace Ark::internal::Builtins
{ "head", Value(Operators::head) },
{ "@", Value(Operators::at) },
{ "@@", Value(Operators::atAt) },
{ "type", Value(Operators::type) }
{ "type", Value(Operators::type) },
{ "append", Value(Operators::append_list) },
{ "concat", Value(Operators::concat_list) },
{ "pop", Value(Operators::pop_list) }
};
}
66 changes: 66 additions & 0 deletions src/arkreactor/Builtins/Operators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,70 @@ namespace Ark::internal::Builtins::Operators

return Value(std::to_string(n[0].valueType()));
}

// cppcheck-suppress constParameterReference
Value append_list(std::vector<Value>& n, VM* vm [[maybe_unused]])
{
if (n.size() < 2 || n[0].valueType() != ValueType::List)
throw types::TypeCheckingError(
"append",
{ { types::Contract {
{ types::Typedef("list", ValueType::List),
types::Typedef("value", ValueType::Any, /* is_variadic= */ true) } } } },
n);

for (Value& e : n | std::ranges::views::drop(1))
n[0].list().push_back(e);

return n[0];
}

// cppcheck-suppress constParameterReference
Value concat_list(std::vector<Value>& n, VM* vm [[maybe_unused]])
{
if (n.size() < 2 || n[0].valueType() != ValueType::List)
throw types::TypeCheckingError(
"concat",
{ { types::Contract {
{ types::Typedef("list", ValueType::List),
types::Typedef("value", ValueType::List, /* is_variadic= */ true) } } } },
n);

for (Value& e : n | std::ranges::views::drop(1))
{
if (e.valueType() != ValueType::List)
throw types::TypeCheckingError(
"concat",
{ { types::Contract {
{ types::Typedef("dst", ValueType::List),
types::Typedef("src", ValueType::List, /* is_variadic= */ true) } } } },
n);

std::ranges::copy(e.list(), std::back_inserter(n[0].list()));
}

return n[0];
}

// cppcheck-suppress constParameterReference
Value pop_list(std::vector<Value>& n, VM* vm [[maybe_unused]])
{
if (!types::check(n, ValueType::List, ValueType::Number))
throw types::TypeCheckingError(
"pop",
{ { types::Contract {
{ types::Typedef("list", ValueType::List),
types::Typedef("index", ValueType::Number) } } } },
n);

long idx = static_cast<long>(n[1].number());
idx = idx < 0 ? static_cast<long>(n[0].list().size()) + idx : idx;
if (std::cmp_greater_equal(idx, n[0].list().size()) || idx < 0)
VM::throwVMError(
ErrorKind::Index,
fmt::format("pop index ({}) out of range (list size: {})", idx, n[0].list().size()));

n[0].list().erase(n[0].list().begin() + idx);
return n[0];
}
}
4 changes: 4 additions & 0 deletions src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ namespace Ark::internal

if (const auto it_builtin = getBuiltin(name))
page(p).emplace_back(Instruction::BUILTIN, it_builtin.value());
else if (std::ranges::find(Language::UpdateRef, name) != Language::UpdateRef.end())
buildAndThrowError(fmt::format("`{}' updates a list in-place, and can not be used as a value. Prefer using their copy alternative (without the `!` at the end) when possible", name), x);
else if (name == Language::And || name == Language::Or)
buildAndThrowError(fmt::format("`{}' can not be used as a value like `+', where (let add +) (add 1 2) would be valid", name), x);
else if (getOperator(name).has_value())
buildAndThrowError(fmt::format("Found a freestanding operator: `{}`. It can not be used as value like `+', where (let add +) (add 1 2) would be valid", name), x);
else
Expand Down
5 changes: 4 additions & 1 deletion tests/unittests/resources/CompilerSuite/ir/operators.ark
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@
(head [])
(@ [1 2] 1)
(@@ [[1] [2] [3]] 0 0)
(type 12))
(type 12)
(append [] 1)
(concat [1] [2])
(pop [1] 0))
14 changes: 13 additions & 1 deletion tests/unittests/resources/CompilerSuite/ir/operators.expected
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,19 @@ page_0
AT_AT 0
LOAD_CONST 3
TYPE 0
CALL_BUILTIN 9, 22
LOAD_CONST 0
LIST 0
APPEND 1
LOAD_CONST 1
LIST 1
LOAD_CONST 0
LIST 1
CONCAT 1
LOAD_CONST 5
LOAD_CONST 0
LIST 1
POP_LIST 0
CALL_BUILTIN 9, 25
.L0:
POP 0
HALT 0
Original file line number Diff line number Diff line change
@@ -1 +1 @@
(print + - * / mod toNumber toString < <= > >= = != not len empty? nil? tail head @ @@ type)
(print + - * / mod toNumber toString < <= > >= = != not len empty? nil? tail head @ @@ type append concat pop)
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ page_0
BUILTIN 88
BUILTIN 89
BUILTIN 90
CALL_BUILTIN 9, 22
BUILTIN 91
BUILTIN 92
BUILTIN 93
CALL_BUILTIN 9, 25
.L0:
POP 0
HALT 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(let a and)
(a 1 2)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
In file tests/unittests/resources/DiagnosticsSuite/compileTime/let_a_and.ark:1
1 | (let a and)
| ^~~
2 | (a 1 2)
3 |
`and' can not be used as a value like `+', where (let add +) (add 1 2) would be valid
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(let a append!)
(mut b [])
(a b 5)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
In file tests/unittests/resources/DiagnosticsSuite/compileTime/let_a_append_in_place.ark:1
1 | (let a append!)
| ^~~~~~~
2 | (mut b [])
3 | (a b 5)
`append!' updates a list in-place, and can not be used as a value. Prefer using their copy alternative (without the `!` at the end) when possible
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(let a @@=)
(mut b [[]])
(a b 5 6 7)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
In file tests/unittests/resources/DiagnosticsSuite/compileTime/let_a_at_at_eq.ark:1
1 | (let a @@=)
| ^~~
2 | (mut b [[]])
3 | (a b 5 6 7)
`@@=' updates a list in-place, and can not be used as a value. Prefer using their copy alternative (without the `!` at the end) when possible
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(let a @=)
(mut b [])
(a b 5 6)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
In file tests/unittests/resources/DiagnosticsSuite/compileTime/let_a_at_eq.ark:1
1 | (let a @=)
| ^~
2 | (mut b [])
3 | (a b 5 6)
`@=' updates a list in-place, and can not be used as a value. Prefer using their copy alternative (without the `!` at the end) when possible
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(let a concat!)
(mut b [])
(a b [5])
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
In file tests/unittests/resources/DiagnosticsSuite/compileTime/let_a_concat_in_place.ark:1
1 | (let a concat!)
| ^~~~~~~
2 | (mut b [])
3 | (a b [5])
`concat!' updates a list in-place, and can not be used as a value. Prefer using their copy alternative (without the `!` at the end) when possible
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(let a or)
(a 1 2)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
In file tests/unittests/resources/DiagnosticsSuite/compileTime/let_a_or.ark:1
1 | (let a or)
| ^~
2 | (a 1 2)
3 |
`or' can not be used as a value like `+', where (let add +) (add 1 2) would be valid
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(let a pop!)
(mut b [])
(a b 5)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
In file tests/unittests/resources/DiagnosticsSuite/compileTime/let_a_pop_in_place.ark:1
1 | (let a pop!)
| ^~~~
2 | (mut b [])
3 | (a b 5)
`pop!' updates a list in-place, and can not be used as a value. Prefer using their copy alternative (without the `!` at the end) when possible
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(apply pop [[1 2 3] 4])
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
IndexError: pop index (4) out of range (list size: 3)

In file tests/unittests/resources/DiagnosticsSuite/runtime/apply_pop_out_of_range.ark:1
1 | (apply pop [[1 2 3] 4])
| ^~~~~~~~~~~~~~~~~~~~~~
2 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(apply pop [[1 2 3] -4])
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
IndexError: pop index (-1) out of range (list size: 3)

In file tests/unittests/resources/DiagnosticsSuite/runtime/apply_pop_out_of_range_neg.ark:1
1 | (apply pop [[1 2 3] -4])
| ^~~~~~~~~~~~~~~~~~~~~~~
2 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(apply append [[1]])
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Function append expected at least 2 arguments but got 1
Call
↳ (append [1])
Signature
↳ (append list value)
Arguments
→ `list' (expected List) ✓
→ variadic `value' (expected any) was not provided

In file tests/unittests/resources/DiagnosticsSuite/typeChecking/apply_append_list.ark:1
1 | (apply append [[1]])
| ^~~~~~~~~~~~~~~~~~~
2 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(apply append [1 2])
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Function append expected at least 2 arguments and got 2
Call
↳ (append 1 2)
Signature
↳ (append list value)
Arguments
→ `list' (expected List), got 1 (Number)
→ variadic `value' (expected any)

In file tests/unittests/resources/DiagnosticsSuite/typeChecking/apply_append_num_num.ark:1
1 | (apply append [1 2])
| ^~~~~~~~~~~~~~~~~~~
2 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(apply concat [[1]])
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Function concat expected at least 2 arguments but got 1
Call
↳ (concat [1])
Signature
↳ (concat list value)
Arguments
→ `list' (expected List) ✓
→ variadic `value' (expected List) was not provided

In file tests/unittests/resources/DiagnosticsSuite/typeChecking/apply_concat_list.ark:1
1 | (apply concat [[1]])
| ^~~~~~~~~~~~~~~~~~~
2 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(apply concat [[1] 1])
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Function concat expected at least 2 arguments and got 2
Call
↳ (concat [1] 1)
Signature
↳ (concat dst src)
Arguments
→ `dst' (expected List) ✓
→ variadic `src' (expected List): 1 argument do not match:
1 (Number) ×

In file tests/unittests/resources/DiagnosticsSuite/typeChecking/apply_concat_list_num.ark:1
1 | (apply concat [[1] 1])
| ^~~~~~~~~~~~~~~~~~~~~
2 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(apply concat [1])
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Function concat expected at least 2 arguments but got 1
Call
↳ (concat 1)
Signature
↳ (concat list value)
Arguments
→ `list' (expected List), got 1 (Number)
→ variadic `value' (expected List) was not provided

In file tests/unittests/resources/DiagnosticsSuite/typeChecking/apply_concat_num.ark:1
1 | (apply concat [1])
| ^~~~~~~~~~~~~~~~~
2 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(apply pop [1 1])
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Function pop expected 2 arguments
Call
↳ (pop 1 1)
Signature
↳ (pop list index)
Arguments
→ `list' (expected List), got 1 (Number)
→ `index' (expected Number) ✓

In file tests/unittests/resources/DiagnosticsSuite/typeChecking/apply_pop_num_num.ark:1
1 | (apply pop [1 1])
| ^~~~~~~~~~~~~~~~
2 |
16 changes: 15 additions & 1 deletion tests/unittests/resources/LangSuite/operators-tests.ark
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,18 @@
(test:eq (apply type [1]) (type 1))
(test:eq (apply type [1]) "Number")
(test:eq (apply type [nil]) (type nil))
(test:eq (apply type [nil]) "Nil") })})
(test:eq (apply type [nil]) "Nil") })

(test:case "append" {
(test:eq (apply append [[] 1]) [1])
(test:eq (apply append [[] 1 2]) [1 2])
(test:eq (apply append [[] 1 2 3]) [1 2 3]) })

(test:case "concat" {
(test:eq (apply concat [[] [1]]) [1])
(test:eq (apply concat [[] [1] [2 3]]) [1 2 3])
(test:eq (apply concat [[] [1] [2 3] [] [4 5 6]]) [1 2 3 4 5 6]) })

(test:case "pop" {
(test:eq (apply pop [[1 2] 0]) [2])
(test:eq (apply pop [[1] 0]) []) }) })
Loading
Loading