From 98822b74c96f03511e9cbc6d8696116d3b4ecb56 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Sat, 28 Feb 2026 12:42:25 +0100 Subject: [PATCH 1/3] fix: tail calls have to reset the scope of the function, otherwise it messes up the indices used for loading variables --- CHANGELOG.md | 10 + include/Ark/Compiler/Instructions.hpp | 205 +++++++++--------- lib/std | 2 +- .../Compiler/Lowerer/ASTLowerer.cpp | 2 +- src/arkreactor/VM/VM.cpp | 8 + .../CompilerSuite/ir/ackermann.expected | 4 +- .../CompilerSuite/ir/tail_call.expected | 2 +- .../optimized_ir/ackermann.expected | 4 +- .../optimized_ir/fused_math_ops.expected | 160 +++++++------- .../resources/LangSuite/vm-tests.ark | 5 +- 10 files changed, 213 insertions(+), 189 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f507dd6..6041fd8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## [Unreleased changes] - 2026-MM-DD +### Breaking changes + +### Added +- new `TAIL_CALL_SELF` instruction to take care of tail calls in functions: jumps to address 0 in the current page, and reset the scope + +### Changed + +### Removed + ## [4.3.0] - 2026-02-26 ### Breaking change - in macros, `len`, `empty?`, `head`, `tail`, `@` have been renamed to `$len`, `$empty?`, `$head`, `$tail` and `$at`. Those versions only work inside macros too, inside of having a weird dichotomy where they sometimes got applied and sometimes not diff --git a/include/Ark/Compiler/Instructions.hpp b/include/Ark/Compiler/Instructions.hpp index 34dda4ab..58329c33 100644 --- a/include/Ark/Compiler/Instructions.hpp +++ b/include/Ark/Compiler/Instructions.hpp @@ -89,367 +89,371 @@ namespace Ark::internal // @role Call function from its symbol id located on top of the stack. Take the given number of arguments from the top of stack and give them to the function (the first argument taken from the stack will be the last one of the function). The stack of the function is now composed of its arguments, from the first to the last one CALL = 0x0e, + // @role Jump to the top of the current function and reset the current scope + TAIL_CALL_SELF = 0x0f, + // @args symbol id // @role Tell the Virtual Machine to capture the variable from the current environment. Main goal is to be able to handle closures, which need to save the environment in which they were created - CAPTURE = 0x0f, + CAPTURE = 0x10, // @args symbol id // @role Tell the VM to use the given symbol for the next capture - RENAME_NEXT_CAPTURE = 0x10, + RENAME_NEXT_CAPTURE = 0x11, // @args builtin id // @role Push the corresponding builtin function object on the stack - BUILTIN = 0x11, + BUILTIN = 0x12, // @args symbol id // @role Remove a variable/constant named following the given symbol id (cf symbols table) - DEL = 0x12, + DEL = 0x13, // @args constant id // @role Push a Closure with the page address pointed by the constant, along with the saved scope created by CAPTURE instruction(s) - MAKE_CLOSURE = 0x13, + MAKE_CLOSURE = 0x14, // @args symbol id // @role Read the field named following the given symbol id (cf symbols table) of a `Closure` stored in TS. Pop TS and push the value of field read on the stack - GET_FIELD = 0x14, + GET_FIELD = 0x15, // @args constant id // @role Load a plugin dynamically, plugin name is stored as a string in the constants table - PLUGIN = 0x15, + PLUGIN = 0x16, // @args number of elements // @role Create a list from the N elements pushed on the stack. Follows the function calling convention - LIST = 0x16, + LIST = 0x17, // @args number of elements // @role Append N elements to a list (TS). Elements are stored in TS(1)..TS(N). Follows the function calling convention - APPEND = 0x17, + APPEND = 0x18, // @args number of elements // @role Concatenate N lists to a list (TS). Lists to concat to TS are stored in TS(1)..TS(N). Follows the function calling convention - CONCAT = 0x18, + CONCAT = 0x19, // @args number of elements // @role Append N elements to a reference to a list (TS), the list is being mutated in-place, no new object created. Elements are stored in TS(1)..TS(N). Follows the function calling convention - APPEND_IN_PLACE = 0x19, + APPEND_IN_PLACE = 0x1a, // @args number of elements // @role Concatenate N lists to a reference to a list (TS), the list is being mutated in-place, no new object created. Lists to concat to TS are stored in TS(1)..TS(N). Follows the function calling convention - CONCAT_IN_PLACE = 0x1a, + CONCAT_IN_PLACE = 0x1b, // @role Remove an element from a list (TS), given an index (TS1). Push a new list without the removed element to the stack - POP_LIST = 0x1b, + POP_LIST = 0x1c, // @role Remove an element from a reference to a list (TS), given an index (TS1). The list is mutated in-place, no new object created - POP_LIST_IN_PLACE = 0x1c, + POP_LIST_IN_PLACE = 0x1d, // @role Modify a reference to a list or string (TS) by replacing the element at TS1 (must be a number) by the value in TS2. The object is mutated in-place, no new object created - SET_AT_INDEX = 0x1d, + SET_AT_INDEX = 0x1e, // @role Modify a reference to a list (TS) by replacing TS[TS2][TS1] by the value in TS3. TS[TS2] can be a string (if it is, TS3 must be a string). The object is mutated in-place, no new object created - SET_AT_2_INDEX = 0x1e, + SET_AT_2_INDEX = 0x1f, // @role Remove the top of the stack - POP = 0x1f, + POP = 0x20, // @role Pop the top of the stack, if it's false, jump to an address - SHORTCIRCUIT_AND = 0x20, + SHORTCIRCUIT_AND = 0x21, // @role Pop the top of the stack, if it's true, jump to an address - SHORTCIRCUIT_OR = 0x21, + SHORTCIRCUIT_OR = 0x22, // @role Create a new local scope - CREATE_SCOPE = 0x22, + CREATE_SCOPE = 0x23, // @role Reset the current scope so that it is empty, and jump to a given location - RESET_SCOPE_JUMP = 0x23, + RESET_SCOPE_JUMP = 0x24, // @role Destroy the last local scope - POP_SCOPE = 0x24, + POP_SCOPE = 0x25, // @args symbol id (function name) // @role Push the current page address as a value on the stack - GET_CURRENT_PAGE_ADDR = 0x25, + GET_CURRENT_PAGE_ADDR = 0x26, - APPLY = 0x26, + // @role Pop a List from the stack and a function, and call the function with the given list as arguments + APPLY = 0x27, - FIRST_OPERATOR = 0x27, + FIRST_OPERATOR = 0x28, // @role Pop the top of the stack, if it's true, trigger the debugger - BREAKPOINT = 0x27, + BREAKPOINT = 0x28, // @role Push `TS1 + TS` - ADD = 0x28, + ADD = 0x29, // @role Push `TS1 - TS` - SUB = 0x29, + SUB = 0x2a, // @role Push `TS1 * TS` - MUL = 0x2a, + MUL = 0x2b, // @role Push `TS1 / TS` - DIV = 0x2b, + DIV = 0x2c, // @role Push `TS1 > TS` - GT = 0x2c, + GT = 0x2d, // @role Push `TS1 < TS` - LT = 0x2d, + LT = 0x2e, // @role Push `TS1 <= TS` - LE = 0x2e, + LE = 0x2f, // @role Push `TS1 >= TS` - GE = 0x2f, + GE = 0x30, // @role Push `TS1 != TS` - NEQ = 0x30, + NEQ = 0x31, // @role Push `TS1 == TS` - EQ = 0x31, + EQ = 0x32, // @role Push `len(TS)`, TS must be a list - LEN = 0x32, + LEN = 0x33, // @role Push `empty?(TS)`, TS must be a list or string - IS_EMPTY = 0x33, + IS_EMPTY = 0x34, // @role Push `tail(TS)`, all the elements of TS except the first one. TS must be a list or string - TAIL = 0x34, + TAIL = 0x35, // @role Push `head(TS)`, the first element of TS or nil if empty. TS must be a list or string - HEAD = 0x35, + HEAD = 0x36, // @role Push true if TS is nil, false otherwise - IS_NIL = 0x36, + IS_NIL = 0x37, // @role Convert TS to number (must be a string) - TO_NUM = 0x37, + TO_NUM = 0x38, // @role Convert TS to string - TO_STR = 0x38, + TO_STR = 0x39, // @role Push the value at index TS (must be a number) in TS1, which must be a list or string - AT = 0x39, + AT = 0x3a, // @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 = 0x3a, + AT_AT = 0x3b, // @role Push `TS1 % TS` - MOD = 0x3b, + MOD = 0x3c, // @role Push the type of TS as a string - TYPE = 0x3c, + TYPE = 0x3d, // @role Check if TS1 is a closure field of TS. TS must be a Closure, TS1 a String - HAS_FIELD = 0x3d, + HAS_FIELD = 0x3e, // @role Push `!TS` - NOT = 0x3e, + NOT = 0x3f, // @args constant id, constant id // @role Load two consts (`primary` then `secondary`) on the stack in one instruction - LOAD_CONST_LOAD_CONST = 0x3f, + LOAD_CONST_LOAD_CONST = 0x40, // @args constant id, symbol id // @role Load const `primary` into the symbol `secondary` (create a variable) - LOAD_CONST_STORE = 0x40, + LOAD_CONST_STORE = 0x41, // @args constant id, symbol id // @role Load const `primary` into the symbol `secondary` (search for the variable with the given symbol id) - LOAD_CONST_SET_VAL = 0x41, + LOAD_CONST_SET_VAL = 0x42, // @args symbol id, symbol id // @role Store the value of the symbol `primary` into a new variable `secondary` - STORE_FROM = 0x42, + STORE_FROM = 0x43, // @args symbol index, symbol id // @role Store the value of the symbol `primary` into a new variable `secondary` - STORE_FROM_INDEX = 0x43, + STORE_FROM_INDEX = 0x44, // @args symbol id, symbol id // @role Store the value of the symbol `primary` into an existing variable `secondary` - SET_VAL_FROM = 0x44, + SET_VAL_FROM = 0x45, // @args symbol index, symbol id // @role Store the value of the symbol `primary` into an existing variable `secondary` - SET_VAL_FROM_INDEX = 0x45, + SET_VAL_FROM_INDEX = 0x46, // @args symbol id, count // @role Increment the variable `primary` by `count` and push its value on the stack - INCREMENT = 0x46, + INCREMENT = 0x47, // @args symbol index, count // @role Increment the variable `primary` by `count` and push its value on the stack - INCREMENT_BY_INDEX = 0x47, + INCREMENT_BY_INDEX = 0x48, // @args symbol id, count // @role Increment the variable `primary` by `count` and store its value in the given symbol id - INCREMENT_STORE = 0x48, + INCREMENT_STORE = 0x49, // @args symbol id, count // @role Decrement the variable `primary` by `count` and push its value on the stack - DECREMENT = 0x49, + DECREMENT = 0x4a, // @args symbol index, count // @role Decrement the variable `primary` by `count` and push its value on the stack - DECREMENT_BY_INDEX = 0x4a, + DECREMENT_BY_INDEX = 0x4b, // @args symbol id, count // @role Decrement the variable `primary` by `count` and store its value in the given symbol id - DECREMENT_STORE = 0x4b, + DECREMENT_STORE = 0x4c, // @args symbol id, symbol id // @role Load the symbol `primary`, compute its tail, store it in a new variable `secondary` - STORE_TAIL = 0x4c, + STORE_TAIL = 0x4d, // @args symbol index, symbol id // @role Load the symbol `primary`, compute its tail, store it in a new variable `secondary` - STORE_TAIL_BY_INDEX = 0x4d, + STORE_TAIL_BY_INDEX = 0x4e, // @args symbol id, symbol id // @role Load the symbol `primary`, compute its head, store it in a new variable `secondary` - STORE_HEAD = 0x4e, + STORE_HEAD = 0x4f, // @args symbol index, symbol id // @role Load the symbol `primary`, compute its head, store it in a new variable `secondary` - STORE_HEAD_BY_INDEX = 0x4f, + STORE_HEAD_BY_INDEX = 0x50, // @args number, symbol id // @role Create a list of `number` elements, and store it in a new variable `secondary` - STORE_LIST = 0x50, + STORE_LIST = 0x51, // @args symbol id, symbol id // @role Load the symbol `primary`, compute its tail, store it in an existing variable `secondary` - SET_VAL_TAIL = 0x51, + SET_VAL_TAIL = 0x52, // @args symbol index, symbol id // @role Load the symbol `primary`, compute its tail, store it in an existing variable `secondary` - SET_VAL_TAIL_BY_INDEX = 0x52, + SET_VAL_TAIL_BY_INDEX = 0x53, // @args symbol id, symbol id // @role Load the symbol `primary`, compute its head, store it in an existing variable `secondary` - SET_VAL_HEAD = 0x53, + SET_VAL_HEAD = 0x54, // @args symbol index, symbol id // @role Load the symbol `primary`, compute its head, store it in an existing variable `secondary` - SET_VAL_HEAD_BY_INDEX = 0x54, + SET_VAL_HEAD_BY_INDEX = 0x55, // @args builtin id, argument count // @role Call a builtin by its id in `primary`, with `secondary` arguments. Bypass the stack size check because we do not push IP/PP since builtins calls do not alter the stack - CALL_BUILTIN = 0x55, + CALL_BUILTIN = 0x56, // @args builtin id, argument count // @role Call a builtin by its id in `primary`, with `secondary` arguments. Bypass the stack size check because we do not push IP/PP since builtins calls do not alter the stack, as well as the return address removal - CALL_BUILTIN_WITHOUT_RETURN_ADDRESS = 0x56, + CALL_BUILTIN_WITHOUT_RETURN_ADDRESS = 0x57, // @args constant id, absolute address to jump to // @role Compare `TS < constant`, if the comparison fails, jump to the given address. Otherwise, does nothing - LT_CONST_JUMP_IF_FALSE = 0x57, + LT_CONST_JUMP_IF_FALSE = 0x58, // @args constant id, absolute address to jump to // @role Compare `TS < constant`, if the comparison succeeds, jump to the given address. Otherwise, does nothing - LT_CONST_JUMP_IF_TRUE = 0x58, + LT_CONST_JUMP_IF_TRUE = 0x59, // @args symbol id, absolute address to jump to // @role Compare `TS < symbol`, if the comparison fails, jump to the given address. Otherwise, does nothing - LT_SYM_JUMP_IF_FALSE = 0x59, + LT_SYM_JUMP_IF_FALSE = 0x5a, // @args constant id, absolute address to jump to // @role Compare `TS > constant`, if the comparison succeeds, jump to the given address. Otherwise, does nothing - GT_CONST_JUMP_IF_TRUE = 0x5a, + GT_CONST_JUMP_IF_TRUE = 0x5b, // @args constant id, absolute address to jump to // @role Compare `TS > constant`, if the comparison fails, jump to the given address. Otherwise, does nothing - GT_CONST_JUMP_IF_FALSE = 0x5b, + GT_CONST_JUMP_IF_FALSE = 0x5c, // @args symbol id, absolute address to jump to // @role Compare `TS > symbol`, if the comparison fails, jump to the given address. Otherwise, does nothing - GT_SYM_JUMP_IF_FALSE = 0x5c, + GT_SYM_JUMP_IF_FALSE = 0x5d, // @args constant id, absolute address to jump to // @role Compare `TS == constant`, if the comparison succeeds, jump to the given address. Otherwise, does nothing - EQ_CONST_JUMP_IF_TRUE = 0x5d, + EQ_CONST_JUMP_IF_TRUE = 0x5e, // @args symbol index, absolute address to jump to // @role Compare `TS == symbol`, if the comparison succeeds, jump to the given address. Otherwise, does nothing - EQ_SYM_INDEX_JUMP_IF_TRUE = 0x5e, + EQ_SYM_INDEX_JUMP_IF_TRUE = 0x5f, // @args constant id, absolute address to jump to // @role Compare `TS != constant`, if the comparison succeeds, jump to the given address. Otherwise, does nothing - NEQ_CONST_JUMP_IF_TRUE = 0x5f, + NEQ_CONST_JUMP_IF_TRUE = 0x60, // @args symbol id, absolute address to jump to // @role Compare `TS != symbol`, if the comparison fails, jump to the given address. Otherwise, does nothing - NEQ_SYM_JUMP_IF_FALSE = 0x60, + NEQ_SYM_JUMP_IF_FALSE = 0x61, // @args symbol id, argument count // @role Call a symbol by its id in `primary`, with `secondary` arguments - CALL_SYMBOL = 0x61, + CALL_SYMBOL = 0x62, // @args symbol id (function name), argument count // @role Call the current page with `secondary` arguments - CALL_CURRENT_PAGE = 0x62, + CALL_CURRENT_PAGE = 0x63, // @args symbol id, field id in symbols table // @role Push the field of a given symbol (which has to be a closure) on the stack - GET_FIELD_FROM_SYMBOL = 0x63, + GET_FIELD_FROM_SYMBOL = 0x64, // @args symbol index, field id in symbols table // @role Push the field of a given symbol (which has to be a closure) on the stack - GET_FIELD_FROM_SYMBOL_INDEX = 0x64, + GET_FIELD_FROM_SYMBOL_INDEX = 0x65, // @args symbol id, symbol id2 // @role Push symbol[symbol2] - AT_SYM_SYM = 0x65, + AT_SYM_SYM = 0x66, // @args symbol index, symbol index2 // @role Push symbol[symbol2] - AT_SYM_INDEX_SYM_INDEX = 0x66, + AT_SYM_INDEX_SYM_INDEX = 0x67, // @args symbol index, constant id // @role Push symbol[constant] - AT_SYM_INDEX_CONST = 0x67, + AT_SYM_INDEX_CONST = 0x68, // @args symbol id, constant id // @role Check that the type of symbol is the given constant, push true if so, false otherwise - CHECK_TYPE_OF = 0x68, + CHECK_TYPE_OF = 0x69, // @args symbol index, constant id // @role Check that the type of symbol is the given constant, push true if so, false otherwise - CHECK_TYPE_OF_BY_INDEX = 0x69, + CHECK_TYPE_OF_BY_INDEX = 0x6a, // @args symbol id, number of elements // @role Append N elements to a reference to a list (symbol id), the list is being mutated in-place, no new object created. Elements are stored in TS(1)..TS(N). Follows the function calling convention - APPEND_IN_PLACE_SYM = 0x6a, + APPEND_IN_PLACE_SYM = 0x6b, // @args symbol index, number of elements // @role Append N elements to a reference to a list (symbol index), the list is being mutated in-place, no new object created. Elements are stored in TS(1)..TS(N). Follows the function calling convention - APPEND_IN_PLACE_SYM_INDEX = 0x6b, + APPEND_IN_PLACE_SYM_INDEX = 0x6c, // @args symbol index, symbol id // @role Compute the length of the list or string at symbol index, and store it in a variable (symbol id) - STORE_LEN = 0x6c, + STORE_LEN = 0x6d, // @args symbol id, absolute address to jump to // @role Compute the length of a symbol (list or string), and pop TS to compare it, then jump if false - LT_LEN_SYM_JUMP_IF_FALSE = 0x6d, + LT_LEN_SYM_JUMP_IF_FALSE = 0x6e, // @args symbol id, offset number // @role Multiply the symbol by (offset symbol - 2048), then push it to the stack - MUL_BY = 0x6e, + MUL_BY = 0x6f, // @args symbol index, offset number // @role Multiply the symbol by (offset symbol - 2048), then push it to the stack - MUL_BY_INDEX = 0x6f, + MUL_BY_INDEX = 0x70, // @args symbol id, offset number // @role Multiply the symbol by (offset symbol - 2048), then store the result using the given symbol id - MUL_SET_VAL = 0x70, + MUL_SET_VAL = 0x71, // @args op1, op2, op3 // @role Pop 3 or 4 values from the stack, and apply the ops sequentially (only ADD, SUB, MUL, and DIV are supported). Push the result to the stack. Only op3 may be NOP. - FUSED_MATH = 0x71, + FUSED_MATH = 0x72, InstructionsCount }; @@ -470,6 +474,7 @@ namespace Ark::internal "HALT", "PUSH_RETURN_ADDRESS", "CALL", + "TAIL_CALL_SELF", "CAPTURE", "RENAME_NEXT_CAPTURE", "BUILTIN", diff --git a/lib/std b/lib/std index 8d2d9c5a..bc191a13 160000 --- a/lib/std +++ b/lib/std @@ -1 +1 @@ -Subproject commit 8d2d9c5ac9032dde5e91f61da3a795a5dcdb555e +Subproject commit bc191a13c54463fe47be17f750516fcc3646098f diff --git a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp index 025fe83f..e5072baa 100644 --- a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp +++ b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp @@ -793,7 +793,7 @@ namespace Ark::internal pushFunctionCallArguments(x, p, /* is_tail_call= */ true); // jump to the top of the function - page(p).emplace_back(JUMP, 0_u16); + page(p).emplace_back(TAIL_CALL_SELF); page(p).back().setSourceLocation(node.filename(), node.position().start.line); return true; // skip the potential Instruction::POP at the end } diff --git a/src/arkreactor/VM/VM.cpp b/src/arkreactor/VM/VM.cpp index 2b1dac53..c8fa2aed 100644 --- a/src/arkreactor/VM/VM.cpp +++ b/src/arkreactor/VM/VM.cpp @@ -467,6 +467,7 @@ namespace Ark &&TARGET_HALT, &&TARGET_PUSH_RETURN_ADDRESS, &&TARGET_CALL, + &&TARGET_TAIL_CALL_SELF, &&TARGET_CAPTURE, &&TARGET_RENAME_NEXT_CAPTURE, &&TARGET_BUILTIN, @@ -719,6 +720,13 @@ namespace Ark DISPATCH(); } + TARGET(TAIL_CALL_SELF) + { + jump(0, context); + context.locals.back().reset(); + DISPATCH(); + } + TARGET(CAPTURE) { if (!context.saved_scope) diff --git a/tests/unittests/resources/CompilerSuite/ir/ackermann.expected b/tests/unittests/resources/CompilerSuite/ir/ackermann.expected index 2fde96b7..81937074 100644 --- a/tests/unittests/resources/CompilerSuite/ir/ackermann.expected +++ b/tests/unittests/resources/CompilerSuite/ir/ackermann.expected @@ -41,14 +41,14 @@ page_1 LOAD_FAST_BY_INDEX 1 LOAD_CONST 2 SUB 0 - JUMP 0 + TAIL_CALL_SELF 0 JUMP L4 .L2: LOAD_CONST 2 LOAD_FAST_BY_INDEX 1 LOAD_CONST 2 SUB 0 - JUMP 0 + TAIL_CALL_SELF 0 .L4: .L1: RET 0 diff --git a/tests/unittests/resources/CompilerSuite/ir/tail_call.expected b/tests/unittests/resources/CompilerSuite/ir/tail_call.expected index b7b9b786..c75fc538 100644 --- a/tests/unittests/resources/CompilerSuite/ir/tail_call.expected +++ b/tests/unittests/resources/CompilerSuite/ir/tail_call.expected @@ -24,7 +24,7 @@ page_1 .L0: LOAD_SYMBOL 1 LOAD_CONST 1 - JUMP 0 + TAIL_CALL_SELF 0 .L2: RET 0 HALT 0 diff --git a/tests/unittests/resources/CompilerSuite/optimized_ir/ackermann.expected b/tests/unittests/resources/CompilerSuite/optimized_ir/ackermann.expected index cfc6e151..1e387980 100644 --- a/tests/unittests/resources/CompilerSuite/optimized_ir/ackermann.expected +++ b/tests/unittests/resources/CompilerSuite/optimized_ir/ackermann.expected @@ -27,12 +27,12 @@ page_1 CALL_CURRENT_PAGE 0, 2 .L3: DECREMENT_BY_INDEX 1, 1 - JUMP 0 + TAIL_CALL_SELF 0 JUMP L4 .L2: LOAD_CONST 2 DECREMENT_BY_INDEX 1, 1 - JUMP 0 + TAIL_CALL_SELF 0 .L4: .L1: RET 0 diff --git a/tests/unittests/resources/CompilerSuite/optimized_ir/fused_math_ops.expected b/tests/unittests/resources/CompilerSuite/optimized_ir/fused_math_ops.expected index f1634e86..5b21085d 100644 --- a/tests/unittests/resources/CompilerSuite/optimized_ir/fused_math_ops.expected +++ b/tests/unittests/resources/CompilerSuite/optimized_ir/fused_math_ops.expected @@ -8,386 +8,386 @@ page_0 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 43, 43 + FUSED_MATH 44, 44, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 41, 43 + FUSED_MATH 44, 42, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 42, 43 + FUSED_MATH 44, 43, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 40, 43 + FUSED_MATH 44, 41, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 43, 42 + FUSED_MATH 44, 44, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 41, 42 + FUSED_MATH 44, 42, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 42, 42 + FUSED_MATH 44, 43, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 40, 42 + FUSED_MATH 44, 41, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 43, 41 + FUSED_MATH 44, 44, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 41, 41 + FUSED_MATH 44, 42, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 42, 41 + FUSED_MATH 44, 43, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 40, 41 + FUSED_MATH 44, 41, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 43, 40 + FUSED_MATH 44, 44, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 41, 40 + FUSED_MATH 44, 42, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 42, 40 + FUSED_MATH 44, 43, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 43, 40, 40 + FUSED_MATH 44, 41, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 43, 43 + FUSED_MATH 43, 44, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 41, 43 + FUSED_MATH 43, 42, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 42, 43 + FUSED_MATH 43, 43, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 40, 43 + FUSED_MATH 43, 41, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 43, 42 + FUSED_MATH 43, 44, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 41, 42 + FUSED_MATH 43, 42, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 42, 42 + FUSED_MATH 43, 43, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 40, 42 + FUSED_MATH 43, 41, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 43, 41 + FUSED_MATH 43, 44, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 41, 41 + FUSED_MATH 43, 42, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 42, 41 + FUSED_MATH 43, 43, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 40, 41 + FUSED_MATH 43, 41, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 43, 40 + FUSED_MATH 43, 44, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 41, 40 + FUSED_MATH 43, 42, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 42, 40 + FUSED_MATH 43, 43, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 42, 40, 40 + FUSED_MATH 43, 41, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 43, 43 + FUSED_MATH 42, 44, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 41, 43 + FUSED_MATH 42, 42, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 42, 43 + FUSED_MATH 42, 43, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 40, 43 + FUSED_MATH 42, 41, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 43, 42 + FUSED_MATH 42, 44, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 41, 42 + FUSED_MATH 42, 42, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 42, 42 + FUSED_MATH 42, 43, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 40, 42 + FUSED_MATH 42, 41, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 43, 41 + FUSED_MATH 42, 44, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 41, 41 + FUSED_MATH 42, 42, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 42, 41 + FUSED_MATH 42, 43, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 40, 41 + FUSED_MATH 42, 41, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 43, 40 + FUSED_MATH 42, 44, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 41, 40 + FUSED_MATH 42, 42, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 42, 40 + FUSED_MATH 42, 43, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 41, 40, 40 + FUSED_MATH 42, 41, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 43, 43 + FUSED_MATH 41, 44, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 41, 43 + FUSED_MATH 41, 42, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 42, 43 + FUSED_MATH 41, 43, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 40, 43 + FUSED_MATH 41, 41, 44 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 43, 42 + FUSED_MATH 41, 44, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 41, 42 + FUSED_MATH 41, 42, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 42, 42 + FUSED_MATH 41, 43, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 40, 42 + FUSED_MATH 41, 41, 43 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 43, 41 + FUSED_MATH 41, 44, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 41, 41 + FUSED_MATH 41, 42, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 42, 41 + FUSED_MATH 41, 43, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 40, 41 + FUSED_MATH 41, 41, 42 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 43, 40 + FUSED_MATH 41, 44, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 41, 40 + FUSED_MATH 41, 42, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 42, 40 + FUSED_MATH 41, 43, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 0 - FUSED_MATH 40, 40, 40 + FUSED_MATH 41, 41, 41 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 43, 43, 0 + FUSED_MATH 44, 44, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 41, 43, 0 + FUSED_MATH 42, 44, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 42, 43, 0 + FUSED_MATH 43, 44, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 40, 43, 0 + FUSED_MATH 41, 44, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 43, 42, 0 + FUSED_MATH 44, 43, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 41, 42, 0 + FUSED_MATH 42, 43, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 42, 42, 0 + FUSED_MATH 43, 43, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 40, 42, 0 + FUSED_MATH 41, 43, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 43, 41, 0 + FUSED_MATH 44, 42, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 41, 41, 0 + FUSED_MATH 42, 42, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 42, 41, 0 + FUSED_MATH 43, 42, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 40, 41, 0 + FUSED_MATH 41, 42, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 43, 40, 0 + FUSED_MATH 44, 41, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 41, 40, 0 + FUSED_MATH 42, 41, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 42, 40, 0 + FUSED_MATH 43, 41, 0 LOAD_FAST_BY_INDEX 3 LOAD_FAST_BY_INDEX 2 LOAD_FAST_BY_INDEX 1 - FUSED_MATH 40, 40, 0 + FUSED_MATH 41, 41, 0 LIST 80 CALL_BUILTIN 9, 1 .L0: diff --git a/tests/unittests/resources/LangSuite/vm-tests.ark b/tests/unittests/resources/LangSuite/vm-tests.ark index cded8a02..5a8cb253 100644 --- a/tests/unittests/resources/LangSuite/vm-tests.ark +++ b/tests/unittests/resources/LangSuite/vm-tests.ark @@ -258,10 +258,11 @@ (test:case "tail calls" { (mut output []) (let f (fun (a b) { - (append! output [a b]) + (let x a) + (append! output [a b x]) (if (nil? b) (f "wrong" a) (append! output b)) })) (f "correct" nil) - (test:eq output [["correct" nil] ["wrong" "correct"] "correct"]) }) }) + (test:eq output [["correct" nil "correct"] ["wrong" "correct" "wrong"] "correct"]) }) }) From d2da57a560df10717f6c49126f2058c48f85e3c1 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Sat, 28 Feb 2026 12:43:13 +0100 Subject: [PATCH 2/3] fix(tests): when updating .expected files, add a new line at the end so the pre-commit hook doesn't have to fix that every time --- tests/unittests/TestsHelper.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unittests/TestsHelper.cpp b/tests/unittests/TestsHelper.cpp index 972c9b36..826f482a 100644 --- a/tests/unittests/TestsHelper.cpp +++ b/tests/unittests/TestsHelper.cpp @@ -24,6 +24,7 @@ void updateExpectedFile(const TestData& data, const std::string& actual) if (f.is_open()) { f << actual; + f << "\n"; f.close(); } } From f5896c6dea1b8adf4fb5b5264d3fc2eb02888154 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Sat, 28 Feb 2026 13:08:19 +0100 Subject: [PATCH 3/3] chore(docs): add placeholder description for macros.txt parameters --- docs/arkdoc/Macros.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/arkdoc/Macros.txt b/docs/arkdoc/Macros.txt index 85e49d43..baf9cf75 100644 --- a/docs/arkdoc/Macros.txt +++ b/docs/arkdoc/Macros.txt @@ -13,7 +13,7 @@ * @name $argcount * @brief Retrieve at compile time the number of arguments taken by a given function. * @details The function must have been defined before using `$argcount`, or must be an anonymous function: `($argcount (fun (a b c) ()))`, `($argcount my-function)`. -* @param node +* @param node node * =begin * (let foo (fun (a b) (+ a b))) * (print ($argcount foo)) # 2 @@ -23,7 +23,7 @@ --# * @name $symcat * @brief Create a new symbol by concatenating a symbol with numbers, strings and/or other symbols -* @param symbol +* @param symbol symbol * @param args... numbers, strings or symbols * =begin * (macro foo () (let ($symcat a 5) 6)) @@ -36,7 +36,7 @@ * @name $repr * @brief Return the AST representation of a given node, as a string. * @details Indentation, newlines and comments are not preserved. -* @param node +* @param node node * =begin * ($repr foobar) # will return "foobar" * ($repr (fun () (+ 1 2 3))) # will return "(fun () (+ 1 2 3))" @@ -46,13 +46,13 @@ --# * @name $as-is * @brief Use a given node as it is, without evaluating it any further in the macro context. Useful to stop the evaluation of arguments passed to a function macro. -* @param node +* @param node node #-- --# * @name $type * @brief Return the type of a given node, as a string. -* @param node +* @param node node * =begin * (print ($type foobar)) # Symbol * (print ($type (fun () (+ 1 2 3)))) # List @@ -62,7 +62,7 @@ --# * @name $len * @brief Return the length of a node -* @param node +* @param node node * =begin * (macro -> (arg fn1 ...fn) { * # we use $len to check if we have more functions to apply @@ -78,7 +78,7 @@ --# * @name $empty? * @brief Check if a node is empty. An empty list, `[]` or `(list)`, is considered empty. -* @param node +* @param node node * =begin * (macro not_empty_node () ($empty? (fun () ()))) * (print (not_empty_node)) # false @@ -88,7 +88,7 @@ --# * @name $head * @brief Return the head node in a list of nodes. The head of a `[1 2 3]` / `(list 1 2 3)` disregards the `list` and returns 1. -* @param node +* @param node node * =begin * (macro h (...args) ($head args)) * (print (h)) # nil @@ -100,7 +100,7 @@ --# * @name $tail * @brief Return the tails nodes in a list of nodes, as a `(list ...)` -* @param node +* @param node node * =begin * (macro g (...args) ($tail args)) * (print (g)) # [] @@ -113,7 +113,7 @@ --# * @name $at * @brief Return the node at a given index in a list of nodes -* @param node +* @param node node * @param index must be a number * =begin * (macro one (...args) ($at args 1))