CEK-native higher-order forms: map, filter, reduce, some, every?, for-each
Some checks are pending
Build and Deploy / build-and-deploy (push) Has started running
Some checks are pending
Build and Deploy / build-and-deploy (push) Has started running
Higher-order forms now step element-by-element through the CEK machine using dedicated frames instead of delegating to tree-walk ho-map etc. Each callback invocation goes through continue-with-call, so deref-as-shift works inside map/filter/reduce callbacks in reactive island contexts. - cek.sx: rewrite step-ho-* to use CEK frames, add frame handlers in step-continue for map, filter, reduce, for-each, some, every - frames.sx: add SomeFrame, EveryFrame, MapIndexedFrame - test-cek-reactive.sx: add 10 tests for CEK-native HO forms 89 tests pass (20 signal + 43 CEK + 26 CEK reactive). 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-14T10:27:39Z";
|
||||
var SX_VERSION = "2026-03-14T10:44:25Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -3922,7 +3922,10 @@ callExpr.push(dictGet(kwargs, k)); } }
|
||||
var makeThreadFrame = function(remaining, env) { return {"type": "thread", "remaining": remaining, "env": env}; };
|
||||
|
||||
// make-map-frame
|
||||
var makeMapFrame = function(f, remaining, results, env) { return {"type": "map", "f": f, "remaining": remaining, "results": results, "env": env}; };
|
||||
var makeMapFrame = function(f, remaining, results, env) { return {"type": "map", "f": f, "remaining": remaining, "results": results, "env": env, "indexed": false}; };
|
||||
|
||||
// make-map-indexed-frame
|
||||
var makeMapIndexedFrame = function(f, remaining, results, env) { return {"type": "map", "f": f, "remaining": remaining, "results": results, "env": env, "indexed": true}; };
|
||||
|
||||
// make-filter-frame
|
||||
var makeFilterFrame = function(f, remaining, results, currentItem, env) { return {"type": "filter", "f": f, "remaining": remaining, "results": results, "current-item": currentItem, "env": env}; };
|
||||
@@ -3933,6 +3936,12 @@ callExpr.push(dictGet(kwargs, k)); } }
|
||||
// make-for-each-frame
|
||||
var makeForEachFrame = function(f, remaining, env) { return {"type": "for-each", "f": f, "remaining": remaining, "env": env}; };
|
||||
|
||||
// make-some-frame
|
||||
var makeSomeFrame = function(f, remaining, env) { return {"type": "some", "f": f, "remaining": remaining, "env": env}; };
|
||||
|
||||
// make-every-frame
|
||||
var makeEveryFrame = function(f, remaining, env) { return {"type": "every", "f": f, "remaining": remaining, "env": env}; };
|
||||
|
||||
// make-scope-frame
|
||||
var makeScopeFrame = function(name, remaining, env) { return {"type": "scope", "name": name, "remaining": remaining, "env": env}; };
|
||||
|
||||
@@ -4440,7 +4449,7 @@ return scan(kont, []); };
|
||||
var args = rest(expr);
|
||||
return (isSxTruthy(!isSxTruthy(sxOr((typeOf(head) == "symbol"), (typeOf(head) == "lambda"), (typeOf(head) == "list")))) ? (isSxTruthy(isEmpty(expr)) ? makeCekValue([], env, kont) : makeCekState(first(expr), env, kontPush(makeMapFrame(NIL, rest(expr), [], env), kont))) : (isSxTruthy((typeOf(head) == "symbol")) ? (function() {
|
||||
var name = symbolName(head);
|
||||
return (isSxTruthy((name == "if")) ? stepSfIf(args, env, kont) : (isSxTruthy((name == "when")) ? stepSfWhen(args, env, kont) : (isSxTruthy((name == "cond")) ? stepSfCond(args, env, kont) : (isSxTruthy((name == "case")) ? stepSfCase(args, env, kont) : (isSxTruthy((name == "and")) ? stepSfAnd(args, env, kont) : (isSxTruthy((name == "or")) ? stepSfOr(args, env, kont) : (isSxTruthy((name == "let")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "let*")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "lambda")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "fn")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "define")) ? stepSfDefine(args, env, kont) : (isSxTruthy((name == "defcomp")) ? makeCekValue(sfDefcomp(args, env), env, kont) : (isSxTruthy((name == "defisland")) ? makeCekValue(sfDefisland(args, env), env, kont) : (isSxTruthy((name == "defmacro")) ? makeCekValue(sfDefmacro(args, env), env, kont) : (isSxTruthy((name == "defstyle")) ? makeCekValue(sfDefstyle(args, env), env, kont) : (isSxTruthy((name == "defhandler")) ? makeCekValue(sfDefhandler(args, env), env, kont) : (isSxTruthy((name == "defpage")) ? makeCekValue(sfDefpage(args, env), env, kont) : (isSxTruthy((name == "defquery")) ? makeCekValue(sfDefquery(args, env), env, kont) : (isSxTruthy((name == "defaction")) ? makeCekValue(sfDefaction(args, env), env, kont) : (isSxTruthy((name == "deftype")) ? makeCekValue(sfDeftype(args, env), env, kont) : (isSxTruthy((name == "defeffect")) ? makeCekValue(sfDefeffect(args, env), env, kont) : (isSxTruthy((name == "begin")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "do")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "quote")) ? makeCekValue((isSxTruthy(isEmpty(args)) ? NIL : first(args)), env, kont) : (isSxTruthy((name == "quasiquote")) ? makeCekValue(qqExpand(first(args), env), env, kont) : (isSxTruthy((name == "->")) ? stepSfThreadFirst(args, env, kont) : (isSxTruthy((name == "set!")) ? stepSfSet(args, env, kont) : (isSxTruthy((name == "letrec")) ? makeCekValue(sfLetrec(args, env), env, kont) : (isSxTruthy((name == "reset")) ? stepSfReset(args, env, kont) : (isSxTruthy((name == "shift")) ? stepSfShift(args, env, kont) : (isSxTruthy((name == "deref")) ? stepSfDeref(args, env, kont) : (isSxTruthy((name == "scope")) ? stepSfScope(args, env, kont) : (isSxTruthy((name == "provide")) ? stepSfProvide(args, env, kont) : (isSxTruthy((name == "dynamic-wind")) ? makeCekValue(sfDynamicWind(args, env), env, kont) : (isSxTruthy((name == "map")) ? stepHoMap(args, env, kont) : (isSxTruthy((name == "map-indexed")) ? makeCekValue(hoMapIndexed(args, env), env, kont) : (isSxTruthy((name == "filter")) ? stepHoFilter(args, env, kont) : (isSxTruthy((name == "reduce")) ? stepHoReduce(args, env, kont) : (isSxTruthy((name == "some")) ? makeCekValue(hoSome(args, env), env, kont) : (isSxTruthy((name == "every?")) ? makeCekValue(hoEvery(args, env), env, kont) : (isSxTruthy((name == "for-each")) ? stepHoForEach(args, env, kont) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() {
|
||||
return (isSxTruthy((name == "if")) ? stepSfIf(args, env, kont) : (isSxTruthy((name == "when")) ? stepSfWhen(args, env, kont) : (isSxTruthy((name == "cond")) ? stepSfCond(args, env, kont) : (isSxTruthy((name == "case")) ? stepSfCase(args, env, kont) : (isSxTruthy((name == "and")) ? stepSfAnd(args, env, kont) : (isSxTruthy((name == "or")) ? stepSfOr(args, env, kont) : (isSxTruthy((name == "let")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "let*")) ? stepSfLet(args, env, kont) : (isSxTruthy((name == "lambda")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "fn")) ? stepSfLambda(args, env, kont) : (isSxTruthy((name == "define")) ? stepSfDefine(args, env, kont) : (isSxTruthy((name == "defcomp")) ? makeCekValue(sfDefcomp(args, env), env, kont) : (isSxTruthy((name == "defisland")) ? makeCekValue(sfDefisland(args, env), env, kont) : (isSxTruthy((name == "defmacro")) ? makeCekValue(sfDefmacro(args, env), env, kont) : (isSxTruthy((name == "defstyle")) ? makeCekValue(sfDefstyle(args, env), env, kont) : (isSxTruthy((name == "defhandler")) ? makeCekValue(sfDefhandler(args, env), env, kont) : (isSxTruthy((name == "defpage")) ? makeCekValue(sfDefpage(args, env), env, kont) : (isSxTruthy((name == "defquery")) ? makeCekValue(sfDefquery(args, env), env, kont) : (isSxTruthy((name == "defaction")) ? makeCekValue(sfDefaction(args, env), env, kont) : (isSxTruthy((name == "deftype")) ? makeCekValue(sfDeftype(args, env), env, kont) : (isSxTruthy((name == "defeffect")) ? makeCekValue(sfDefeffect(args, env), env, kont) : (isSxTruthy((name == "begin")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "do")) ? stepSfBegin(args, env, kont) : (isSxTruthy((name == "quote")) ? makeCekValue((isSxTruthy(isEmpty(args)) ? NIL : first(args)), env, kont) : (isSxTruthy((name == "quasiquote")) ? makeCekValue(qqExpand(first(args), env), env, kont) : (isSxTruthy((name == "->")) ? stepSfThreadFirst(args, env, kont) : (isSxTruthy((name == "set!")) ? stepSfSet(args, env, kont) : (isSxTruthy((name == "letrec")) ? makeCekValue(sfLetrec(args, env), env, kont) : (isSxTruthy((name == "reset")) ? stepSfReset(args, env, kont) : (isSxTruthy((name == "shift")) ? stepSfShift(args, env, kont) : (isSxTruthy((name == "deref")) ? stepSfDeref(args, env, kont) : (isSxTruthy((name == "scope")) ? stepSfScope(args, env, kont) : (isSxTruthy((name == "provide")) ? stepSfProvide(args, env, kont) : (isSxTruthy((name == "dynamic-wind")) ? makeCekValue(sfDynamicWind(args, env), env, kont) : (isSxTruthy((name == "map")) ? stepHoMap(args, env, kont) : (isSxTruthy((name == "map-indexed")) ? stepHoMapIndexed(args, env, kont) : (isSxTruthy((name == "filter")) ? stepHoFilter(args, env, kont) : (isSxTruthy((name == "reduce")) ? stepHoReduce(args, env, kont) : (isSxTruthy((name == "some")) ? stepHoSome(args, env, kont) : (isSxTruthy((name == "every?")) ? stepHoEvery(args, env, kont) : (isSxTruthy((name == "for-each")) ? stepHoForEach(args, env, kont) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() {
|
||||
var mac = envGet(env, name);
|
||||
return makeCekState(expandMacro(mac, args, env), env, kont);
|
||||
})() : (isSxTruthy((isSxTruthy(renderActiveP()) && isRenderExpr(expr))) ? makeCekValue(renderExpr(expr, env), env, kont) : stepEvalCall(head, args, env, kont))))))))))))))))))))))))))))))))))))))))))));
|
||||
@@ -4582,16 +4591,54 @@ return forEach(function(d) { return cekCall(d, NIL); }, subDisposers); });
|
||||
var stepEvalCall = function(head, args, env, kont) { return makeCekState(head, env, kontPush(makeArgFrame(NIL, [], args, env, args), kont)); };
|
||||
|
||||
// step-ho-map
|
||||
var stepHoMap = function(args, env, kont) { return makeCekValue(hoMap(args, env), env, kont); };
|
||||
var stepHoMap = function(args, env, kont) { return (function() {
|
||||
var f = trampoline(evalExpr(first(args), env));
|
||||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||||
return (isSxTruthy(isEmpty(coll)) ? makeCekValue([], env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeMapFrame(f, rest(coll), [], env), kont)));
|
||||
})(); };
|
||||
|
||||
// step-ho-map-indexed
|
||||
var stepHoMapIndexed = function(args, env, kont) { return (function() {
|
||||
var f = trampoline(evalExpr(first(args), env));
|
||||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||||
return (isSxTruthy(isEmpty(coll)) ? makeCekValue([], env, kont) : continueWithCall(f, [0, first(coll)], env, [], kontPush(makeMapIndexedFrame(f, rest(coll), [], env), kont)));
|
||||
})(); };
|
||||
|
||||
// step-ho-filter
|
||||
var stepHoFilter = function(args, env, kont) { return makeCekValue(hoFilter(args, env), env, kont); };
|
||||
var stepHoFilter = function(args, env, kont) { return (function() {
|
||||
var f = trampoline(evalExpr(first(args), env));
|
||||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||||
return (isSxTruthy(isEmpty(coll)) ? makeCekValue([], env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeFilterFrame(f, rest(coll), [], first(coll), env), kont)));
|
||||
})(); };
|
||||
|
||||
// step-ho-reduce
|
||||
var stepHoReduce = function(args, env, kont) { return makeCekValue(hoReduce(args, env), env, kont); };
|
||||
var stepHoReduce = function(args, env, kont) { return (function() {
|
||||
var f = trampoline(evalExpr(first(args), env));
|
||||
var init = trampoline(evalExpr(nth(args, 1), env));
|
||||
var coll = trampoline(evalExpr(nth(args, 2), env));
|
||||
return (isSxTruthy(isEmpty(coll)) ? makeCekValue(init, env, kont) : continueWithCall(f, [init, first(coll)], env, [], kontPush(makeReduceFrame(f, rest(coll), env), kont)));
|
||||
})(); };
|
||||
|
||||
// step-ho-some
|
||||
var stepHoSome = function(args, env, kont) { return (function() {
|
||||
var f = trampoline(evalExpr(first(args), env));
|
||||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||||
return (isSxTruthy(isEmpty(coll)) ? makeCekValue(false, env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeSomeFrame(f, rest(coll), env), kont)));
|
||||
})(); };
|
||||
|
||||
// step-ho-every
|
||||
var stepHoEvery = function(args, env, kont) { return (function() {
|
||||
var f = trampoline(evalExpr(first(args), env));
|
||||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||||
return (isSxTruthy(isEmpty(coll)) ? makeCekValue(true, env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeEveryFrame(f, rest(coll), env), kont)));
|
||||
})(); };
|
||||
|
||||
// step-ho-for-each
|
||||
var stepHoForEach = function(args, env, kont) { return makeCekValue(hoForEach(args, env), env, kont); };
|
||||
var stepHoForEach = function(args, env, kont) { return (function() {
|
||||
var f = trampoline(evalExpr(first(args), env));
|
||||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||||
return (isSxTruthy(isEmpty(coll)) ? makeCekValue(NIL, env, kont) : continueWithCall(f, [first(coll)], env, [], kontPush(makeForEachFrame(f, rest(coll), env), kont)));
|
||||
})(); };
|
||||
|
||||
// step-continue
|
||||
var stepContinue = function(state) { return (function() {
|
||||
@@ -4741,7 +4788,51 @@ return forEach(function(d) { return cekCall(d, NIL); }, subDisposers); });
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
return (isSxTruthy(isEmpty(remaining)) ? (scopePop(name), makeCekValue(value, fenv, restK)) : makeCekState(first(remaining), fenv, kontPush(makeScopeFrame(name, rest(remaining), fenv), restK)));
|
||||
})() : error((String("Unknown frame type: ") + String(ft))))))))))))))))))));
|
||||
})() : (isSxTruthy((ft == "map")) ? (function() {
|
||||
var f = get(frame, "f");
|
||||
var remaining = get(frame, "remaining");
|
||||
var results = get(frame, "results");
|
||||
var indexed = get(frame, "indexed");
|
||||
var fenv = get(frame, "env");
|
||||
return (function() {
|
||||
var newResults = append(results, [value]);
|
||||
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(newResults, fenv, restK) : (function() {
|
||||
var callArgs = (isSxTruthy(indexed) ? [len(newResults), first(remaining)] : [first(remaining)]);
|
||||
var nextFrame = (isSxTruthy(indexed) ? makeMapIndexedFrame(f, rest(remaining), newResults, fenv) : makeMapFrame(f, rest(remaining), newResults, fenv));
|
||||
return continueWithCall(f, callArgs, fenv, [], kontPush(nextFrame, restK));
|
||||
})());
|
||||
})();
|
||||
})() : (isSxTruthy((ft == "filter")) ? (function() {
|
||||
var f = get(frame, "f");
|
||||
var remaining = get(frame, "remaining");
|
||||
var results = get(frame, "results");
|
||||
var currentItem = get(frame, "current-item");
|
||||
var fenv = get(frame, "env");
|
||||
return (function() {
|
||||
var newResults = (isSxTruthy(value) ? append(results, [currentItem]) : results);
|
||||
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(newResults, fenv, restK) : continueWithCall(f, [first(remaining)], fenv, [], kontPush(makeFilterFrame(f, rest(remaining), newResults, first(remaining), fenv), restK)));
|
||||
})();
|
||||
})() : (isSxTruthy((ft == "reduce")) ? (function() {
|
||||
var f = get(frame, "f");
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(value, fenv, restK) : continueWithCall(f, [value, first(remaining)], fenv, [], kontPush(makeReduceFrame(f, rest(remaining), fenv), restK)));
|
||||
})() : (isSxTruthy((ft == "for-each")) ? (function() {
|
||||
var f = get(frame, "f");
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
return (isSxTruthy(isEmpty(remaining)) ? makeCekValue(NIL, fenv, restK) : continueWithCall(f, [first(remaining)], fenv, [], kontPush(makeForEachFrame(f, rest(remaining), fenv), restK)));
|
||||
})() : (isSxTruthy((ft == "some")) ? (function() {
|
||||
var f = get(frame, "f");
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
return (isSxTruthy(value) ? makeCekValue(value, fenv, restK) : (isSxTruthy(isEmpty(remaining)) ? makeCekValue(false, fenv, restK) : continueWithCall(f, [first(remaining)], fenv, [], kontPush(makeSomeFrame(f, rest(remaining), fenv), restK))));
|
||||
})() : (isSxTruthy((ft == "every")) ? (function() {
|
||||
var f = get(frame, "f");
|
||||
var remaining = get(frame, "remaining");
|
||||
var fenv = get(frame, "env");
|
||||
return (isSxTruthy(!isSxTruthy(value)) ? makeCekValue(false, fenv, restK) : (isSxTruthy(isEmpty(remaining)) ? makeCekValue(true, fenv, restK) : continueWithCall(f, [first(remaining)], fenv, [], kontPush(makeEveryFrame(f, rest(remaining), fenv), restK))));
|
||||
})() : error((String("Unknown frame type: ") + String(ft))))))))))))))))))))))))));
|
||||
})());
|
||||
})(); };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user