From 91b2d3fcd73853e67100c5898b1a853adb7fe78b Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Thu, 12 Mar 2026 14:51:50 +0100 Subject: [PATCH 1/5] feat: ARK-344, pop! return the removed value, @= and @@= return the inserted value --- CHANGELOG.md | 2 + docs/arkdoc/List.txt | 24 +++++++++++- docs/arkdoc/String.txt | 22 +++++++++++ src/arkreactor/Compiler/BytecodeReader.cpp | 4 ++ .../Compiler/Lowerer/ASTLowerer.cpp | 37 ++++++++++++++----- src/arkreactor/VM/VM.cpp | 23 ++++++++++++ .../resources/LangSuite/list-tests.ark | 14 ++++--- .../resources/ParserSuite/success/compact.ark | 5 +++ .../ParserSuite/success/compact.expected | 5 +++ 9 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 tests/unittests/resources/ParserSuite/success/compact.ark create mode 100644 tests/unittests/resources/ParserSuite/success/compact.expected diff --git a/CHANGELOG.md b/CHANGELOG.md index 12ccef768..909283dfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ - display a warning to `stderr` when using a deprecated function/value (checks for `@deprecated` inside the attached comment of functions / values) ### Changed +- `pop!` can return the removed value +- `@=` and `@@=` return the inserted value ### Removed diff --git a/docs/arkdoc/List.txt b/docs/arkdoc/List.txt index ef846fab8..fcdab9315 100644 --- a/docs/arkdoc/List.txt +++ b/docs/arkdoc/List.txt @@ -87,7 +87,7 @@ --# * @name pop! -* @brief Remove an element from a list in place, given its index. It doesn't return anything +* @brief Remove an element from a list in place, given its index. Return the removed element * @details Supports negative indices, -1 being the end. * @param lst a list. Must be mutable * @param index number @@ -157,3 +157,25 @@ * (print (@@ ["abc" "def" "ghi"] 0 -1)) # c * =end #-- + +--# +* @name @= +* @brief Set an element in a list, in place +* @details Return the newly added element +* @param lst list +* @param index number (can be negative to start from the end) +* @param x value +* =begin +* (mut lst [1 2 3 4 5]) +* (print (@= lst 0 "x")) # "x" +* (print lst) # ["x" 2 3 4 5] +* (print (@= lst 1 "y")) # "y" +* (print lst) # ["x" "y" 3 4 5] +* (print (@= lst 2 "z")) # "z" +* (print lst) # ["x" "y" "z" 4 5] +* (@= lst -1 "f") +* (print lst) # ["x" "y" "z" 4 "f"] +* (@= lst -2 "g") +* (print lst) # ["x" "y" "z" "g" "f"] +* =end +#-- diff --git a/docs/arkdoc/String.txt b/docs/arkdoc/String.txt index f0eea36a6..18e567179 100644 --- a/docs/arkdoc/String.txt +++ b/docs/arkdoc/String.txt @@ -77,3 +77,25 @@ * (print (@ "abc" -2)) # "b" * =end #-- + +--# +* @name @= +* @brief Set a character in a string, in place +* @details Return the newly added character +* @param str string +* @param index number (can be negative to start from the end) +* @param char character +* =begin +* (mut str "abcde") +* (print (@= str 0 "x")) # "x" +* (print str) # "xbcde" +* (print (@= str 1 "y")) # "y" +* (print str) # "xycde" +* (print (@= str 2 "z")) # "z" +* (print str) # "xyzde" +* (@= str -1 "f") +* (print str) # "xyzdf" +* (@= str -2 "g") +* (print str) # "xyzgf" +* =end +#-- diff --git a/src/arkreactor/Compiler/BytecodeReader.cpp b/src/arkreactor/Compiler/BytecodeReader.cpp index b51f5be0a..ce1c294e0 100644 --- a/src/arkreactor/Compiler/BytecodeReader.cpp +++ b/src/arkreactor/Compiler/BytecodeReader.cpp @@ -513,6 +513,10 @@ namespace Ark { CONCAT, ArgKind::Raw }, { APPEND_IN_PLACE, ArgKind::Raw }, { CONCAT_IN_PLACE, ArgKind::Raw }, + { POP_LIST, ArgKind::Raw }, + { POP_LIST_IN_PLACE, ArgKind::Raw }, + { SET_AT_INDEX, ArgKind::Raw }, + { SET_AT_2_INDEX, ArgKind::Raw }, { RESET_SCOPE_JUMP, ArgKind::Raw }, { GET_CURRENT_PAGE_ADDR, ArgKind::Symbol }, { LOAD_CONST_LOAD_CONST, ArgKind::ConstConst }, diff --git a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp index d595ed83a..7e0d6e60e 100644 --- a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp +++ b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp @@ -95,7 +95,7 @@ namespace Ark::internal bool ASTLowerer::nodeProducesOutput(const Node& node) { if (node.nodeType() == NodeType::List && !node.constList().empty() && node.constList()[0].nodeType() == NodeType::Keyword) - // a begin node produces a value if the last node in it produces a value + // a 'begin' node produces a value if the last node in it produces a value return (node.constList()[0].keyword() == Keyword::Begin && node.constList().size() > 1 && nodeProducesOutput(node.constList().back())) || // a function always produces a value ; even if it ends with a node not producing one, the VM returns nil node.constList()[0].keyword() == Keyword::Fun || @@ -103,10 +103,14 @@ namespace Ark::internal (node.constList()[0].keyword() == Keyword::If && nodeProducesOutput(node.constList()[2]) && (node.constList().size() == 3 || nodeProducesOutput(node.constList()[3]))); - // in place list instruction, as well as breakpoint, do not produce values + // append! and concat! instructions, as well as breakpoint, do not produce values if (node.nodeType() == NodeType::List && !node.constList().empty() && node.constList()[0].nodeType() == NodeType::Symbol) - return std::ranges::find(Language::UpdateRef, node.constList().front().string()) == Language::UpdateRef.end() && - node.constList().front().string() != "breakpoint"; + { + const std::string& name = node.constList().front().string(); + return name != Language::AppendInPlace && + name != Language::ConcatInPlace && + name != "breakpoint"; + } return true; // any other node, function call, symbol, number... } @@ -332,15 +336,15 @@ namespace Ark::internal void ASTLowerer::compileListInstruction(Node& x, const Page p, const bool is_result_unused) { const Node head = x.constList()[0]; - std::string name = x.constList()[0].string(); - Instruction inst = getListInstruction(name).value(); + const std::string& name = head.string(); + const Instruction inst = getListInstruction(name).value(); // length of at least 1 since we got a symbol name const auto argc = x.constList().size() - 1u; // error, can not use append/concat/pop (and their in place versions) with a <2 length argument list - if (argc < 2 && APPEND <= inst && inst <= POP) + if (argc < 2 && APPEND <= inst && inst <= SET_AT_2_INDEX) buildAndThrowError(fmt::format("Can not use {} with less than 2 arguments", name), head); - if (inst <= POP && std::cmp_greater(argc, MaxValue16Bits)) + if (std::cmp_greater(argc, MaxValue16Bits)) buildAndThrowError(fmt::format("Too many arguments ({}), exceeds {}", argc, MaxValue16Bits), x); if (argc != 3 && inst == SET_AT_INDEX) buildAndThrowError(fmt::format("Expected 3 arguments (list, index, value) for {}, got {}", name, argc), head); @@ -366,24 +370,37 @@ namespace Ark::internal break; case APPEND: + [[fallthrough]]; case APPEND_IN_PLACE: + [[fallthrough]]; case CONCAT: + [[fallthrough]]; case CONCAT_IN_PLACE: inst_argc = argc - 1; break; case POP_LIST: - case POP_LIST_IN_PLACE: inst_argc = 0; break; + case SET_AT_INDEX: + [[fallthrough]]; + case SET_AT_2_INDEX: + [[fallthrough]]; + case POP_LIST_IN_PLACE: + inst_argc = is_result_unused ? 0 : 1; + break; + default: break; } page(p).emplace_back(inst, static_cast(inst_argc)); page(p).back().setSourceLocation(head.filename(), head.position().start.line); - if (is_result_unused && name.back() != '!' && inst <= POP_LIST_IN_PLACE) // in-place functions never push a value + // append! and concat! do not push anything to the stack (for now) + // pop!, @= and @@= can push to the stack, but not using its returned value isn't an error + if (is_result_unused && inst != APPEND_IN_PLACE && inst != CONCAT_IN_PLACE && + inst != POP_LIST_IN_PLACE && inst != SET_AT_INDEX && inst != SET_AT_2_INDEX) { warning("Ignoring return value of function", x); page(p).emplace_back(POP); diff --git a/src/arkreactor/VM/VM.cpp b/src/arkreactor/VM/VM.cpp index 6f6733811..71dee2df2 100644 --- a/src/arkreactor/VM/VM.cpp +++ b/src/arkreactor/VM/VM.cpp @@ -920,7 +920,14 @@ namespace Ark ErrorKind::Index, fmt::format("pop! index ({}) out of range (list size: {})", idx, list->list().size())); + // Save the value we're removing to push it later. + // We need to save the value and push later because we're using a pointer to 'list', and pushing before erasing + // would overwrite values from the stack. + if (arg) + number = list->list()[static_cast(idx)]; list->list().erase(list->list().begin() + idx); + if (arg) + push(number, context); } DISPATCH(); } @@ -954,9 +961,17 @@ namespace Ark fmt::format("@= index ({}) out of range (indexable size: {})", idx, size)); if (list->valueType() == ValueType::List) + { list->list()[static_cast(idx)] = new_value; + if (arg) + push(new_value, context); + } else + { list->stringRef()[static_cast(idx)] = new_value.string()[0]; + if (arg) + push(Value(new_value.string()[0]), context); + } } DISPATCH(); } @@ -1016,9 +1031,17 @@ namespace Ark fmt::format("@@= index (x: {}) out of range (inner indexable size: {})", idx_x, size)); if (is_list) + { list->list()[static_cast(idx_y)].list()[static_cast(idx_x)] = new_value; + if (arg) + push(new_value, context); + } else + { list->list()[static_cast(idx_y)].stringRef()[static_cast(idx_x)] = new_value.string()[0]; + if (arg) + push(Value(new_value.string()[0]), context); + } } DISPATCH(); } diff --git a/tests/unittests/resources/LangSuite/list-tests.ark b/tests/unittests/resources/LangSuite/list-tests.ark index a363d9a3c..25a9492c8 100644 --- a/tests/unittests/resources/LangSuite/list-tests.ark +++ b/tests/unittests/resources/LangSuite/list-tests.ark @@ -105,15 +105,15 @@ (test:case "in place mutation with @=" { (mut numbers [0 1 2 3 4]) - (@= numbers 2 5) - (@= numbers -1 9) + (test:eq (@= numbers 2 5) 5) + (test:eq (@= numbers -1 9) 9) (@= numbers -2 8) (test:eq numbers [0 1 5 8 9] "@=") }) (test:case "in place 2D mutation with @@=" { (mut numbers [[0 1 2 3] [4 5 6 7] [8 9 0 1]]) - (@@= numbers 0 0 9) - (@@= numbers 1 1 "a") + (test:eq (@@= numbers 0 0 9) 9) + (test:eq (@@= numbers 1 1 "a") "a") (@@= numbers -1 -1 -1) (@@= numbers -2 -2 -2) (test:eq numbers [[9 1 2 3] [4 "a" -2 7] [8 9 0 -1]]) }) @@ -126,9 +126,11 @@ (concat! c d) (test:eq c [1 2 3 4 4 5 6]) (test:eq d [4 5 6]) - (pop! c -1) + (test:eq (pop! c -1) 6) (test:eq c [1 2 3 4 4 5]) - (pop! c 1) + (test:eq (pop! c 1) 2) (test:eq c [1 3 4 4 5]) + (pop! c 0) + (test:eq c [3 4 4 5]) (test:eq a [1 2 3]) (test:eq b [4 5 6]) })}) diff --git a/tests/unittests/resources/ParserSuite/success/compact.ark b/tests/unittests/resources/ParserSuite/success/compact.ark new file mode 100644 index 000000000..2f0ecbf8e --- /dev/null +++ b/tests/unittests/resources/ParserSuite/success/compact.ark @@ -0,0 +1,5 @@ +(+ 1a) +(- 2b) +(* 0c) +(print 1"hello"d) +(concat[1][2]) diff --git a/tests/unittests/resources/ParserSuite/success/compact.expected b/tests/unittests/resources/ParserSuite/success/compact.expected new file mode 100644 index 000000000..9a5a7d23e --- /dev/null +++ b/tests/unittests/resources/ParserSuite/success/compact.expected @@ -0,0 +1,5 @@ +( Symbol:+ Number:1 Symbol:a ) +( Symbol:- Number:2 Symbol:b ) +( Symbol:* Number:0 Symbol:c ) +( Symbol:print Number:1 String:hello Symbol:d ) +( Symbol:concat ( Symbol:list Number:1 ) ( Symbol:list Number:2 ) ) From bc94ca6bee398e44704548669227726a9c2e51c4 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Thu, 12 Mar 2026 15:35:20 +0100 Subject: [PATCH 2/5] feat: ARK-344, append! and concat! return the modified list --- CHANGELOG.md | 1 + docs/arkdoc/List.txt | 4 +-- .../Compiler/Lowerer/ASTLowerer.cpp | 19 +++++++----- .../CompilerSuite/optimized_ir/lists.ark | 9 ++++++ .../CompilerSuite/optimized_ir/lists.expected | 31 ++++++++++++++++--- .../compileTime/apply_invalid_node.ark | 2 +- .../compileTime/apply_invalid_node.expected | 4 +-- .../resources/LangSuite/list-tests.ark | 4 +-- 8 files changed, 54 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 909283dfd..c34a8409f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ### Changed - `pop!` can return the removed value - `@=` and `@@=` return the inserted value +- `append!` and `concat!` return the modified list ### Removed diff --git a/docs/arkdoc/List.txt b/docs/arkdoc/List.txt index fcdab9315..32c031ec7 100644 --- a/docs/arkdoc/List.txt +++ b/docs/arkdoc/List.txt @@ -35,7 +35,7 @@ --# * @name append! -* @brief Add an element to a list, modifying it in place. It doesn't return anything +* @brief Add an element to a list, modifying it in place. Return the modified list * @param lst a list. Must be mutable * @param element * =begin @@ -60,7 +60,7 @@ --# * @name concat! -* @brief Concatenate two lists in place, modifying the first one it in place. It doesn't return anything +* @brief Concatenate two lists in place, modifying the first one it in place. Return the modified list * @param lst a list. Must be mutable * @param more another list * =begin diff --git a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp index 7e0d6e60e..3ce2233d7 100644 --- a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp +++ b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp @@ -103,13 +103,11 @@ namespace Ark::internal (node.constList()[0].keyword() == Keyword::If && nodeProducesOutput(node.constList()[2]) && (node.constList().size() == 3 || nodeProducesOutput(node.constList()[3]))); - // append! and concat! instructions, as well as breakpoint, do not produce values + // breakpoint do not produce values if (node.nodeType() == NodeType::List && !node.constList().empty() && node.constList()[0].nodeType() == NodeType::Symbol) { const std::string& name = node.constList().front().string(); - return name != Language::AppendInPlace && - name != Language::ConcatInPlace && - name != "breakpoint"; + return name != "breakpoint"; } return true; // any other node, function call, symbol, number... } @@ -397,10 +395,15 @@ namespace Ark::internal page(p).emplace_back(inst, static_cast(inst_argc)); page(p).back().setSourceLocation(head.filename(), head.position().start.line); - // append! and concat! do not push anything to the stack (for now) - // pop!, @= and @@= can push to the stack, but not using its returned value isn't an error - if (is_result_unused && inst != APPEND_IN_PLACE && inst != CONCAT_IN_PLACE && - inst != POP_LIST_IN_PLACE && inst != SET_AT_INDEX && inst != SET_AT_2_INDEX) + if (!is_result_unused && (inst == APPEND_IN_PLACE || inst == CONCAT_IN_PLACE)) + { + // Load the first argument which should be a symbol (or field), + // that append!/concat! write to, so that we have its new value available. + compileExpression(x.list()[1], p, false, false); + } + + // append!, concat!, pop!, @= and @@= can push to the stack, but not using its returned value isn't an error + if (is_result_unused && (inst == LIST || inst == APPEND || inst == CONCAT || inst == POP_LIST)) { warning("Ignoring return value of function", x); page(p).emplace_back(POP); diff --git a/tests/unittests/resources/CompilerSuite/optimized_ir/lists.ark b/tests/unittests/resources/CompilerSuite/optimized_ir/lists.ark index 6a5a0b4d4..ee8fb4e64 100644 --- a/tests/unittests/resources/CompilerSuite/optimized_ir/lists.ark +++ b/tests/unittests/resources/CompilerSuite/optimized_ir/lists.ark @@ -20,6 +20,15 @@ # APPEND_IN_PLACE_SYM (append! source 6) + # APPEND_IN_PLACE_SYM + # + LOAD_FAST + (print (append! source 6)) + + # CONCAT_IN_PLACE + (concat! source [7]) + # CONCAT_IN_PLACE + # + LOAD_FAST + (print (concat! source [7])) # AT_SYM_SYM (@ source n) })) diff --git a/tests/unittests/resources/CompilerSuite/optimized_ir/lists.expected b/tests/unittests/resources/CompilerSuite/optimized_ir/lists.expected index 7521508a7..520af99aa 100644 --- a/tests/unittests/resources/CompilerSuite/optimized_ir/lists.expected +++ b/tests/unittests/resources/CompilerSuite/optimized_ir/lists.expected @@ -5,16 +5,16 @@ page_0 STORE_LEN 0, 1 LOAD_CONST_STORE 3, 2 LOAD_CONST_STORE 4, 3 - PUSH_RETURN_ADDRESS L0 + PUSH_RETURN_ADDRESS L2 LOAD_FAST_BY_INDEX 0 CALL 0 -.L0: +.L2: POP 0 STORE_HEAD_BY_INDEX 3, 7 - PUSH_RETURN_ADDRESS L1 + PUSH_RETURN_ADDRESS L3 LOAD_FAST_BY_INDEX 0 CALL_BUILTIN 9, 1 -.L1: +.L3: POP 0 STORE_TAIL_BY_INDEX 4, 8 STORE_FROM_INDEX 5, 9 @@ -24,8 +24,9 @@ page_0 POP 0 AT_SYM_INDEX_CONST 6, 2 POP 0 - LOAD_CONST 6 + LOAD_CONST 7 APPEND_IN_PLACE_SYM_INDEX 1, 1 + LOAD_FAST_BY_INDEX 1 HALT 0 page_1 @@ -36,6 +37,26 @@ page_1 SET_VAL_TAIL 0, 6 LOAD_CONST 5 APPEND_IN_PLACE_SYM 0, 1 + PUSH_RETURN_ADDRESS L0 + LOAD_CONST 5 + APPEND_IN_PLACE_SYM 0, 1 + LOAD_FAST 0 + CALL_BUILTIN 9, 1 +.L0: + POP 0 + LOAD_CONST 6 + LIST 1 + LOAD_FAST 0 + CONCAT_IN_PLACE 1 + PUSH_RETURN_ADDRESS L1 + LOAD_CONST 6 + LIST 1 + LOAD_FAST 0 + CONCAT_IN_PLACE 1 + LOAD_FAST 0 + CALL_BUILTIN 9, 1 +.L1: + POP 0 AT_SYM_SYM 0, 2 RET 0 HALT 0 diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/apply_invalid_node.ark b/tests/unittests/resources/DiagnosticsSuite/compileTime/apply_invalid_node.ark index 182d88530..bed97acf5 100644 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/apply_invalid_node.ark +++ b/tests/unittests/resources/DiagnosticsSuite/compileTime/apply_invalid_node.ark @@ -1,2 +1,2 @@ (mut b []) -(apply print (append! b 5)) +(apply print (breakpoint)) diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/apply_invalid_node.expected b/tests/unittests/resources/DiagnosticsSuite/compileTime/apply_invalid_node.expected index db280353d..796f8c00d 100644 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/apply_invalid_node.expected +++ b/tests/unittests/resources/DiagnosticsSuite/compileTime/apply_invalid_node.expected @@ -1,6 +1,6 @@ In file tests/unittests/resources/DiagnosticsSuite/compileTime/apply_invalid_node.ark:2 1 | (mut b []) - 2 | (apply print (append! b 5)) - | ^~~~~~~~~~~~~ + 2 | (apply print (breakpoint)) + | ^~~~~~~~~~~~ 3 | Invalid node inside call to `apply'. The given node doesn't return a value, and thus can't be used as an expression. diff --git a/tests/unittests/resources/LangSuite/list-tests.ark b/tests/unittests/resources/LangSuite/list-tests.ark index 25a9492c8..93f0f0871 100644 --- a/tests/unittests/resources/LangSuite/list-tests.ark +++ b/tests/unittests/resources/LangSuite/list-tests.ark @@ -121,9 +121,9 @@ (test:case "in place list mutation" { (mut c a) (mut d b) - (append! c 4) + (test:eq (append! c 4) [1 2 3 4]) (test:eq c [1 2 3 4]) - (concat! c d) + (test:eq (concat! c d) [1 2 3 4 4 5 6]) (test:eq c [1 2 3 4 4 5 6]) (test:eq d [4 5 6]) (test:eq (pop! c -1) 6) From 115821b1bd22cd8ccbf12f50e8af3945036e20d6 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Thu, 12 Mar 2026 17:44:14 +0100 Subject: [PATCH 3/5] feat: ARK-344, let, mut and set can return the assigned value --- CHANGELOG.md | 1 + include/Ark/Compiler/Lowerer/ASTLowerer.hpp | 2 +- .../Compiler/Lowerer/ASTLowerer.cpp | 19 ++++-- src/arkreactor/VM/Debugger.cpp | 7 +- tests/unittests/Suites/DebuggerSuite.cpp | 25 ++++---- .../CompilerSuite/ir/closures.expected | 1 + .../optimized_ir/builtins.expected | 1 + .../optimized_ir/closures.expected | 2 + .../CompilerSuite/optimized_ir/mul.expected | 1 + .../resources/DebuggerSuite/basic.expected | 14 ++-- .../DebuggerSuite/debugger_quit.expected | 8 +-- .../resources/DebuggerSuite/loop.expected | 16 ++--- .../modify_program_state.expected | 9 +-- .../resources/DebuggerSuite/on_error.expected | 6 +- .../DebuggerSuite/stack_and_locals.expected | 64 +++++++++---------- .../compileTime/can_not_call_breakpoint.ark | 1 + .../can_not_call_breakpoint.expected | 5 ++ .../compileTime/can_not_call_let.ark | 1 - .../compileTime/can_not_call_let.expected | 5 -- .../compileTime/invalid_node_in_list.ark | 2 +- .../compileTime/invalid_node_in_list.expected | 4 +- .../compileTime/or_1_breakpoint.ark | 1 + .../compileTime/or_1_breakpoint.expected | 5 ++ .../DiagnosticsSuite/compileTime/or_1_mut.ark | 1 - .../compileTime/or_1_mut.expected | 5 -- .../DiagnosticsSuite/compileTime/or_let_1.ark | 1 - .../compileTime/or_let_1.expected | 5 -- .../resources/LangSuite/vm-tests.ark | 13 ++++ 28 files changed, 125 insertions(+), 100 deletions(-) create mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_breakpoint.ark create mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_breakpoint.expected delete mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_let.ark delete mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_let.expected create mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_breakpoint.ark create mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_breakpoint.expected delete mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_mut.ark delete mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_mut.expected delete mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/or_let_1.ark delete mode 100644 tests/unittests/resources/DiagnosticsSuite/compileTime/or_let_1.expected diff --git a/CHANGELOG.md b/CHANGELOG.md index c34a8409f..6de96db49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - `pop!` can return the removed value - `@=` and `@@=` return the inserted value - `append!` and `concat!` return the modified list +- `let`, `mut` and `set` can return the assigned value ### Removed diff --git a/include/Ark/Compiler/Lowerer/ASTLowerer.hpp b/include/Ark/Compiler/Lowerer/ASTLowerer.hpp index a4b5c5f88..820ed47e3 100644 --- a/include/Ark/Compiler/Lowerer/ASTLowerer.hpp +++ b/include/Ark/Compiler/Lowerer/ASTLowerer.hpp @@ -257,7 +257,7 @@ namespace Ark::internal void compileApplyInstruction(Node& x, Page p, bool is_result_unused); void compileIf(Node& x, Page p, bool is_result_unused, bool is_terminal); void compileFunction(Node& x, Page p, bool is_result_unused); - void compileLetMutSet(Keyword n, Node& x, Page p); + void compileLetMutSet(Keyword n, Node& x, Page p, bool is_result_unused); void compileWhile(Node& x, Page p); void compilePluginImport(const Node& x, Page p); void pushFunctionCallArguments(Node& call, Page p, bool is_tail_call); diff --git a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp index 3ce2233d7..ce673cd49 100644 --- a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp +++ b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp @@ -99,6 +99,10 @@ namespace Ark::internal return (node.constList()[0].keyword() == Keyword::Begin && node.constList().size() > 1 && nodeProducesOutput(node.constList().back())) || // a function always produces a value ; even if it ends with a node not producing one, the VM returns nil node.constList()[0].keyword() == Keyword::Fun || + // a let/mut/set pushes the value that was assigned + node.constList()[0].keyword() == Keyword::Let || + node.constList()[0].keyword() == Keyword::Mut || + node.constList()[0].keyword() == Keyword::Set || // a condition produces a value if all its branches produce a value (node.constList()[0].keyword() == Keyword::If && nodeProducesOutput(node.constList()[2]) && @@ -250,7 +254,7 @@ namespace Ark::internal case Keyword::Let: [[fallthrough]]; case Keyword::Mut: - compileLetMutSet(keyword, x, p); + compileLetMutSet(keyword, x, p, is_result_unused); break; case Keyword::Fun: @@ -555,7 +559,7 @@ namespace Ark::internal } } - void ASTLowerer::compileLetMutSet(const Keyword n, Node& x, const Page p) + void ASTLowerer::compileLetMutSet(const Keyword n, Node& x, const Page p, const bool is_result_unused) { if (const auto sym = x.constList()[1]; sym.nodeType() != NodeType::Symbol) buildAndThrowError(fmt::format("Expected a symbol, got a {}", typeToString(sym)), sym); @@ -577,17 +581,24 @@ namespace Ark::internal // put value before symbol id // starting at index = 2 because x is a (let|mut|set variable ...) node - for (std::size_t idx = 2, end = x.constList().size(); idx < end; ++idx) - compileExpression(x.list()[idx], p, false, false); + compileExpression(x.list()[2], p, false, false); if (n == Keyword::Let || n == Keyword::Mut) { page(p).emplace_back(STORE, i); m_locals_locator.addLocal(name); + + if (!is_result_unused) + page(p).emplace_back(LOAD_FAST_BY_INDEX, 0); } else + { page(p).emplace_back(SET_VAL, i); + if (!is_result_unused) + page(p).emplace_back(LOAD_FAST, i); + } + if (is_function) m_opened_vars.pop(); page(p).back().setSourceLocation(x.filename(), x.position().start.line); diff --git a/src/arkreactor/VM/Debugger.cpp b/src/arkreactor/VM/Debugger.cpp index b3f561406..08ae3d9dc 100644 --- a/src/arkreactor/VM/Debugger.cpp +++ b/src/arkreactor/VM/Debugger.cpp @@ -179,7 +179,7 @@ namespace Ark::internal if (limit > 0 && count > 0) { fmt::println(m_os, "scope size: {}", limit); - fmt::println(m_os, "index | id | type | value"); + fmt::println(m_os, "index | id | name | type | value"); std::size_t i = 0; do @@ -192,9 +192,10 @@ namespace Ark::internal fmt::println( m_os, - "{:>5} | {:3} | {:>9} | {}", + "{:>5} | {:3} | {:14} | {:>9} | {}", fmt::styled(limit - i - 1, color), fmt::styled(id, color), + fmt::styled(vm.m_state.m_symbols[id], color), fmt::styled(std::to_string(value.valueType()), color), fmt::styled(value.toString(vm, /* show_as_code= */ true), color)); ++i; @@ -257,7 +258,7 @@ namespace Ark::internal m_os, "dbg[{},{}]:{:0>3}{} ", fmt::format("pp:{}", fmt::styled(pp, m_colorize ? fmt::fg(fmt::color::green) : fmt::text_style())), - fmt::format("ip:{}", fmt::styled(ip, m_colorize ? fmt::fg(fmt::color::cyan) : fmt::text_style())), + fmt::format("ip:{}", fmt::styled(ip / 4, m_colorize ? fmt::fg(fmt::color::cyan) : fmt::text_style())), m_line_count, unfinished_block ? ":" : ">"); diff --git a/tests/unittests/Suites/DebuggerSuite.cpp b/tests/unittests/Suites/DebuggerSuite.cpp index 57a9369bf..4c72bfbf3 100644 --- a/tests/unittests/Suites/DebuggerSuite.cpp +++ b/tests/unittests/Suites/DebuggerSuite.cpp @@ -33,19 +33,18 @@ ut::suite<"Debugger"> debugger_suite = [] { std::filesystem::path prompt_path(data.path); prompt_path.replace_extension("prompt"); - try - { - Ark::VM vm(state); - vm.usePromptFileForDebugger(prompt_path.generic_string(), os); - vm.run(/* fail_with_exception= */ false); - - const std::string output = sanitizeOutput(os.str()); - expectOrDiff(data.expected, output); - } - catch (const std::exception&) - { - expect(false); - } + expect( + nothrow( + [&] { + Ark::VM vm(state); + vm.usePromptFileForDebugger(prompt_path.generic_string(), os); + vm.run(/* fail_with_exception= */ false); + + const std::string output = sanitizeOutput(os.str()); + expectOrDiff(data.expected, output); + if (shouldWriteNewDiffsTofile() && data.expected != output) + updateExpectedFile(data, output); + })); }; }); }; diff --git a/tests/unittests/resources/CompilerSuite/ir/closures.expected b/tests/unittests/resources/CompilerSuite/ir/closures.expected index 0bf9b580f..995722daf 100644 --- a/tests/unittests/resources/CompilerSuite/ir/closures.expected +++ b/tests/unittests/resources/CompilerSuite/ir/closures.expected @@ -111,6 +111,7 @@ page_2 STORE 5 LOAD_FAST_BY_INDEX 0 SET_VAL 2 + LOAD_FAST 2 RET 0 HALT 0 diff --git a/tests/unittests/resources/CompilerSuite/optimized_ir/builtins.expected b/tests/unittests/resources/CompilerSuite/optimized_ir/builtins.expected index a8c4a2277..fd6ed676d 100644 --- a/tests/unittests/resources/CompilerSuite/optimized_ir/builtins.expected +++ b/tests/unittests/resources/CompilerSuite/optimized_ir/builtins.expected @@ -2,6 +2,7 @@ page_0 LOAD_CONST_STORE 0, 0 LOAD_CONST_STORE 1, 2 LOAD_CONST_STORE 2, 4 + LOAD_FAST_BY_INDEX 0 HALT 0 page_1 diff --git a/tests/unittests/resources/CompilerSuite/optimized_ir/closures.expected b/tests/unittests/resources/CompilerSuite/optimized_ir/closures.expected index 176d1d18d..bdae3566a 100644 --- a/tests/unittests/resources/CompilerSuite/optimized_ir/closures.expected +++ b/tests/unittests/resources/CompilerSuite/optimized_ir/closures.expected @@ -51,6 +51,7 @@ page_0 .L7: STORE 10 LOAD_CONST_STORE 18, 11 + LOAD_FAST_BY_INDEX 0 HALT 0 page_1 @@ -69,6 +70,7 @@ page_1 page_2 STORE 5 SET_VAL_FROM_INDEX 0, 2 + LOAD_FAST 2 RET 0 HALT 0 diff --git a/tests/unittests/resources/CompilerSuite/optimized_ir/mul.expected b/tests/unittests/resources/CompilerSuite/optimized_ir/mul.expected index 4f7bcedc9..30431dfa1 100644 --- a/tests/unittests/resources/CompilerSuite/optimized_ir/mul.expected +++ b/tests/unittests/resources/CompilerSuite/optimized_ir/mul.expected @@ -18,5 +18,6 @@ page_1 STORE 2 MUL_SET_VAL 0, 2056 MUL_SET_VAL 0, 2056 + LOAD_FAST 0 RET 0 HALT 0 diff --git a/tests/unittests/resources/DebuggerSuite/basic.expected b/tests/unittests/resources/DebuggerSuite/basic.expected index 90fe228bc..5511b90c2 100644 --- a/tests/unittests/resources/DebuggerSuite/basic.expected +++ b/tests/unittests/resources/DebuggerSuite/basic.expected @@ -6,11 +6,11 @@ In file tests/unittests/resources/DebuggerSuite/basic.ark:3 4 | (prn (format "ark: after first breakpoint, a={}, b={}" a b)) 5 | -dbg[pp:0,ip:12]:000> (let c (+ a b)) -dbg[pp:0,ip:12]:001> (prn c) +dbg[pp:0,ip:3]:000> (let c (+ a b)) 11 -nil -dbg[pp:0,ip:12]:002> c +dbg[pp:0,ip:3]:001> (prn c) +11 +dbg[pp:0,ip:3]:002> c dbg: continue ark: after first breakpoint, a=5, b=6 @@ -23,17 +23,17 @@ In file tests/unittests/resources/DebuggerSuite/basic.ark:7 8 | (prn "ark: in (foo x y z), after second breakpoint") 9 | (+ x y z) })) -dbg[pp:1,ip:20]:000> (prn x y z) +dbg[pp:1,ip:5]:000> (prn x y z) 567 nil -dbg[pp:1,ip:20]:001> help +dbg[pp:1,ip:5]:001> help Available commands: help -- display this message c, continue -- resume execution q, quit -- quit the debugger, stopping the script execution stack -- show the last n values on the stack locals -- show the last n values on the locals' stack -dbg[pp:1,ip:20]:001> continue +dbg[pp:1,ip:5]:001> continue dbg: continue ark: in (foo x y z), after second breakpoint 18 diff --git a/tests/unittests/resources/DebuggerSuite/debugger_quit.expected b/tests/unittests/resources/DebuggerSuite/debugger_quit.expected index 0adb73182..a5df39493 100644 --- a/tests/unittests/resources/DebuggerSuite/debugger_quit.expected +++ b/tests/unittests/resources/DebuggerSuite/debugger_quit.expected @@ -6,9 +6,9 @@ In file tests/unittests/resources/DebuggerSuite/debugger_quit.ark:3 4 | (prn (format "ark: after first breakpoint, a={}, b={}" a b)) 5 | -dbg[pp:0,ip:12]:000> (let c (+ a b)) -dbg[pp:0,ip:12]:001> (prn c) +dbg[pp:0,ip:3]:000> (let c (+ a b)) 11 -nil -dbg[pp:0,ip:12]:002> q +dbg[pp:0,ip:3]:001> (prn c) +11 +dbg[pp:0,ip:3]:002> q dbg: stop diff --git a/tests/unittests/resources/DebuggerSuite/loop.expected b/tests/unittests/resources/DebuggerSuite/loop.expected index 424086953..0feebd27b 100644 --- a/tests/unittests/resources/DebuggerSuite/loop.expected +++ b/tests/unittests/resources/DebuggerSuite/loop.expected @@ -13,10 +13,10 @@ In file tests/unittests/resources/DebuggerSuite/loop.ark:3 4 | (prn (format "ark: i={}" i)) 5 | (set i (+ 1 i)) }) -dbg[pp:0,ip:32]:000> (prn i) +dbg[pp:0,ip:8]:000> (prn i) 6 nil -dbg[pp:0,ip:32]:001> c +dbg[pp:0,ip:8]:001> c dbg: continue ark: i=6 @@ -28,10 +28,10 @@ In file tests/unittests/resources/DebuggerSuite/loop.ark:3 4 | (prn (format "ark: i={}" i)) 5 | (set i (+ 1 i)) }) -dbg[pp:0,ip:32]:000> (prn i) +dbg[pp:0,ip:8]:000> (prn i) 7 nil -dbg[pp:0,ip:32]:001> c +dbg[pp:0,ip:8]:001> c dbg: continue ark: i=7 @@ -43,10 +43,10 @@ In file tests/unittests/resources/DebuggerSuite/loop.ark:3 4 | (prn (format "ark: i={}" i)) 5 | (set i (+ 1 i)) }) -dbg[pp:0,ip:32]:000> (prn i) +dbg[pp:0,ip:8]:000> (prn i) 8 nil -dbg[pp:0,ip:32]:001> c +dbg[pp:0,ip:8]:001> c dbg: continue ark: i=8 @@ -58,10 +58,10 @@ In file tests/unittests/resources/DebuggerSuite/loop.ark:3 4 | (prn (format "ark: i={}" i)) 5 | (set i (+ 1 i)) }) -dbg[pp:0,ip:32]:000> (prn i) +dbg[pp:0,ip:8]:000> (prn i) 9 nil -dbg[pp:0,ip:32]:001> c +dbg[pp:0,ip:8]:001> c dbg: continue ark: i=9 ark: end diff --git a/tests/unittests/resources/DebuggerSuite/modify_program_state.expected b/tests/unittests/resources/DebuggerSuite/modify_program_state.expected index 75dc4b45d..682b7cf2f 100644 --- a/tests/unittests/resources/DebuggerSuite/modify_program_state.expected +++ b/tests/unittests/resources/DebuggerSuite/modify_program_state.expected @@ -13,10 +13,10 @@ In file tests/unittests/resources/DebuggerSuite/modify_program_state.ark:3 4 | (prn (format "ark: i={}" i)) 5 | (set i (+ 1 i)) }) -dbg[pp:0,ip:32]:000> (prn i) +dbg[pp:0,ip:8]:000> (prn i) 6 nil -dbg[pp:0,ip:32]:001> c +dbg[pp:0,ip:8]:001> c dbg: continue ark: i=6 @@ -28,8 +28,9 @@ In file tests/unittests/resources/DebuggerSuite/modify_program_state.ark:3 4 | (prn (format "ark: i={}" i)) 5 | (set i (+ 1 i)) }) -dbg[pp:0,ip:32]:000> (set i 20) -dbg[pp:0,ip:32]:001> c +dbg[pp:0,ip:8]:000> (set i 20) +20 +dbg[pp:0,ip:8]:001> c dbg: continue ark: i=20 ark: end diff --git a/tests/unittests/resources/DebuggerSuite/on_error.expected b/tests/unittests/resources/DebuggerSuite/on_error.expected index e70e1a9c0..fd4e9435f 100644 --- a/tests/unittests/resources/DebuggerSuite/on_error.expected +++ b/tests/unittests/resources/DebuggerSuite/on_error.expected @@ -1,8 +1,8 @@ -dbg[pp:0,ip:12]:000> (prn a) +dbg[pp:0,ip:3]:000> (prn a) 5 nil -dbg[pp:0,ip:12]:001> (prn (type a)) +dbg[pp:0,ip:3]:001> (prn (type a)) Number nil -dbg[pp:0,ip:12]:002> c +dbg[pp:0,ip:3]:002> c dbg: continue diff --git a/tests/unittests/resources/DebuggerSuite/stack_and_locals.expected b/tests/unittests/resources/DebuggerSuite/stack_and_locals.expected index f960fb2e3..4dc361ae9 100644 --- a/tests/unittests/resources/DebuggerSuite/stack_and_locals.expected +++ b/tests/unittests/resources/DebuggerSuite/stack_and_locals.expected @@ -7,16 +7,16 @@ In file tests/unittests/resources/DebuggerSuite/stack_and_locals.ark:8 9 | (prn (f 1 2)) 10 | -dbg[pp:0,ip:8]:000> stack +dbg[pp:0,ip:2]:000> stack Stack is empty -dbg[pp:0,ip:8]:000> locals +dbg[pp:0,ip:2]:000> locals scope size: 2 -index | id | type | value - 1 | 0 | Function | Function@1 - 0 | 4 | CProc | CProcedure +index | id | name | type | value + 1 | 0 | f | Function | Function@1 + 0 | 4 | prn | CProc | CProcedure -dbg[pp:0,ip:8]:000> c +dbg[pp:0,ip:2]:000> c dbg: continue In file tests/unittests/resources/DebuggerSuite/stack_and_locals.ark:3 @@ -27,38 +27,38 @@ In file tests/unittests/resources/DebuggerSuite/stack_and_locals.ark:3 4 | (if (= 1 a) 5 | (f "correct" "wrong") -dbg[pp:1,ip:16]:000> stack +dbg[pp:1,ip:4]:000> stack 3 -> Instruction@28 2 -> Function@0 1 -> Instruction@32 0 -> Function@0 -dbg[pp:1,ip:16]:000> locals 1 +dbg[pp:1,ip:4]:000> locals 1 scope size: 3 -index | id | type | value - 2 | 3 | Number | 1 +index | id | name | type | value + 2 | 3 | x | Number | 1 -dbg[pp:1,ip:16]:000> locals 2 +dbg[pp:1,ip:4]:000> locals 2 scope size: 3 -index | id | type | value - 2 | 3 | Number | 1 - 1 | 2 | Number | 2 +index | id | name | type | value + 2 | 3 | x | Number | 1 + 1 | 2 | b | Number | 2 -dbg[pp:1,ip:16]:000> locals 3 +dbg[pp:1,ip:4]:000> locals 3 scope size: 3 -index | id | type | value - 2 | 3 | Number | 1 - 1 | 2 | Number | 2 - 0 | 1 | Number | 1 +index | id | name | type | value + 2 | 3 | x | Number | 1 + 1 | 2 | b | Number | 2 + 0 | 1 | a | Number | 1 -dbg[pp:1,ip:16]:000> locals +dbg[pp:1,ip:4]:000> locals scope size: 3 -index | id | type | value - 2 | 3 | Number | 1 - 1 | 2 | Number | 2 - 0 | 1 | Number | 1 +index | id | name | type | value + 2 | 3 | x | Number | 1 + 1 | 2 | b | Number | 2 + 0 | 1 | a | Number | 1 -dbg[pp:1,ip:16]:000> c +dbg[pp:1,ip:4]:000> c dbg: continue In file tests/unittests/resources/DebuggerSuite/stack_and_locals.ark:3 @@ -69,19 +69,19 @@ In file tests/unittests/resources/DebuggerSuite/stack_and_locals.ark:3 4 | (if (= 1 a) 5 | (f "correct" "wrong") -dbg[pp:1,ip:16]:000> stack +dbg[pp:1,ip:4]:000> stack 3 -> Instruction@28 2 -> Function@0 1 -> Instruction@32 0 -> Function@0 -dbg[pp:1,ip:16]:000> locals +dbg[pp:1,ip:4]:000> locals scope size: 3 -index | id | type | value - 2 | 3 | String | "correct" - 1 | 2 | String | "wrong" - 0 | 1 | String | "correct" +index | id | name | type | value + 2 | 3 | x | String | "correct" + 1 | 2 | b | String | "wrong" + 0 | 1 | a | String | "correct" -dbg[pp:1,ip:16]:000> c +dbg[pp:1,ip:4]:000> c dbg: continue correct diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_breakpoint.ark b/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_breakpoint.ark new file mode 100644 index 000000000..a03603771 --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_breakpoint.ark @@ -0,0 +1 @@ +((breakpoint) builtin__list:slice [] 1 1 2) diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_breakpoint.expected b/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_breakpoint.expected new file mode 100644 index 000000000..228dbfcab --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_breakpoint.expected @@ -0,0 +1,5 @@ +In file tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_breakpoint.ark:1 + 1 | ((breakpoint) builtin__list:slice [] 1 1 2) + | ^~~~~~~~~~~~ + 2 | + Can not call `(breakpoint)', as it doesn't return a value diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_let.ark b/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_let.ark deleted file mode 100644 index 077cb83eb..000000000 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_let.ark +++ /dev/null @@ -1 +0,0 @@ -((let in (list 0 0 3 4 5)) builtin__list:slice in 1 1 2) diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_let.expected b/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_let.expected deleted file mode 100644 index ab99a2a1b..000000000 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_let.expected +++ /dev/null @@ -1,5 +0,0 @@ -In file tests/unittests/resources/DiagnosticsSuite/compileTime/can_not_call_let.ark:1 - 1 | ((let in (list 0 0 3 4 5)) builtin__list:slice in 1 1 2) - | ^~~~~~~~~~~~~~~~~~~~~~~~~~ - 2 | - Can not call `(let in (list 0 0 3 4 5))', as it doesn't return a value diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/invalid_node_in_list.ark b/tests/unittests/resources/DiagnosticsSuite/compileTime/invalid_node_in_list.ark index 4384732e5..6ca4b6854 100644 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/invalid_node_in_list.ark +++ b/tests/unittests/resources/DiagnosticsSuite/compileTime/invalid_node_in_list.ark @@ -1 +1 @@ -[(mut c 1)] +[(breakpoint)] diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/invalid_node_in_list.expected b/tests/unittests/resources/DiagnosticsSuite/compileTime/invalid_node_in_list.expected index 6c22d23d3..4d4685075 100644 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/invalid_node_in_list.expected +++ b/tests/unittests/resources/DiagnosticsSuite/compileTime/invalid_node_in_list.expected @@ -1,5 +1,5 @@ In file tests/unittests/resources/DiagnosticsSuite/compileTime/invalid_node_in_list.ark:1 - 1 | [(mut c 1)] - | ^~~~~~~~ + 1 | [(breakpoint)] + | ^~~~~~~~~~~~ 2 | Invalid node inside call to `list'. The given node doesn't return a value, and thus can't be used as an expression. diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_breakpoint.ark b/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_breakpoint.ark new file mode 100644 index 000000000..c2061b0df --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_breakpoint.ark @@ -0,0 +1 @@ +(print (or 1 (breakpoint))) diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_breakpoint.expected b/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_breakpoint.expected new file mode 100644 index 000000000..978b6ea4b --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_breakpoint.expected @@ -0,0 +1,5 @@ +In file tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_breakpoint.ark:1 + 1 | (print (or 1 (breakpoint))) + | ^~~~~~~~~~~~ + 2 | + Can not use `(breakpoint)' inside a `or' expression, as it doesn't return a value diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_mut.ark b/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_mut.ark deleted file mode 100644 index 71ed4309f..000000000 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_mut.ark +++ /dev/null @@ -1 +0,0 @@ -(print (or 1 (mut x 3))) diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_mut.expected b/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_mut.expected deleted file mode 100644 index 7f7f68785..000000000 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_mut.expected +++ /dev/null @@ -1,5 +0,0 @@ -In file tests/unittests/resources/DiagnosticsSuite/compileTime/or_1_mut.ark:1 - 1 | (print (or 1 (mut x 3))) - | ^~~~~~~~ - 2 | - Can not use `(mut x 3)' inside a `or' expression, as it doesn't return a value diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_let_1.ark b/tests/unittests/resources/DiagnosticsSuite/compileTime/or_let_1.ark deleted file mode 100644 index e34b9f093..000000000 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_let_1.ark +++ /dev/null @@ -1 +0,0 @@ -(print (or (let x 1) 1)) diff --git a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_let_1.expected b/tests/unittests/resources/DiagnosticsSuite/compileTime/or_let_1.expected deleted file mode 100644 index e2b2637e7..000000000 --- a/tests/unittests/resources/DiagnosticsSuite/compileTime/or_let_1.expected +++ /dev/null @@ -1,5 +0,0 @@ -In file tests/unittests/resources/DiagnosticsSuite/compileTime/or_let_1.ark:1 - 1 | (print (or (let x 1) 1)) - | ^~~~~~~~ - 2 | - Can not use `(let x 1)' inside a `or' expression, as it doesn't return a value diff --git a/tests/unittests/resources/LangSuite/vm-tests.ark b/tests/unittests/resources/LangSuite/vm-tests.ark index 5a8cb2531..7430b578a 100644 --- a/tests/unittests/resources/LangSuite/vm-tests.ark +++ b/tests/unittests/resources/LangSuite/vm-tests.ark @@ -28,7 +28,20 @@ (fun (&set-age &name &age) ()) })) (let bob (create-human "Bob" 38)) +(let egg (fun ((mut n)) + (set n n))) + (test:suite vm { + (test:case "assignments" { + (mut val (let x1 4)) + (test:eq val 4) + (set val (mut x2 5)) + (test:eq val 5) + (set val (set x2 6)) + (test:eq val 6) + (set val (egg 7)) + (test:eq val 7) }) + (test:case "arithmetic operations" { (test:eq (+ 1 2) 3) (test:eq (+ 1.5 2.5) 4.0) From 1a1594ff4c47ae62236b73b13f600026b7fb37c4 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Thu, 12 Mar 2026 18:31:20 +0100 Subject: [PATCH 4/5] chore: ARK-344, benchmarks comparison script color lines to make them easily identifiable --- tests/benchmarks/compare.py | 16 +++++++++------- tests/benchmarks/results/013-74e64c67.csv | 11 +++++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 tests/benchmarks/results/013-74e64c67.csv diff --git a/tests/benchmarks/compare.py b/tests/benchmarks/compare.py index cda25992d..6ce013b37 100644 --- a/tests/benchmarks/compare.py +++ b/tests/benchmarks/compare.py @@ -127,24 +127,26 @@ def main(files: List[str]): runs_by_name[run.name].append(run) data = [] - times = colorize_time_type("real_time", 0) + "\n" + colorize_time_type("cpu_time", 1) - for (name, runs) in runs_by_name.items(): + for i, (name, runs) in enumerate(runs_by_name.items()): baseline: Run = runs[0] baseline_index = headers.index(baseline.benchmark) - 2 diffs = [r.diff_from_baseline(baseline) for r in runs[1:]] padding = ["" for _ in range(baseline_index)] if baseline_index > 0 else [] data.append( - [name, times] + + [ + colorize_time_type(name, i % 2), + colorize_time_type("real_time", i % 2) + "\n" + colorize_time_type("cpu_time", i % 2) + ] + padding + [ - colorize_time_type(f"{baseline.real_time:.3f}{baseline.time_unit}", 0) + "\n" + - colorize_time_type(f"{baseline.cpu_time:.3f}{baseline.time_unit}", 1) + colorize_time_type(f"{baseline.real_time:.3f}{baseline.time_unit}", i % 2) + "\n" + + colorize_time_type(f"{baseline.cpu_time:.3f}{baseline.time_unit}", i % 2) ] + [ - f"{colorize_time_type(diff.dt_real_time, 0)} ({colorize_diff(diff.dt_rt_percent)}%)\n" + - f"{colorize_time_type(diff.dt_cpu_time, 1)} ({colorize_diff(diff.dt_ct_percent)}%)" + f"{colorize_time_type(diff.dt_real_time, i % 2)} ({colorize_diff(diff.dt_rt_percent)}%)\n" + + f"{colorize_time_type(diff.dt_cpu_time, i % 2)} ({colorize_diff(diff.dt_ct_percent)}%)" for diff in diffs ] diff --git a/tests/benchmarks/results/013-74e64c67.csv b/tests/benchmarks/results/013-74e64c67.csv new file mode 100644 index 000000000..2f178694c --- /dev/null +++ b/tests/benchmarks/results/013-74e64c67.csv @@ -0,0 +1,11 @@ +name,iterations,real_time,cpu_time,time_unit,bytes_per_second,items_per_second,label,error_occurred,error_message +"quicksort",7431,0.0933847,0.0930486,ms,,,,, +"ackermann/iterations:50",50,32.3309,32.1861,ms,,,,, +"fibonacci/iterations:100",100,3.16125,3.14818,ms,,,,, +"builtins",1205,0.581715,0.580722,ms,,,,, +"binary_trees",1,855.337,853.891,ms,,,,, +"for_sum",8,88.2647,88.0911,ms,,,,, +"create_closure/iterations:500",500,0.771819,0.770728,ms,,,,, +"create_list/iterations:500",500,1.7033,1.70064,ms,,,,, +"create_list_with_ref/iterations:500",500,1.46902,1.46652,ms,,,,, +"n_queens/iterations:50",50,13.0718,13.0555,ms,,,,, From 601ead9d84fa5c7c8406d533bae42f002f1c0c67 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Thu, 12 Mar 2026 22:46:33 +0100 Subject: [PATCH 5/5] fix: when compiling code for the debugger, set is_result_unused to true --- src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp | 8 +++++--- tests/unittests/resources/DebuggerSuite/basic.expected | 2 -- .../resources/DebuggerSuite/debugger_quit.expected | 1 - tests/unittests/resources/DebuggerSuite/loop.expected | 4 ---- .../resources/DebuggerSuite/modify_program_state.expected | 2 -- tests/unittests/resources/DebuggerSuite/on_error.expected | 2 -- 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp index ce673cd49..0fbf9ec7e 100644 --- a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp +++ b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp @@ -37,9 +37,11 @@ namespace Ark::internal // gather symbols, values, and start to create code segments compileExpression( ast, - /* current_page */ global, - /* is_result_unused */ false, - /* is_terminal */ false); + /* current_page= */ global, + // the offset is non-zero when coming from the debugger, and setting is_result_unused to + // true will avoid adding a LOAD_FAST/LOAD_FAST_FROM_INDEX after a let/mut/set + /* is_result_unused= */ m_start_page_at_offset != 0, + /* is_terminal= */ false); m_logger.traceEnd(); } diff --git a/tests/unittests/resources/DebuggerSuite/basic.expected b/tests/unittests/resources/DebuggerSuite/basic.expected index 5511b90c2..cc189307c 100644 --- a/tests/unittests/resources/DebuggerSuite/basic.expected +++ b/tests/unittests/resources/DebuggerSuite/basic.expected @@ -7,7 +7,6 @@ In file tests/unittests/resources/DebuggerSuite/basic.ark:3 5 | dbg[pp:0,ip:3]:000> (let c (+ a b)) -11 dbg[pp:0,ip:3]:001> (prn c) 11 dbg[pp:0,ip:3]:002> c @@ -25,7 +24,6 @@ In file tests/unittests/resources/DebuggerSuite/basic.ark:7 dbg[pp:1,ip:5]:000> (prn x y z) 567 -nil dbg[pp:1,ip:5]:001> help Available commands: help -- display this message diff --git a/tests/unittests/resources/DebuggerSuite/debugger_quit.expected b/tests/unittests/resources/DebuggerSuite/debugger_quit.expected index a5df39493..2b35cc5e3 100644 --- a/tests/unittests/resources/DebuggerSuite/debugger_quit.expected +++ b/tests/unittests/resources/DebuggerSuite/debugger_quit.expected @@ -7,7 +7,6 @@ In file tests/unittests/resources/DebuggerSuite/debugger_quit.ark:3 5 | dbg[pp:0,ip:3]:000> (let c (+ a b)) -11 dbg[pp:0,ip:3]:001> (prn c) 11 dbg[pp:0,ip:3]:002> q diff --git a/tests/unittests/resources/DebuggerSuite/loop.expected b/tests/unittests/resources/DebuggerSuite/loop.expected index 0feebd27b..b6bfc2f26 100644 --- a/tests/unittests/resources/DebuggerSuite/loop.expected +++ b/tests/unittests/resources/DebuggerSuite/loop.expected @@ -15,7 +15,6 @@ In file tests/unittests/resources/DebuggerSuite/loop.ark:3 dbg[pp:0,ip:8]:000> (prn i) 6 -nil dbg[pp:0,ip:8]:001> c dbg: continue ark: i=6 @@ -30,7 +29,6 @@ In file tests/unittests/resources/DebuggerSuite/loop.ark:3 dbg[pp:0,ip:8]:000> (prn i) 7 -nil dbg[pp:0,ip:8]:001> c dbg: continue ark: i=7 @@ -45,7 +43,6 @@ In file tests/unittests/resources/DebuggerSuite/loop.ark:3 dbg[pp:0,ip:8]:000> (prn i) 8 -nil dbg[pp:0,ip:8]:001> c dbg: continue ark: i=8 @@ -60,7 +57,6 @@ In file tests/unittests/resources/DebuggerSuite/loop.ark:3 dbg[pp:0,ip:8]:000> (prn i) 9 -nil dbg[pp:0,ip:8]:001> c dbg: continue ark: i=9 diff --git a/tests/unittests/resources/DebuggerSuite/modify_program_state.expected b/tests/unittests/resources/DebuggerSuite/modify_program_state.expected index 682b7cf2f..2c83d8ce8 100644 --- a/tests/unittests/resources/DebuggerSuite/modify_program_state.expected +++ b/tests/unittests/resources/DebuggerSuite/modify_program_state.expected @@ -15,7 +15,6 @@ In file tests/unittests/resources/DebuggerSuite/modify_program_state.ark:3 dbg[pp:0,ip:8]:000> (prn i) 6 -nil dbg[pp:0,ip:8]:001> c dbg: continue ark: i=6 @@ -29,7 +28,6 @@ In file tests/unittests/resources/DebuggerSuite/modify_program_state.ark:3 5 | (set i (+ 1 i)) }) dbg[pp:0,ip:8]:000> (set i 20) -20 dbg[pp:0,ip:8]:001> c dbg: continue ark: i=20 diff --git a/tests/unittests/resources/DebuggerSuite/on_error.expected b/tests/unittests/resources/DebuggerSuite/on_error.expected index fd4e9435f..db0686aff 100644 --- a/tests/unittests/resources/DebuggerSuite/on_error.expected +++ b/tests/unittests/resources/DebuggerSuite/on_error.expected @@ -1,8 +1,6 @@ dbg[pp:0,ip:3]:000> (prn a) 5 -nil dbg[pp:0,ip:3]:001> (prn (type a)) Number -nil dbg[pp:0,ip:3]:002> c dbg: continue