Fix named-let set! scoping + convert test to deftest
Named let's sf-named-let used call-lambda which returns a thunk that was never trampolined. The body executed in a disconnected env, so set! couldn't reach outer let bindings. Fixed by using cek-call which evaluates through the full CEK machine with proper env chain. Also converted test-named-let-set.sx from assert= (uses broken = for lists) to deftest/assert-equal (uses deep equal?). JS standard: 1120/1120, JS full: 1600/1600. Zero failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,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-03-31T10:16:31Z";
|
var SX_VERSION = "2026-03-31T21:28:15Z";
|
||||||
|
|
||||||
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); }
|
||||||
@@ -422,7 +422,7 @@
|
|||||||
PRIMITIVES["len"] = function(c) { return Array.isArray(c) ? c.length : typeof c === "string" ? c.length : Object.keys(c).length; };
|
PRIMITIVES["len"] = function(c) { return Array.isArray(c) ? c.length : typeof c === "string" ? c.length : Object.keys(c).length; };
|
||||||
PRIMITIVES["first"] = function(c) { return c && c.length > 0 ? c[0] : NIL; };
|
PRIMITIVES["first"] = function(c) { return c && c.length > 0 ? c[0] : NIL; };
|
||||||
PRIMITIVES["last"] = function(c) { return c && c.length > 0 ? c[c.length - 1] : NIL; };
|
PRIMITIVES["last"] = function(c) { return c && c.length > 0 ? c[c.length - 1] : NIL; };
|
||||||
PRIMITIVES["rest"] = function(c) { if (c && typeof c.slice !== "function") { console.error("[sx-debug] rest called on non-sliceable:", typeof c, c, new Error().stack); return []; } return c ? c.slice(1) : []; };
|
PRIMITIVES["rest"] = function(c) { if (!c || c._nil) return []; if (typeof c.slice !== "function") return []; return c.slice(1); };
|
||||||
PRIMITIVES["nth"] = function(c, n) { return c && n >= 0 && n < c.length ? c[n] : NIL; };
|
PRIMITIVES["nth"] = function(c, n) { return c && n >= 0 && n < c.length ? c[n] : NIL; };
|
||||||
PRIMITIVES["cons"] = function(x, c) { return [x].concat(c || []); };
|
PRIMITIVES["cons"] = function(x, c) { return [x].concat(c || []); };
|
||||||
PRIMITIVES["append"] = function(c, x) { return (c || []).concat(Array.isArray(x) ? x : [x]); };
|
PRIMITIVES["append"] = function(c, x) { return (c || []).concat(Array.isArray(x) ? x : [x]); };
|
||||||
@@ -1366,7 +1366,7 @@ return append_b(inits, nth(binding, 1)); }, bindings) : reduce(function(acc, pai
|
|||||||
envBind(lambdaClosure(loopFn), loopName, loopFn);
|
envBind(lambdaClosure(loopFn), loopName, loopFn);
|
||||||
return (function() {
|
return (function() {
|
||||||
var initVals = map(function(e) { return trampoline(evalExpr(e, env)); }, inits);
|
var initVals = map(function(e) { return trampoline(evalExpr(e, env)); }, inits);
|
||||||
return callLambda(loopFn, initVals, env);
|
return cekCall(loopFn, initVals);
|
||||||
})();
|
})();
|
||||||
})();
|
})();
|
||||||
})(); };
|
})(); };
|
||||||
@@ -6683,7 +6683,7 @@ PRIMITIVES["batch"] = batch;
|
|||||||
PRIMITIVES["notify-subscribers"] = notifySubscribers;
|
PRIMITIVES["notify-subscribers"] = notifySubscribers;
|
||||||
|
|
||||||
// flush-subscribers
|
// flush-subscribers
|
||||||
var flushSubscribers = function(s) { return forEach(function(sub) { return sub(); }, signalSubscribers(s)); };
|
var flushSubscribers = function(s) { return forEach(function(sub) { return cekCall(sub, NIL); }, signalSubscribers(s)); };
|
||||||
PRIMITIVES["flush-subscribers"] = flushSubscribers;
|
PRIMITIVES["flush-subscribers"] = flushSubscribers;
|
||||||
|
|
||||||
// dispose-computed
|
// dispose-computed
|
||||||
|
|||||||
@@ -544,7 +544,7 @@
|
|||||||
(env-bind! (lambda-closure loop-fn) loop-name loop-fn)
|
(env-bind! (lambda-closure loop-fn) loop-name loop-fn)
|
||||||
(let
|
(let
|
||||||
((init-vals (map (fn (e) (trampoline (eval-expr e env))) inits)))
|
((init-vals (map (fn (e) (trampoline (eval-expr e env))) inits)))
|
||||||
(call-lambda loop-fn init-vals env))))))
|
(cek-call loop-fn init-vals))))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
sf-lambda
|
sf-lambda
|
||||||
|
|||||||
@@ -1,52 +1,38 @@
|
|||||||
(assert=
|
(defsuite "named-let-set"
|
||||||
(let ((x 0)) (let loop () (when (< x 5) (set! x (+ x 1)) (loop))) x)
|
(deftest "set! counter in named let loop"
|
||||||
5
|
(assert-equal 5
|
||||||
"set! counter in named let loop")
|
(let ((x 0)) (let loop () (when (< x 5) (set! x (+ x 1)) (loop))) x)))
|
||||||
|
|
||||||
(assert=
|
(deftest "set! list accumulator in named let with param"
|
||||||
(let
|
(assert-equal (list 0 1 2)
|
||||||
((acc (list)))
|
(let ((acc (list)))
|
||||||
(let
|
(let loop ((i 0))
|
||||||
loop
|
|
||||||
((i 0))
|
|
||||||
(when (< i 3) (set! acc (append acc (list i))) (loop (+ i 1))))
|
(when (< i 3) (set! acc (append acc (list i))) (loop (+ i 1))))
|
||||||
acc)
|
acc)))
|
||||||
(list 0 1 2)
|
|
||||||
"set! list accumulator in named let with param")
|
|
||||||
|
|
||||||
(assert=
|
(deftest "append! + set! counter in named let"
|
||||||
(let
|
(assert-equal (list 0 1 2)
|
||||||
((acc (list)) (i 0))
|
(let ((acc (list)) (i 0))
|
||||||
(let loop () (when (< i 3) (append! acc i) (set! i (+ i 1)) (loop)))
|
(let loop () (when (< i 3) (append! acc i) (set! i (+ i 1)) (loop)))
|
||||||
acc)
|
acc)))
|
||||||
(list 0 1 2)
|
|
||||||
"append! + set! counter in named let")
|
|
||||||
|
|
||||||
(assert=
|
(deftest "set! sum in named let loop (1..10)"
|
||||||
(let
|
(assert-equal 55
|
||||||
((sum 0))
|
(let ((sum 0))
|
||||||
(let
|
(let loop ((i 1))
|
||||||
loop
|
|
||||||
((i 1))
|
|
||||||
(when (<= i 10) (set! sum (+ sum i)) (loop (+ i 1))))
|
(when (<= i 10) (set! sum (+ sum i)) (loop (+ i 1))))
|
||||||
sum)
|
sum)))
|
||||||
55
|
|
||||||
"set! sum in named let loop (1..10)")
|
|
||||||
|
|
||||||
(assert=
|
(deftest "set! string accumulator in named let"
|
||||||
(let
|
(assert-equal "012"
|
||||||
((result ""))
|
(let ((result ""))
|
||||||
(let
|
(let loop ((i 0))
|
||||||
loop
|
|
||||||
((i 0))
|
|
||||||
(when (< i 3) (set! result (str result (str i))) (loop (+ i 1))))
|
(when (< i 3) (set! result (str result (str i))) (loop (+ i 1))))
|
||||||
result)
|
result)))
|
||||||
"012"
|
|
||||||
"set! string accumulator in named let")
|
|
||||||
|
|
||||||
(assert= (let ((x 0)) (set! x 42) x) 42 "set! in plain let (baseline)")
|
(deftest "set! in plain let (baseline)"
|
||||||
|
(assert-equal 42 (let ((x 0)) (set! x 42) x)))
|
||||||
|
|
||||||
(assert=
|
(deftest "named let without set! (baseline)"
|
||||||
(let loop ((i 0) (acc 0)) (if (< i 5) (loop (+ i 1) (+ acc i)) acc))
|
(assert-equal 10
|
||||||
10
|
(let loop ((i 0) (acc 0)) (if (< i 5) (loop (+ i 1) (+ acc i)) acc)))))
|
||||||
"named let without set! (baseline)")
|
|
||||||
|
|||||||
Reference in New Issue
Block a user