From 13c7149dda94c60fcdb91ad4b325139b7a077966 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Sat, 14 Feb 2026 13:27:12 +0100 Subject: [PATCH 1/6] chore!: rename list:slice and string:slice to slice_ as we introduce a new slice builtin, add std.Prelude to load (nearly) all libraries, deprecate *:size functions as we can use len instead now --- Dict.ark | 1 + List.ark | 4 +++- Prelude.ark | 10 ++++++++++ String.ark | 9 +++++---- tests/list-tests.ark | 2 +- tests/string-tests.ark | 8 ++++---- 6 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 Prelude.ark diff --git a/Dict.ark b/Dict.ark index 5b755cd..99380df 100644 --- a/Dict.ark +++ b/Dict.ark @@ -99,6 +99,7 @@ # @brief Computes the number of (key, value) pairs in a given dictionary # @param _D dictionary +# @deprecated Use the builtin `len` instead # =begin # (let data (dict "key" "value")) # (print (dict:size data)) # 1 diff --git a/List.ark b/List.ark index 409bff6..da627cc 100644 --- a/List.ark +++ b/List.ark @@ -35,11 +35,12 @@ # @param start included, must be positive # @param end not included, must be positive and smaller than the list # @param step must be greater than 0 +# @deprecated Use the builtin `slice` instead # =begin # (list:slice [1 2 3 4 5] 1 4 2) # [2 4] # =end # @author https://github.com/SuperFola -(let slice (fun (_L _start _end _step) (builtin__list:slice _L _start _end _step))) +(let slice_ (fun (_L _start _end _step) (builtin__list:slice _L _start _end _step))) # @brief Sort a List and return a new one # @details The original list is not modified @@ -61,6 +62,7 @@ # @brief Function to call the `len` operator on a list # @param _L list to get the size of +# @deprecated Use the builtin `len` instead # =begin # (print (list:size [1 2 3 4])) # 4 # =end diff --git a/Prelude.ark b/Prelude.ark new file mode 100644 index 0000000..fdd85bc --- /dev/null +++ b/Prelude.ark @@ -0,0 +1,10 @@ +(import std.Dict) +(import std.IO) +(import std.List) +(import std.Macros) +(import std.Math) +(import std.Random) +(import std.Range) +(import std.String) +(import std.Switch) +(import std.Sys) diff --git a/String.ark b/String.ark index e852193..035df6e 100644 --- a/String.ark +++ b/String.ark @@ -245,13 +245,14 @@ # @param _string the string to get a slice of # @param _startingIndex the index in the string where to start slicing # @param _length the length of the slice -# @details The original string is left unmodified. Example: +# @details The original string is left unmodified. +# @deprecated Use the builtin `slice` instead # =begin # (let message "hello world, I like goats") # (let slice (string:slice message 6 4)) # => worl # =end # @author https://github.com/Natendrtfm -(let slice (fun (_string _startingIndex _length) +(let slice_ (fun (_string _startingIndex _length) (if (= _length 0) "" { @@ -326,8 +327,8 @@ (let _pattern_sz (len _pattern)) (while (!= -1 _idx) { - (mut _first_segment (slice _out 0 _idx)) - (mut _next_segment (slice _out (+ _idx _pattern_sz) (- (len _out) (+ _idx _pattern_sz)))) + (mut _first_segment (slice_ _out 0 _idx)) + (mut _next_segment (slice_ _out (+ _idx _pattern_sz) (- (len _out) (+ _idx _pattern_sz)))) (set _out (+ _first_segment _new _next_segment)) (set _idx (find _next_segment _pattern)) diff --git a/tests/list-tests.ark b/tests/list-tests.ark index a71d537..02f2654 100644 --- a/tests/list-tests.ark +++ b/tests/list-tests.ark @@ -15,7 +15,7 @@ (test:eq (builtin__list:find a 0) (list:find a 0)) (test:eq (builtin__list:find a 1) (list:find a 1)) - (test:eq (builtin__list:slice a 1 2 1) (list:slice a 1 2 1)) + (test:eq (builtin__list:slice a 1 2 1) (list:slice_ a 1 2 1)) (test:eq (builtin__list:sort [9 8 1]) (list:sort [9 8 1])) (test:eq (builtin__list:sort []) (list:sort [])) diff --git a/tests/string-tests.ark b/tests/string-tests.ark index 7968697..c9fbcb6 100644 --- a/tests/string-tests.ark +++ b/tests/string-tests.ark @@ -64,10 +64,10 @@ (test:eq (string:repeat "a" 5) "aaaaa") }) (test:case "slice" { - (test:eq (string:slice "hello world" 0 5) "hello") - (test:eq (string:slice "hello world" 0 100) "hello world") - (test:eq (string:slice "hello world" 0 1) "h") - (test:eq (string:slice "hello world" 1 4) "ello") }) + (test:eq (string:slice_ "hello world" 0 5) "hello") + (test:eq (string:slice_ "hello world" 0 100) "hello world") + (test:eq (string:slice_ "hello world" 0 1) "h") + (test:eq (string:slice_ "hello world" 1 4) "ello") }) (test:case "split" { (test:eq (string:split "a,bc,def" ",") ["a" "bc" "def"]) From 10ab24c1dd1839b9c2bbd062b96d9bb9eebb6bc9 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Mon, 16 Feb 2026 19:04:35 +0100 Subject: [PATCH 2/6] feat!: use new macros prefixed by $ --- Macros.ark | 16 ++++++++-------- Switch.ark | 2 +- tests/dict-tests.ark | 8 +++----- tests/macros-tests.ark | 5 ++++- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Macros.ark b/Macros.ark index bcfe945..aeeaa0f 100644 --- a/Macros.ark +++ b/Macros.ark @@ -1,6 +1,6 @@ # internal, do not use (macro __replace_all_placeholders_with (replacement x ...xs) { - ($if (empty? xs) + ($if ($empty? xs) ($if (= "_" ($repr x)) replacement x) @@ -26,7 +26,7 @@ ($if (= "Symbol" ($type fn1)) (macro call (fn1 arg)) (macro call ((__replace_all_placeholders_with arg ...fn1)))) - ($if (> (len fns) 0) + ($if (> ($len fns) 0) (-> call ...fns) call) }) @@ -48,11 +48,11 @@ # =end # @author https://github.com/SuperFola (macro partial (func ...defargs) { - (macro bloc (__suffix-dup a (- ($argcount func) (len defargs)))) + (macro bloc (__suffix-dup a (- ($argcount func) ($len defargs)))) (fun (bloc) (func ...defargs bloc)) ($undef bloc) }) -(macro __count_placeholders (acc x ...xs) ($if (empty? xs) +(macro __count_placeholders (acc x ...xs) ($if ($empty? xs) ($if (= "_" ($repr x)) (+ 1 acc) acc) @@ -61,14 +61,14 @@ (__count_placeholders acc ...xs)))) (macro __replace_placeholders (replacements x ...xs) { - ($if (empty? xs) + ($if ($empty? xs) ($if (= "_" ($repr x)) - (head replacements) + ($head replacements) x) ($if (= "_" ($repr x)) { - (head replacements) - (__replace_placeholders (tail replacements) ...xs) } + ($head replacements) + (__replace_placeholders ($tail replacements) ...xs) } { x (__replace_placeholders replacements ...xs) })) }) diff --git a/Switch.ark b/Switch.ark index 4417e97..550e8e8 100644 --- a/Switch.ark +++ b/Switch.ark @@ -18,4 +18,4 @@ then (if (= value case) then - ($if (>= (len cases) 2) (switch value ...cases)))) }) + ($if (>= ($len cases) 2) (switch value ...cases)))) }) diff --git a/tests/dict-tests.ark b/tests/dict-tests.ark index 33dd3bd..06a5581 100644 --- a/tests/dict-tests.ark +++ b/tests/dict-tests.ark @@ -25,9 +25,8 @@ (let filter_odd (fun (k v) (= 1 (mod v 2)))) (test:case "comparison" { - # FIXME: the macro processor is using the macro version of `empty?`, even though we have an `$as-is` inside expect - (test:expect ($as-is (empty? (dict)))) - (test:expect ($as-is (not (empty? (dict "a" 2))))) + (test:expect (empty? (dict))) + (test:expect (not (empty? (dict "a" 2)))) (test:expect (not empty)) (test:expect (not (not d))) (test:eq empty (dict)) @@ -68,8 +67,7 @@ (test:eq (dict:size d) 6) (test:eq (dict:size d) (len d)) (test:eq (dict:size (dict)) 0) - # FIXME: the macro processor is using the macro version of `len`, even though we have an `$as-is` inside eq - (test:eq (dict:size (dict)) ($as-is (len (dict)))) + (test:eq (dict:size (dict)) (len (dict))) (test:eq (dict:size d3) 1) (test:eq (dict:size d3) (len d3)) (test:eq (dict:size d4) 1) }) diff --git a/tests/macros-tests.ark b/tests/macros-tests.ark index 2d940ba..864ae61 100644 --- a/tests/macros-tests.ark +++ b/tests/macros-tests.ark @@ -14,6 +14,7 @@ (let test_func1 (partial test_func 1)) (let test_func2 (partial test_func1 2)) (let test_func3 (partial2 test_func 1 _ 3)) +(let test_func4 (partial2 test_func _ 2 _)) (test:suite macros { (test:case "->" { @@ -25,7 +26,9 @@ (test:eq (test_func1 2 3) 6) (test:eq ($argcount test_func1) 2) (test:eq ($argcount test_func2) 1) - (test:eq (test_func3 2) 6) }) + (test:eq ($argcount test_func4) 2) + (test:eq (test_func3 2) 6) + (test:eq (test_func4 1 3) 6) }) (test:case "unless" { (unless false From 4cf3d5eb52bea7b1e34cf66a43f4d009c2c69477 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Sun, 22 Feb 2026 14:27:51 +0100 Subject: [PATCH 3/6] chore: undo renaming string:slice and list:slice, as that would be a breaking change --- List.ark | 3 +-- String.ark | 7 +++---- tests/list-tests.ark | 2 +- tests/string-tests.ark | 8 ++++---- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/List.ark b/List.ark index da627cc..03867a2 100644 --- a/List.ark +++ b/List.ark @@ -35,12 +35,11 @@ # @param start included, must be positive # @param end not included, must be positive and smaller than the list # @param step must be greater than 0 -# @deprecated Use the builtin `slice` instead # =begin # (list:slice [1 2 3 4 5] 1 4 2) # [2 4] # =end # @author https://github.com/SuperFola -(let slice_ (fun (_L _start _end _step) (builtin__list:slice _L _start _end _step))) +(let slice (fun (_L _start _end _step) (builtin__list:slice _L _start _end _step))) # @brief Sort a List and return a new one # @details The original list is not modified diff --git a/String.ark b/String.ark index 035df6e..7e99b8b 100644 --- a/String.ark +++ b/String.ark @@ -246,13 +246,12 @@ # @param _startingIndex the index in the string where to start slicing # @param _length the length of the slice # @details The original string is left unmodified. -# @deprecated Use the builtin `slice` instead # =begin # (let message "hello world, I like goats") # (let slice (string:slice message 6 4)) # => worl # =end # @author https://github.com/Natendrtfm -(let slice_ (fun (_string _startingIndex _length) +(let slice (fun (_string _startingIndex _length) (if (= _length 0) "" { @@ -327,8 +326,8 @@ (let _pattern_sz (len _pattern)) (while (!= -1 _idx) { - (mut _first_segment (slice_ _out 0 _idx)) - (mut _next_segment (slice_ _out (+ _idx _pattern_sz) (- (len _out) (+ _idx _pattern_sz)))) + (mut _first_segment (slice _out 0 _idx)) + (mut _next_segment (slice _out (+ _idx _pattern_sz) (- (len _out) (+ _idx _pattern_sz)))) (set _out (+ _first_segment _new _next_segment)) (set _idx (find _next_segment _pattern)) diff --git a/tests/list-tests.ark b/tests/list-tests.ark index 02f2654..a71d537 100644 --- a/tests/list-tests.ark +++ b/tests/list-tests.ark @@ -15,7 +15,7 @@ (test:eq (builtin__list:find a 0) (list:find a 0)) (test:eq (builtin__list:find a 1) (list:find a 1)) - (test:eq (builtin__list:slice a 1 2 1) (list:slice_ a 1 2 1)) + (test:eq (builtin__list:slice a 1 2 1) (list:slice a 1 2 1)) (test:eq (builtin__list:sort [9 8 1]) (list:sort [9 8 1])) (test:eq (builtin__list:sort []) (list:sort [])) diff --git a/tests/string-tests.ark b/tests/string-tests.ark index c9fbcb6..7968697 100644 --- a/tests/string-tests.ark +++ b/tests/string-tests.ark @@ -64,10 +64,10 @@ (test:eq (string:repeat "a" 5) "aaaaa") }) (test:case "slice" { - (test:eq (string:slice_ "hello world" 0 5) "hello") - (test:eq (string:slice_ "hello world" 0 100) "hello world") - (test:eq (string:slice_ "hello world" 0 1) "h") - (test:eq (string:slice_ "hello world" 1 4) "ello") }) + (test:eq (string:slice "hello world" 0 5) "hello") + (test:eq (string:slice "hello world" 0 100) "hello world") + (test:eq (string:slice "hello world" 0 1) "h") + (test:eq (string:slice "hello world" 1 4) "ello") }) (test:case "split" { (test:eq (string:split "a,bc,def" ",") ["a" "bc" "def"]) From 51974c1e901bb1dc487d22415d185f8f52123419 Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Mon, 23 Feb 2026 19:18:16 +0100 Subject: [PATCH 4/6] feat(string): add levenshteinDistance function --- String.ark | 43 ++++++++++++++++++++++++++++++++++++++++++ tests/string-tests.ark | 6 ++++++ 2 files changed, 49 insertions(+) diff --git a/String.ark b/String.ark index 7e99b8b..9fd8957 100644 --- a/String.ark +++ b/String.ark @@ -513,3 +513,46 @@ (if (endsWith? _str _suffix) (slice _str 0 (- (len _str) (len _suffix))) _str))) + +# @brief Compute the levenshtein distance between two strings +# @param _str1 string +# @param _str2 string +# =begin +# (print (string:levenshteinDistance "arkscript" "arkscript")) # 0 +# (print (string:levenshteinDistance "arkscript" "Orkscript")) # 1 +# (print (string:levenshteinDistance "arkscript" "0rCscript")) # 2 +# (print (string:levenshteinDistance "arkscript" "OrC")) # 8 +# =end +# @author https://github.com/SuperFola +(let levenshteinDistance (fun (_str1 _str2) { + (let _len1 (+ (len _str1) 1)) + (let _len2 (+ (len _str2) 1)) + (mut _edit_distances (builtin__list:fill _len1 (builtin__list:fill _len2 0))) + + (mut _i 0) + (while (< _i _len1) { + (@@= _edit_distances _i 0 _i) + (set _i (+ 1 _i)) }) + (set _i 0) + (while (< _i _len2) { + (@@= _edit_distances 0 _i _i) + (set _i (+ 1 _i)) }) + + (set _i 1) + (while (< _i _len1) { + (mut _j 1) + (while (< _j _len2) { + (let _dist [ + (+ 1 (@@ _edit_distances (- _i 1) _j)) + (+ 1 (@@ _edit_distances _i (- _j 1))) + (+ (if (= (@ _str1 (- _i 1)) (@ _str2 (- _j 1))) 0 1) (@@ _edit_distances (- _i 1) (- _j 1))) ]) + (@@= _edit_distances _i _j + (if (and (< (@ _dist 0) (@ _dist 1)) (< (@ _dist 0) (@ _dist 2))) + (@ _dist 0) + (if (and (< (@ _dist 1) (@ _dist 0)) (< (@ _dist 1) (@ _dist 2))) + (@ _dist 1) + (@ _dist 2)))) + (set _j (+ 1 _j)) }) + (set _i (+ 1 _i)) }) + + (@@ _edit_distances (- _len1 1) (- _len2 1)) })) diff --git a/tests/string-tests.ark b/tests/string-tests.ark index 7968697..2737082 100644 --- a/tests/string-tests.ark +++ b/tests/string-tests.ark @@ -162,4 +162,10 @@ (test:eq (string:removeSuffix "TestCase" "Case") "Test") (test:eq (string:removeSuffix "BaseTestCase" "Test") "BaseTestCase") }) + + (test:case "levenshteinDistance" { + (test:eq (string:levenshteinDistance "arkscript" "arkscript") 0) + (test:eq (string:levenshteinDistance "arkscript" "Orkscript") 1) + (test:eq (string:levenshteinDistance "arkscript" "0rCscript") 2) + (test:eq (string:levenshteinDistance "arkscript" "OrC") 8) }) }) From 8d2d9c5ac9032dde5e91f61da3a795a5dcdb555e Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Wed, 25 Feb 2026 18:40:20 +0100 Subject: [PATCH 5/6] fix(math): prime? and divs should only accept integers, closes #49 --- Math.ark | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Math.ark b/Math.ark index 8347356..8e7756a 100644 --- a/Math.ark +++ b/Math.ark @@ -255,7 +255,7 @@ (let prime? (fun (n) (if (= 2 n) true - (if (or (= 0 (mod n 2)) (= 1 n)) + (if (or (= 0 (mod n 2)) (= 1 n) (!= 0 (mod n 1))) false { (let k (ceil (+ 1 (sqrt n)))) @@ -276,6 +276,7 @@ # @author https://github.com/Wafelack (let divs (fun (n) { (assert (>= n 1) "divs: n must be greater or equal to 1") + (assert (= 0 (mod n 1)) "divs: n must be an integer") (mut i 1) (mut divisors []) (let top (ceil (/ n 2))) From bff549d7940a4137f4e4262caad3fce9fb70046a Mon Sep 17 00:00:00 2001 From: Lexy Plt Date: Sat, 28 Feb 2026 12:38:29 +0100 Subject: [PATCH 6/6] chore: format code --- Dict.ark | 26 ++++++++++++-------------- String.ark | 11 +++++++++-- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Dict.ark b/Dict.ark index 99380df..63bde12 100644 --- a/Dict.ark +++ b/Dict.ark @@ -294,13 +294,12 @@ (mut _output "[") (mut _i 0) (while (< _i (len _L)) { - (set _output - (+ - _output - (_valAsJson (@ _L _i)) - (if (= (len _L) (+ 1 _i)) - "" - ", "))) + (set _output (+ + _output + (_valAsJson (@ _L _i)) + (if (= (len _L) (+ 1 _i)) + "" + ", "))) (set _i (+ 1 _i)) }) (+ _output "]") })) @@ -328,13 +327,12 @@ (mut _as_str "") (set _i 0) (while (< _i (len _output)) { - (set _as_str - (+ - _as_str - (@ _output _i) - (if (= (len _output) (+ 1 _i)) - "" - ", "))) + (set _as_str (+ + _as_str + (@ _output _i) + (if (= (len _output) (+ 1 _i)) + "" + ", "))) (set _i (+ 1 _i)) }) (+ "{" _as_str "}") })) diff --git a/String.ark b/String.ark index 9fd8957..5917cad 100644 --- a/String.ark +++ b/String.ark @@ -545,8 +545,15 @@ (let _dist [ (+ 1 (@@ _edit_distances (- _i 1) _j)) (+ 1 (@@ _edit_distances _i (- _j 1))) - (+ (if (= (@ _str1 (- _i 1)) (@ _str2 (- _j 1))) 0 1) (@@ _edit_distances (- _i 1) (- _j 1))) ]) - (@@= _edit_distances _i _j + (+ + (if (= (@ _str1 (- _i 1)) (@ _str2 (- _j 1))) + 0 + 1) + (@@ _edit_distances (- _i 1) (- _j 1)))]) + (@@= + _edit_distances + _i + _j (if (and (< (@ _dist 0) (@ _dist 1)) (< (@ _dist 0) (@ _dist 2))) (@ _dist 0) (if (and (< (@ _dist 1) (@ _dist 0)) (< (@ _dist 1) (@ _dist 2)))