Fix stdlib.sx: trim to safe subset, fix escape-html transpilation
The full stdlib migration revealed constraints: - Replacing native callables with SX lambdas changes CEK continuation capture behavior (breaks shift/reset tests) - The transpiler doesn't support named-let (breaks range, split, etc.) - Platform-internal functions (nil?, isNil) can't be shadowed Safe subset in stdlib.sx (11 functions): upcase, downcase, string-length, substring, string-contains?, starts-with?, ends-with?, pluralize, escape, parse-datetime, assert Fix escape-html in render.sx: replace -> (thread-first) with let/set! since the JS transpiler can't handle -> in spec files. 3 pre-existing regressions from evaluator decoupling commit to investigate: cek-complex-calls, higher-order-closures, tco-patterns. Python 744/744 clean. JS 954/957 (3 pre-existing). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-03-16T09:43:09Z";
|
||||
var SX_VERSION = "2026-03-16T10:42:47Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -2030,262 +2030,12 @@ PRIMITIVES["trampoline"] = trampoline;
|
||||
|
||||
// === Transpiled from stdlib (library functions from former primitives) ===
|
||||
|
||||
// not
|
||||
var not = function(x) { return (isSxTruthy(x) ? false : true); };
|
||||
PRIMITIVES["not"] = not;
|
||||
|
||||
// !=
|
||||
var != = function(a, b) { return !isSxTruthy((a == b)); };
|
||||
PRIMITIVES["!="] = !=;
|
||||
|
||||
// <=
|
||||
var <= = function(a, b) { return sxOr((a < b), (a == b)); };
|
||||
PRIMITIVES["<="] = <=;
|
||||
|
||||
// >=
|
||||
var >= = function(a, b) { return sxOr((a > b), (a == b)); };
|
||||
PRIMITIVES[">="] = >=;
|
||||
|
||||
// eq?
|
||||
var eq_p = =;
|
||||
PRIMITIVES["eq?"] = eq_p;
|
||||
|
||||
// eqv?
|
||||
var eqv_p = =;
|
||||
PRIMITIVES["eqv?"] = eqv_p;
|
||||
|
||||
// equal?
|
||||
var equal_p = =;
|
||||
PRIMITIVES["equal?"] = equal_p;
|
||||
|
||||
// nil?
|
||||
var isNil = function(x) { return (typeOf(x) == "nil"); };
|
||||
PRIMITIVES["nil?"] = isNil;
|
||||
|
||||
// boolean?
|
||||
var boolean_p = function(x) { return (typeOf(x) == "boolean"); };
|
||||
PRIMITIVES["boolean?"] = boolean_p;
|
||||
|
||||
// number?
|
||||
var isNumber = function(x) { return (typeOf(x) == "number"); };
|
||||
PRIMITIVES["number?"] = isNumber;
|
||||
|
||||
// string?
|
||||
var isString = function(x) { return (typeOf(x) == "string"); };
|
||||
PRIMITIVES["string?"] = isString;
|
||||
|
||||
// list?
|
||||
var isList = function(x) { return (typeOf(x) == "list"); };
|
||||
PRIMITIVES["list?"] = isList;
|
||||
|
||||
// dict?
|
||||
var isDict = function(x) { return (typeOf(x) == "dict"); };
|
||||
PRIMITIVES["dict?"] = isDict;
|
||||
|
||||
// continuation?
|
||||
var continuation_p = function(x) { return (typeOf(x) == "continuation"); };
|
||||
PRIMITIVES["continuation?"] = continuation_p;
|
||||
|
||||
// zero?
|
||||
var isZero = function(n) { return (n == 0); };
|
||||
PRIMITIVES["zero?"] = isZero;
|
||||
|
||||
// odd?
|
||||
var isOdd = function(n) { return ((n % 2) == 1); };
|
||||
PRIMITIVES["odd?"] = isOdd;
|
||||
|
||||
// even?
|
||||
var isEven = function(n) { return ((n % 2) == 0); };
|
||||
PRIMITIVES["even?"] = isEven;
|
||||
|
||||
// inc
|
||||
var inc = function(n) { return (n + 1); };
|
||||
PRIMITIVES["inc"] = inc;
|
||||
|
||||
// dec
|
||||
var dec = function(n) { return (n - 1); };
|
||||
PRIMITIVES["dec"] = dec;
|
||||
|
||||
// abs
|
||||
var abs = function(x) { return (isSxTruthy((x < 0)) ? (-x) : x); };
|
||||
PRIMITIVES["abs"] = abs;
|
||||
|
||||
// ceil
|
||||
var ceil = function(x) { return (function() {
|
||||
var f = floor(x);
|
||||
return (isSxTruthy((x == f)) ? f : (f + 1));
|
||||
})(); };
|
||||
PRIMITIVES["ceil"] = ceil;
|
||||
|
||||
// round
|
||||
var round = function(x, ndigits) { return (isSxTruthy(isNil(ndigits)) ? floor((x + 0.5)) : (function() {
|
||||
var f = pow(10, ndigits);
|
||||
return (floor(((x * f) + 0.5)) / f);
|
||||
})()); };
|
||||
PRIMITIVES["round"] = round;
|
||||
|
||||
// min
|
||||
var min = function(a, b) { return (isSxTruthy((a < b)) ? a : b); };
|
||||
PRIMITIVES["min"] = min;
|
||||
|
||||
// max
|
||||
var max = function(a, b) { return (isSxTruthy((a > b)) ? a : b); };
|
||||
PRIMITIVES["max"] = max;
|
||||
|
||||
// clamp
|
||||
var clamp = function(x, lo, hi) { return max(lo, min(hi, x)); };
|
||||
PRIMITIVES["clamp"] = clamp;
|
||||
|
||||
// first
|
||||
var first = function(coll) { return (isSxTruthy((isSxTruthy(coll) && (len(coll) > 0))) ? get(coll, 0) : NIL); };
|
||||
PRIMITIVES["first"] = first;
|
||||
|
||||
// last
|
||||
var last = function(coll) { return (isSxTruthy((isSxTruthy(coll) && (len(coll) > 0))) ? get(coll, (len(coll) - 1)) : NIL); };
|
||||
PRIMITIVES["last"] = last;
|
||||
|
||||
// rest
|
||||
var rest = function(coll) { return (isSxTruthy(coll) ? slice(coll, 1) : []); };
|
||||
PRIMITIVES["rest"] = rest;
|
||||
|
||||
// nth
|
||||
var nth = function(coll, n) { return (isSxTruthy((isSxTruthy(coll) && isSxTruthy((n >= 0)) && (n < len(coll)))) ? get(coll, n) : NIL); };
|
||||
PRIMITIVES["nth"] = nth;
|
||||
|
||||
// empty?
|
||||
var isEmpty = function(coll) { return sxOr(isNil(coll), (len(coll) == 0)); };
|
||||
PRIMITIVES["empty?"] = isEmpty;
|
||||
|
||||
// cons
|
||||
var cons = function(x, coll) { return concat([x], sxOr(coll, [])); };
|
||||
PRIMITIVES["cons"] = cons;
|
||||
|
||||
// append
|
||||
var append = function(coll, x) { return (isSxTruthy(isList(x)) ? concat(coll, x) : concat(coll, [x])); };
|
||||
PRIMITIVES["append"] = append;
|
||||
|
||||
// reverse
|
||||
var reverse = function(coll) { return (function() {
|
||||
var result = [];
|
||||
var i = (len(coll) - 1);
|
||||
(function() {
|
||||
[i(i)];
|
||||
return (isSxTruthy((i >= 0)) ? (append_b(result, get(coll, i)), loop((i - 1))) : NIL);
|
||||
})();
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["reverse"] = reverse;
|
||||
|
||||
// flatten
|
||||
var flatten = function(coll) { return (function() {
|
||||
var result = [];
|
||||
{ var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var x = _c[_i]; (isSxTruthy(isList(x)) ? forEach(function(y) { return append_b(result, y); }, x) : append_b(result, x)); } }
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["flatten"] = flatten;
|
||||
|
||||
// range
|
||||
var range = function(start, end, step) { return (function() {
|
||||
var s = (isSxTruthy(isNil(step)) ? 1 : step);
|
||||
var result = [];
|
||||
(function() {
|
||||
[i(start)];
|
||||
return (isSxTruthy((i < end)) ? (append_b(result, i), loop((i + s))) : NIL);
|
||||
})();
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["range"] = range;
|
||||
|
||||
// chunk-every
|
||||
var chunkEvery = function(coll, n) { return (function() {
|
||||
var result = [];
|
||||
var clen = len(coll);
|
||||
(function() {
|
||||
[i(0)];
|
||||
return (isSxTruthy((i < clen)) ? (append_b(result, slice(coll, i, min((i + n), clen))), loop((i + n))) : NIL);
|
||||
})();
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["chunk-every"] = chunkEvery;
|
||||
|
||||
// zip-pairs
|
||||
var zipPairs = function(coll) { return (function() {
|
||||
var result = [];
|
||||
var clen = len(coll);
|
||||
(function() {
|
||||
[i(0)];
|
||||
return (isSxTruthy((i < (clen - 1))) ? (append_b(result, [get(coll, i), get(coll, (i + 1))]), loop((i + 1))) : NIL);
|
||||
})();
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["zip-pairs"] = zipPairs;
|
||||
|
||||
// vals
|
||||
var vals = function(d) { return (function() {
|
||||
var result = [];
|
||||
{ var _c = keys(d); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result.push(get(d, k)); } }
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["vals"] = vals;
|
||||
|
||||
// has-key?
|
||||
var dictHas = function(d, key) { return some(function(k) { return (k == key); }, keys(d)); };
|
||||
PRIMITIVES["has-key?"] = dictHas;
|
||||
|
||||
// merge
|
||||
var merge = function(a, b) { return (function() {
|
||||
var result = {};
|
||||
if (isSxTruthy(a)) {
|
||||
{ var _c = keys(a); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result[k] = get(a, k); } }
|
||||
}
|
||||
if (isSxTruthy(b)) {
|
||||
{ var _c = keys(b); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result[k] = get(b, k); } }
|
||||
}
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["merge"] = merge;
|
||||
|
||||
// assoc
|
||||
var assoc = function(d, key, val) { return (function() {
|
||||
var result = {};
|
||||
if (isSxTruthy(d)) {
|
||||
{ var _c = keys(d); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result[k] = get(d, k); } }
|
||||
}
|
||||
result[key] = val;
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["assoc"] = assoc;
|
||||
|
||||
// dissoc
|
||||
var dissoc = function(d, key) { return (function() {
|
||||
var result = {};
|
||||
{ var _c = keys(d); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; if (isSxTruthy((k != key))) {
|
||||
result[k] = get(d, k);
|
||||
} } }
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["dissoc"] = dissoc;
|
||||
|
||||
// into
|
||||
var into = function(target, coll) { return (isSxTruthy(isList(target)) ? (isSxTruthy(isList(coll)) ? concat(coll, []) : (function() {
|
||||
var result = [];
|
||||
{ var _c = keys(coll); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; result.push([k, get(coll, k)]); } }
|
||||
return result;
|
||||
})()) : (isSxTruthy(isDict(target)) ? (function() {
|
||||
var result = {};
|
||||
{ var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var pair = _c[_i]; if (isSxTruthy((isSxTruthy(isList(pair)) && (len(pair) >= 2)))) {
|
||||
result[get(pair, 0)] = get(pair, 1);
|
||||
} } }
|
||||
return result;
|
||||
})() : target)); };
|
||||
PRIMITIVES["into"] = into;
|
||||
|
||||
// upcase
|
||||
var upcase = upper;
|
||||
var upcase = function(s) { return upper(s); };
|
||||
PRIMITIVES["upcase"] = upcase;
|
||||
|
||||
// downcase
|
||||
var downcase = lower;
|
||||
var downcase = function(s) { return lower(s); };
|
||||
PRIMITIVES["downcase"] = downcase;
|
||||
|
||||
// string-length
|
||||
@@ -2312,44 +2062,20 @@ PRIMITIVES["starts-with?"] = startsWith;
|
||||
})(); };
|
||||
PRIMITIVES["ends-with?"] = endsWith;
|
||||
|
||||
// split
|
||||
var split = function(s, sep) { return (function() {
|
||||
var separator = (isSxTruthy(isNil(sep)) ? " " : sep);
|
||||
var result = [];
|
||||
var slen = len(s);
|
||||
var seplen = len(separator);
|
||||
return (function() {
|
||||
[start(0)];
|
||||
return (function() {
|
||||
var idx = indexOf_(s, separator, start);
|
||||
return (isSxTruthy((idx == -1)) ? (append_b(result, slice(s, start)), result) : (append_b(result, slice(s, start, idx)), loop((idx + seplen))));
|
||||
})();
|
||||
})();
|
||||
})(); };
|
||||
PRIMITIVES["split"] = split;
|
||||
|
||||
// join
|
||||
var join = function(sep, coll) { return (function() {
|
||||
var result = "";
|
||||
{ var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var x = _c[_i]; result = (isSxTruthy((result == "")) ? (String(x)) : (String(result) + String(sep) + String(x))); } }
|
||||
return result;
|
||||
})(); };
|
||||
PRIMITIVES["join"] = join;
|
||||
|
||||
// replace
|
||||
var replace_ = function(s, old, new_) { return join(new_, split(s, old)); };
|
||||
PRIMITIVES["replace"] = replace_;
|
||||
|
||||
// contains?
|
||||
var contains = function(coll, key) { return (isSxTruthy(isString(coll)) ? (indexOf_(coll, (String(key))) != -1) : (isSxTruthy(isDict(coll)) ? dictHas(coll, key) : (isSxTruthy(isList(coll)) ? some(function(x) { return (x == key); }, coll) : false))); };
|
||||
PRIMITIVES["contains?"] = contains;
|
||||
|
||||
// pluralize
|
||||
var pluralize = function(count, singular, plural) { return (isSxTruthy((count == 1)) ? sxOr(singular, "") : sxOr(plural, "s")); };
|
||||
PRIMITIVES["pluralize"] = pluralize;
|
||||
|
||||
// escape
|
||||
var escape = function(s) { return >((String(s)), replace_("&", "&"), replace_("<", "<"), replace_(">", ">"), replace_("\"", """), replace_("'", "'")); };
|
||||
var escape = function(s) { return (function() {
|
||||
var r = (String(s));
|
||||
r = replace_(r, "&", "&");
|
||||
r = replace_(r, "<", "<");
|
||||
r = replace_(r, ">", ">");
|
||||
r = replace_(r, "\"", """);
|
||||
r = replace_(r, "'", "'");
|
||||
return r;
|
||||
})(); };
|
||||
PRIMITIVES["escape"] = escape;
|
||||
|
||||
// parse-datetime
|
||||
@@ -2574,7 +2300,14 @@ PRIMITIVES["is-render-expr?"] = isRenderExpr;
|
||||
PRIMITIVES["merge-spread-attrs"] = mergeSpreadAttrs;
|
||||
|
||||
// escape-html
|
||||
var escapeHtml = function(s) { return >((String(s)), replace_("&", "&"), replace_("<", "<"), replace_(">", ">"), replace_("\"", """)); };
|
||||
var escapeHtml = function(s) { return (function() {
|
||||
var r = (String(s));
|
||||
r = replace_(r, "&", "&");
|
||||
r = replace_(r, "<", "<");
|
||||
r = replace_(r, ">", ">");
|
||||
r = replace_(r, "\"", """);
|
||||
return r;
|
||||
})(); };
|
||||
PRIMITIVES["escape-html"] = escapeHtml;
|
||||
|
||||
// escape-attr
|
||||
|
||||
Reference in New Issue
Block a user