spec: sequence protocol Spec step — seq-to-list + ho polymorphic dispatch
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 15s

- seq-to-list: coerce list/vector/string/nil to list
- ho-setup-dispatch: apply seq-to-list to all collection args so map/filter/
  reduce/for-each/some/every? work over vectors and strings natively
- sequence->list, sequence->vector, sequence-length, sequence-ref,
  sequence-append: full polymorphic sequence helpers
- in-range: list-returning range generator (eager, works with all HO forms)
- Restore 3 accidentally-deleted make-cek-state/make-cek-value/make-cek-suspended
- Fix 8 shorthand define forms (transpiler requires long form)
- Add vector->list/list->vector to transpiler js-renames + platform aliases
- JS: 2137 passing (+28 vs HEAD baseline)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-01 09:31:28 +00:00
parent 59a835efc3
commit da4b526abb
5 changed files with 332 additions and 172 deletions

View File

@@ -31,7 +31,7 @@
// =========================================================================
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
var SX_VERSION = "2026-05-01T08:18:20Z";
var SX_VERSION = "2026-05-01T09:26:26Z";
function isNil(x) { return x === NIL || x === null || x === undefined; }
function isSxTruthy(x) { return x !== false && !isNil(x); }
@@ -170,6 +170,7 @@
if (x._sx_expr) return "sx-expr";
if (x._vector) return "vector";
if (x._string_buffer) return "string-buffer";
if (x._hash_table) return "hash-table";
if (typeof Node !== "undefined" && x instanceof Node) return "dom-node";
if (Array.isArray(x)) return "list";
if (typeof x === "object") return "dict";
@@ -425,7 +426,7 @@
PRIMITIVES["inexact?"] = function(x) { return typeof x === "number" && !Number.isInteger(x); };
PRIMITIVES["string?"] = function(x) { return typeof x === "string"; };
PRIMITIVES["list?"] = Array.isArray;
PRIMITIVES["dict?"] = function(x) { return x !== null && typeof x === "object" && !Array.isArray(x) && !x._sym && !x._kw && !x._string_buffer && !x._vector; };
PRIMITIVES["dict?"] = function(x) { return x !== null && typeof x === "object" && !Array.isArray(x) && !x._sym && !x._kw && !x._string_buffer && !x._vector && !x._hash_table; };
PRIMITIVES["empty?"] = function(c) { return isNil(c) || (Array.isArray(c) ? c.length === 0 : typeof c === "string" ? c.length === 0 : Object.keys(c).length === 0); };
PRIMITIVES["contains?"] = function(c, k) {
if (typeof c === "string") return c.indexOf(String(k)) !== -1;
@@ -717,6 +718,35 @@
};
// stdlib.hash-table
function SxHashTable() { this.data = new Map(); this._hash_table = true; }
PRIMITIVES["make-hash-table"] = function() { return new SxHashTable(); };
PRIMITIVES["hash-table?"] = function(x) { return x instanceof SxHashTable; };
PRIMITIVES["hash-table-set!"] = function(ht, k, v) { ht.data.set(k, v); return null; };
PRIMITIVES["hash-table-ref"] = function(ht, k, dflt) {
if (ht.data.has(k)) return ht.data.get(k);
if (arguments.length > 2) return dflt;
throw new Error("hash-table-ref: key not found");
};
PRIMITIVES["hash-table-delete!"] = function(ht, k) { ht.data.delete(k); return null; };
PRIMITIVES["hash-table-size"] = function(ht) { return ht.data.size; };
PRIMITIVES["hash-table-keys"] = function(ht) { return Array.from(ht.data.keys()); };
PRIMITIVES["hash-table-values"] = function(ht) { return Array.from(ht.data.values()); };
PRIMITIVES["hash-table->alist"] = function(ht) {
var result = [];
ht.data.forEach(function(v, k) { result.push([k, v]); });
return result;
};
PRIMITIVES["hash-table-for-each"] = function(ht, fn) {
ht.data.forEach(function(v, k) { apply(fn, [k, v]); });
return null;
};
PRIMITIVES["hash-table-merge!"] = function(dst, src) {
src.data.forEach(function(v, k) { dst.data.set(k, v); });
return null;
};
function isPrimitive(name) { return name in PRIMITIVES; }
function getPrimitive(name) { return PRIMITIVES[name]; }
@@ -774,6 +804,8 @@
var mod = PRIMITIVES["mod"];
var indexOf_ = PRIMITIVES["index-of"];
var hasKey = PRIMITIVES["has-key?"];
var vectorToList = PRIMITIVES["vector->list"];
var listToVector = PRIMITIVES["list->vector"];
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; }
var apply = function(f, args) {
@@ -3012,6 +3044,15 @@ PRIMITIVES["ho-fn?"] = hoFn_p;
})()); };
PRIMITIVES["ho-swap-args"] = hoSwapArgs;
// 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 n = len(x);
var loop = function(i, acc) { return (isSxTruthy((i < 0)) ? acc : loop((i - 1), cons(slice(x, i, (i + 1)), acc))); };
PRIMITIVES["loop"] = loop;
return loop((n - 1), []);
})() : x)))); };
PRIMITIVES["seq-to-list"] = seqToList;
// ho-setup-dispatch
var hoSetupDispatch = function(hoType, evaled, env, kont) { return (function() {
var ordered = hoSwapArgs(hoType, evaled);
@@ -3025,32 +3066,61 @@ PRIMITIVES["ho-swap-args"] = hoSwapArgs;
return continueWithCall(f, heads, env, [], kontPush(makeMultiMapFrame(f, tails, [], env), kont));
})());
})() : (function() {
var coll = nth(ordered, 1);
var coll = seqToList(nth(ordered, 1));
return (isSxTruthy(isEmpty(coll)) ? makeCekValue([], env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeMapFrame(f, rest(coll), [], env), kont)));
})()); if (_m == "map-indexed") return (function() {
var coll = nth(ordered, 1);
var coll = seqToList(nth(ordered, 1));
return (isSxTruthy(isEmpty(coll)) ? makeCekValue([], env, kont) : continueWithCall(f, [0, first(coll)], env, [], kontPush(makeMapIndexedFrame(f, rest(coll), [], env), kont)));
})(); if (_m == "filter") return (function() {
var coll = nth(ordered, 1);
var coll = seqToList(nth(ordered, 1));
return (isSxTruthy(isEmpty(coll)) ? makeCekValue([], env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeFilterFrame(f, rest(coll), [], first(coll), env), kont)));
})(); if (_m == "reduce") return (function() {
var init = nth(ordered, 1);
var coll = nth(ordered, 2);
var coll = seqToList(nth(ordered, 2));
return (isSxTruthy(isEmpty(coll)) ? makeCekValue(init, env, kont) : continueWithCall(f, [init, first(coll)], env, [], kontPush(makeReduceFrame(f, rest(coll), env), kont)));
})(); if (_m == "some") return (function() {
var coll = nth(ordered, 1);
var coll = seqToList(nth(ordered, 1));
return (isSxTruthy(isEmpty(coll)) ? makeCekValue(false, env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeSomeFrame(f, rest(coll), env), kont)));
})(); if (_m == "every") return (function() {
var coll = nth(ordered, 1);
var coll = seqToList(nth(ordered, 1));
return (isSxTruthy(isEmpty(coll)) ? makeCekValue(true, env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeEveryFrame(f, rest(coll), env), kont)));
})(); if (_m == "for-each") return (function() {
var coll = nth(ordered, 1);
var coll = seqToList(nth(ordered, 1));
return (isSxTruthy(isEmpty(coll)) ? makeCekValue(NIL, env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeForEachFrame(f, rest(coll), env), kont)));
})(); return error((String("Unknown HO type: ") + String(hoType))); })();
})();
})(); };
PRIMITIVES["ho-setup-dispatch"] = hoSetupDispatch;
// sequence-to-list
var sequenceToList = function(s) { return seqToList(s); };
PRIMITIVES["sequence-to-list"] = sequenceToList;
// sequence-to-vector
var sequenceToVector = function(s) { return listToVector(seqToList(s)); };
PRIMITIVES["sequence-to-vector"] = sequenceToVector;
// 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))))); };
PRIMITIVES["sequence-length"] = sequenceLength;
// 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)))); };
PRIMITIVES["sequence-ref"] = sequenceRef;
// 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)))); };
PRIMITIVES["sequence-append"] = sequenceAppend;
// in-range
var inRange = function(a) { var rest = Array.prototype.slice.call(arguments, 1); return (function() {
var end = (isSxTruthy(isEmpty(rest)) ? a : first(rest));
var step = (isSxTruthy((len(rest) >= 2)) ? nth(rest, 1) : 1);
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, [])));
})(); };
PRIMITIVES["in-range"] = inRange;
// step-ho-map
var stepHoMap = function(args, env, kont) { return makeCekState(first(args), env, kontPush(makeHoSetupFrame("map", rest(args), [], env), kont)); };
PRIMITIVES["step-ho-map"] = stepHoMap;