spec: sequence protocol tests — 45 tests, all passing on JS and OCaml
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1659,6 +1659,10 @@ PLATFORM_JS_POST = '''
|
|||||||
var hasKey = PRIMITIVES["has-key?"];
|
var hasKey = PRIMITIVES["has-key?"];
|
||||||
var vectorToList = PRIMITIVES["vector->list"];
|
var vectorToList = PRIMITIVES["vector->list"];
|
||||||
var listToVector = PRIMITIVES["list->vector"];
|
var listToVector = PRIMITIVES["list->vector"];
|
||||||
|
var isVector = PRIMITIVES["vector?"];
|
||||||
|
var vectorLength = PRIMITIVES["vector-length"];
|
||||||
|
var vectorRef = PRIMITIVES["vector-ref"];
|
||||||
|
var reverse = PRIMITIVES["reverse"];
|
||||||
function zip(a, b) { var r = []; for (var i = 0; i < Math.min(a.length, b.length); i++) r.push([a[i], b[i]]); return r; }
|
function zip(a, b) { var r = []; for (var i = 0; i < Math.min(a.length, b.length); i++) r.push([a[i], b[i]]); return r; }
|
||||||
function append_b(arr, x) { arr.push(x); return arr; }
|
function append_b(arr, x) { arr.push(x); return arr; }
|
||||||
var apply = function(f, args) {
|
var apply = function(f, args) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -31,7 +31,7 @@
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||||
var SX_VERSION = "2026-05-01T09:26:26Z";
|
var SX_VERSION = "2026-05-01T10:16:10Z";
|
||||||
|
|
||||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||||
@@ -806,6 +806,10 @@
|
|||||||
var hasKey = PRIMITIVES["has-key?"];
|
var hasKey = PRIMITIVES["has-key?"];
|
||||||
var vectorToList = PRIMITIVES["vector->list"];
|
var vectorToList = PRIMITIVES["vector->list"];
|
||||||
var listToVector = PRIMITIVES["list->vector"];
|
var listToVector = PRIMITIVES["list->vector"];
|
||||||
|
var isVector = PRIMITIVES["vector?"];
|
||||||
|
var vectorLength = PRIMITIVES["vector-length"];
|
||||||
|
var vectorRef = PRIMITIVES["vector-ref"];
|
||||||
|
var reverse = PRIMITIVES["reverse"];
|
||||||
function zip(a, b) { var r = []; for (var i = 0; i < Math.min(a.length, b.length); i++) r.push([a[i], b[i]]); return r; }
|
function zip(a, b) { var r = []; for (var i = 0; i < Math.min(a.length, b.length); i++) r.push([a[i], b[i]]); return r; }
|
||||||
function append_b(arr, x) { arr.push(x); return arr; }
|
function append_b(arr, x) { arr.push(x); return arr; }
|
||||||
var apply = function(f, args) {
|
var apply = function(f, args) {
|
||||||
@@ -3045,7 +3049,7 @@ PRIMITIVES["ho-fn?"] = hoFn_p;
|
|||||||
PRIMITIVES["ho-swap-args"] = hoSwapArgs;
|
PRIMITIVES["ho-swap-args"] = hoSwapArgs;
|
||||||
|
|
||||||
// seq-to-list
|
// seq-to-list
|
||||||
var seqToList = function(x) { return (isSxTruthy(sxEq(x, NIL)) ? [] : (isSxTruthy(isList(x)) ? x : (isSxTruthy(vector_p(x)) ? vectorToList(x) : (isSxTruthy(isString(x)) ? (function() {
|
var seqToList = function(x) { return (isSxTruthy(sxEq(x, NIL)) ? [] : (isSxTruthy(isList(x)) ? x : (isSxTruthy(isVector(x)) ? vectorToList(x) : (isSxTruthy(isString(x)) ? (function() {
|
||||||
var n = len(x);
|
var n = len(x);
|
||||||
var loop = function(i, acc) { return (isSxTruthy((i < 0)) ? acc : loop((i - 1), cons(slice(x, i, (i + 1)), acc))); };
|
var loop = function(i, acc) { return (isSxTruthy((i < 0)) ? acc : loop((i - 1), cons(slice(x, i, (i + 1)), acc))); };
|
||||||
PRIMITIVES["loop"] = loop;
|
PRIMITIVES["loop"] = loop;
|
||||||
@@ -3101,23 +3105,27 @@ PRIMITIVES["sequence-to-list"] = sequenceToList;
|
|||||||
PRIMITIVES["sequence-to-vector"] = sequenceToVector;
|
PRIMITIVES["sequence-to-vector"] = sequenceToVector;
|
||||||
|
|
||||||
// sequence-length
|
// sequence-length
|
||||||
var sequenceLength = function(s) { return (isSxTruthy(sxOr(sxEq(s, NIL), isList(s))) ? len(s) : (isSxTruthy(vector_p(s)) ? vectorLength(s) : (isSxTruthy(isString(s)) ? len(s) : len(seqToList(s))))); };
|
var sequenceLength = function(s) { return (isSxTruthy(sxEq(s, NIL)) ? 0 : (isSxTruthy(isList(s)) ? len(s) : (isSxTruthy(isVector(s)) ? vectorLength(s) : (isSxTruthy(isString(s)) ? len(s) : len(seqToList(s)))))); };
|
||||||
PRIMITIVES["sequence-length"] = sequenceLength;
|
PRIMITIVES["sequence-length"] = sequenceLength;
|
||||||
|
|
||||||
// sequence-ref
|
// sequence-ref
|
||||||
var sequenceRef = function(s, i) { return (isSxTruthy(sxOr(sxEq(s, NIL), isList(s))) ? nth(s, i) : (isSxTruthy(vector_p(s)) ? vectorRef(s, i) : (isSxTruthy(isString(s)) ? slice(s, i, (i + 1)) : nth(seqToList(s), i)))); };
|
var sequenceRef = function(s, i) { return (isSxTruthy(sxOr(sxEq(s, NIL), isList(s))) ? nth(s, i) : (isSxTruthy(isVector(s)) ? vectorRef(s, i) : (isSxTruthy(isString(s)) ? slice(s, i, (i + 1)) : nth(seqToList(s), i)))); };
|
||||||
PRIMITIVES["sequence-ref"] = sequenceRef;
|
PRIMITIVES["sequence-ref"] = sequenceRef;
|
||||||
|
|
||||||
// sequence-append
|
// sequence-append
|
||||||
var sequenceAppend = function(s1, s2) { return (isSxTruthy((isSxTruthy(vector_p(s1)) && vector_p(s2))) ? listToVector(concat(vectorToList(s1), vectorToList(s2))) : (isSxTruthy((isSxTruthy(isString(s1)) && isString(s2))) ? (String(s1) + String(s2)) : concat(seqToList(s1), seqToList(s2)))); };
|
var sequenceAppend = function(s1, s2) { return (isSxTruthy((isSxTruthy(isVector(s1)) && isVector(s2))) ? listToVector(concat(vectorToList(s1), vectorToList(s2))) : (isSxTruthy((isSxTruthy(isString(s1)) && isString(s2))) ? (String(s1) + String(s2)) : concat(seqToList(s1), seqToList(s2)))); };
|
||||||
PRIMITIVES["sequence-append"] = sequenceAppend;
|
PRIMITIVES["sequence-append"] = sequenceAppend;
|
||||||
|
|
||||||
|
// build-range
|
||||||
|
var buildRange = function(i, end, step, acc) { return (isSxTruthy((isSxTruthy((step > 0)) ? (i >= end) : (i <= end))) ? reverse(acc) : buildRange((i + step), end, step, cons(i, acc))); };
|
||||||
|
PRIMITIVES["build-range"] = buildRange;
|
||||||
|
|
||||||
// in-range
|
// in-range
|
||||||
var inRange = function(a) { var rest = Array.prototype.slice.call(arguments, 1); return (function() {
|
var inRange = function(a) { var rest = Array.prototype.slice.call(arguments, 1); return (function() {
|
||||||
var end = (isSxTruthy(isEmpty(rest)) ? a : first(rest));
|
var end = (isSxTruthy(isEmpty(rest)) ? a : first(rest));
|
||||||
var step = (isSxTruthy((len(rest) >= 2)) ? nth(rest, 1) : 1);
|
var step = (isSxTruthy((len(rest) >= 2)) ? nth(rest, 1) : 1);
|
||||||
var realStart = (isSxTruthy(isEmpty(rest)) ? 0 : a);
|
var realStart = (isSxTruthy(isEmpty(rest)) ? 0 : a);
|
||||||
return (isSxTruthy(sxEq(step, 0)) ? error("in-range: step cannot be zero") : (define(build, function(i, acc) { return (isSxTruthy((isSxTruthy((step > 0)) ? (i >= end) : (i <= end))) ? reverse(acc) : build((i + step), cons(i, acc))); }), build(realStart, [])));
|
return (isSxTruthy(sxEq(step, 0)) ? error("in-range: step cannot be zero") : buildRange(realStart, end, step, []));
|
||||||
})(); };
|
})(); };
|
||||||
PRIMITIVES["in-range"] = inRange;
|
PRIMITIVES["in-range"] = inRange;
|
||||||
|
|
||||||
|
|||||||
@@ -3649,7 +3649,8 @@
|
|||||||
(fn
|
(fn
|
||||||
(s)
|
(s)
|
||||||
(cond
|
(cond
|
||||||
((or (= s nil) (list? s)) (len s))
|
((= s nil) 0)
|
||||||
|
((list? s) (len s))
|
||||||
((vector? s) (vector-length s))
|
((vector? s) (vector-length s))
|
||||||
((string? s) (len s))
|
((string? s) (len s))
|
||||||
(else (len (seq-to-list s))))))
|
(else (len (seq-to-list s))))))
|
||||||
@@ -3674,6 +3675,15 @@
|
|||||||
((and (string? s1) (string? s2)) (str s1 s2))
|
((and (string? s1) (string? s2)) (str s1 s2))
|
||||||
(else (concat (seq-to-list s1) (seq-to-list s2))))))
|
(else (concat (seq-to-list s1) (seq-to-list s2))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
build-range
|
||||||
|
(fn
|
||||||
|
(i end step acc)
|
||||||
|
(if
|
||||||
|
(if (> step 0) (>= i end) (<= i end))
|
||||||
|
(reverse acc)
|
||||||
|
(build-range (+ i step) end step (cons i acc)))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
in-range
|
in-range
|
||||||
(fn
|
(fn
|
||||||
@@ -3686,16 +3696,7 @@
|
|||||||
(if
|
(if
|
||||||
(= step 0)
|
(= step 0)
|
||||||
(error "in-range: step cannot be zero")
|
(error "in-range: step cannot be zero")
|
||||||
(do
|
(build-range real-start end step (list))))))
|
||||||
(define
|
|
||||||
build
|
|
||||||
(fn
|
|
||||||
(i acc)
|
|
||||||
(if
|
|
||||||
(if (> step 0) (>= i end) (<= i end))
|
|
||||||
(reverse acc)
|
|
||||||
(build (+ i step) (cons i acc)))))
|
|
||||||
(build real-start (list)))))))
|
|
||||||
|
|
||||||
(define
|
(define
|
||||||
step-ho-map
|
step-ho-map
|
||||||
|
|||||||
202
spec/tests/test-sequences.sx
Normal file
202
spec/tests/test-sequences.sx
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
;; test-sequences.sx — Phase 11: sequence protocol tests
|
||||||
|
|
||||||
|
(defsuite
|
||||||
|
"sequences"
|
||||||
|
(deftest
|
||||||
|
"seq-to-list nil is empty list"
|
||||||
|
(assert-equal (list) (seq-to-list nil)))
|
||||||
|
(deftest
|
||||||
|
"seq-to-list list is identity"
|
||||||
|
(assert-equal
|
||||||
|
(list 1 2 3)
|
||||||
|
(seq-to-list (list 1 2 3))))
|
||||||
|
(deftest
|
||||||
|
"seq-to-list vector to list"
|
||||||
|
(assert-equal
|
||||||
|
(list 10 20 30)
|
||||||
|
(seq-to-list (vector 10 20 30))))
|
||||||
|
(deftest
|
||||||
|
"seq-to-list string to char list"
|
||||||
|
(assert-equal (list "a" "b" "c") (seq-to-list "abc")))
|
||||||
|
(deftest
|
||||||
|
"seq-to-list empty string to empty list"
|
||||||
|
(assert-equal (list) (seq-to-list "")))
|
||||||
|
(deftest
|
||||||
|
"sequence-to-list nil is empty list"
|
||||||
|
(assert-equal (list) (sequence-to-list nil)))
|
||||||
|
(deftest
|
||||||
|
"sequence-to-list list is identity"
|
||||||
|
(assert-equal
|
||||||
|
(list 1 2 3)
|
||||||
|
(sequence-to-list (list 1 2 3))))
|
||||||
|
(deftest
|
||||||
|
"sequence-to-list vector to list"
|
||||||
|
(assert-equal (list "x" "y") (sequence-to-list (vector "x" "y"))))
|
||||||
|
(deftest
|
||||||
|
"sequence-to-list string to char list"
|
||||||
|
(assert-equal (list "h" "i") (sequence-to-list "hi")))
|
||||||
|
(deftest
|
||||||
|
"sequence-to-vector nil is empty vector"
|
||||||
|
(let
|
||||||
|
((v (sequence-to-vector nil)))
|
||||||
|
(do (assert (vector? v)) (assert= 0 (vector-length v)))))
|
||||||
|
(deftest
|
||||||
|
"sequence-to-vector list to vector"
|
||||||
|
(let
|
||||||
|
((v (sequence-to-vector (list 1 2 3))))
|
||||||
|
(do
|
||||||
|
(assert (vector? v))
|
||||||
|
(assert= 3 (vector-length v))
|
||||||
|
(assert= 1 (vector-ref v 0))
|
||||||
|
(assert= 3 (vector-ref v 2)))))
|
||||||
|
(deftest
|
||||||
|
"sequence-to-vector string to vector of chars"
|
||||||
|
(let
|
||||||
|
((v (sequence-to-vector "abc")))
|
||||||
|
(do
|
||||||
|
(assert (vector? v))
|
||||||
|
(assert= 3 (vector-length v))
|
||||||
|
(assert= "a" (vector-ref v 0))
|
||||||
|
(assert= "c" (vector-ref v 2)))))
|
||||||
|
(deftest
|
||||||
|
"sequence-length nil is 0"
|
||||||
|
(assert= 0 (sequence-length nil)))
|
||||||
|
(deftest
|
||||||
|
"sequence-length empty list is 0"
|
||||||
|
(assert= 0 (sequence-length (list))))
|
||||||
|
(deftest
|
||||||
|
"sequence-length list of 3"
|
||||||
|
(assert=
|
||||||
|
3
|
||||||
|
(sequence-length (list 1 2 3))))
|
||||||
|
(deftest
|
||||||
|
"sequence-length empty vector is 0"
|
||||||
|
(assert= 0 (sequence-length (vector))))
|
||||||
|
(deftest
|
||||||
|
"sequence-length vector of 4"
|
||||||
|
(assert=
|
||||||
|
4
|
||||||
|
(sequence-length (vector 10 20 30 40))))
|
||||||
|
(deftest
|
||||||
|
"sequence-length empty string is 0"
|
||||||
|
(assert= 0 (sequence-length "")))
|
||||||
|
(deftest
|
||||||
|
"sequence-length string hello"
|
||||||
|
(assert= 5 (sequence-length "hello")))
|
||||||
|
(deftest
|
||||||
|
"sequence-ref list first"
|
||||||
|
(assert=
|
||||||
|
10
|
||||||
|
(sequence-ref (list 10 20 30) 0)))
|
||||||
|
(deftest
|
||||||
|
"sequence-ref list last"
|
||||||
|
(assert=
|
||||||
|
30
|
||||||
|
(sequence-ref (list 10 20 30) 2)))
|
||||||
|
(deftest
|
||||||
|
"sequence-ref vector middle"
|
||||||
|
(assert=
|
||||||
|
20
|
||||||
|
(sequence-ref (vector 10 20 30) 1)))
|
||||||
|
(deftest
|
||||||
|
"sequence-ref string first char"
|
||||||
|
(assert= "h" (sequence-ref "hello" 0)))
|
||||||
|
(deftest
|
||||||
|
"sequence-ref string last char"
|
||||||
|
(assert= "o" (sequence-ref "hello" 4)))
|
||||||
|
(deftest
|
||||||
|
"sequence-append two lists"
|
||||||
|
(assert-equal
|
||||||
|
(list 1 2 3 4)
|
||||||
|
(sequence-append
|
||||||
|
(list 1 2)
|
||||||
|
(list 3 4))))
|
||||||
|
(deftest
|
||||||
|
"sequence-append list with empty"
|
||||||
|
(assert-equal
|
||||||
|
(list 1 2)
|
||||||
|
(sequence-append (list 1 2) (list))))
|
||||||
|
(deftest
|
||||||
|
"sequence-append two strings"
|
||||||
|
(assert= "hello world" (sequence-append "hello " "world")))
|
||||||
|
(deftest
|
||||||
|
"sequence-append empty strings"
|
||||||
|
(assert= "abc" (sequence-append "" "abc")))
|
||||||
|
(deftest
|
||||||
|
"in-range 1-arg gives 0..n-1"
|
||||||
|
(assert-equal
|
||||||
|
(list 0 1 2 3 4)
|
||||||
|
(in-range 5)))
|
||||||
|
(deftest
|
||||||
|
"in-range 1-arg zero is empty"
|
||||||
|
(assert-equal (list) (in-range 0)))
|
||||||
|
(deftest
|
||||||
|
"in-range 2-arg start and end"
|
||||||
|
(assert-equal
|
||||||
|
(list 1 2 3)
|
||||||
|
(in-range 1 4)))
|
||||||
|
(deftest
|
||||||
|
"in-range 2-arg same start end is empty"
|
||||||
|
(assert-equal (list) (in-range 3 3)))
|
||||||
|
(deftest
|
||||||
|
"in-range 3-arg with step 2"
|
||||||
|
(assert-equal
|
||||||
|
(list 0 2 4)
|
||||||
|
(in-range 0 6 2)))
|
||||||
|
(deftest
|
||||||
|
"in-range result is a list"
|
||||||
|
(assert (list? (in-range 5))))
|
||||||
|
(deftest
|
||||||
|
"in-range length is correct"
|
||||||
|
(assert= 10 (len (in-range 10))))
|
||||||
|
(deftest
|
||||||
|
"map over vector"
|
||||||
|
(assert-equal
|
||||||
|
(list 2 4 6)
|
||||||
|
(map
|
||||||
|
(fn (x) (* x 2))
|
||||||
|
(vector 1 2 3))))
|
||||||
|
(deftest
|
||||||
|
"filter over vector keeps odds"
|
||||||
|
(assert-equal
|
||||||
|
(list 1 3 5)
|
||||||
|
(filter
|
||||||
|
odd?
|
||||||
|
(vector 1 2 3 4 5))))
|
||||||
|
(deftest
|
||||||
|
"reduce over vector sums"
|
||||||
|
(assert=
|
||||||
|
10
|
||||||
|
(reduce
|
||||||
|
+
|
||||||
|
0
|
||||||
|
(vector 1 2 3 4))))
|
||||||
|
(deftest
|
||||||
|
"some over vector finds odd"
|
||||||
|
(assert (some odd? (vector 2 4 3 6))))
|
||||||
|
(deftest
|
||||||
|
"every? over vector all even"
|
||||||
|
(assert
|
||||||
|
(every? even? (vector 2 4 6 8))))
|
||||||
|
(deftest
|
||||||
|
"every? over vector fails with odd"
|
||||||
|
(assert= false (every? even? (vector 2 3 6))))
|
||||||
|
(deftest
|
||||||
|
"map over in-range squares"
|
||||||
|
(assert-equal
|
||||||
|
(list 0 1 4 9 16)
|
||||||
|
(map (fn (x) (* x x)) (in-range 5))))
|
||||||
|
(deftest
|
||||||
|
"filter over in-range keeps evens"
|
||||||
|
(assert-equal
|
||||||
|
(list 0 2 4 6)
|
||||||
|
(filter even? (in-range 7))))
|
||||||
|
(deftest
|
||||||
|
"reduce over in-range sums"
|
||||||
|
(assert= 15 (reduce + 0 (in-range 6))))
|
||||||
|
(deftest
|
||||||
|
"map over string returns char list"
|
||||||
|
(assert-equal (list "a" "b" "c") (map (fn (c) c) "abc")))
|
||||||
|
(deftest
|
||||||
|
"filter over string keeps matching chars"
|
||||||
|
(assert-equal (list "p" "p") (filter (fn (c) (= c "p")) "apple"))))
|
||||||
Reference in New Issue
Block a user