Step 10c: fix bind subscriber re-evaluation — track names not frames

Root cause: context called inside lambdas (e.g. swap!) went through
nested cek_run with empty kont, so provide frames weren't found and
never tracked to *bind-tracking*.

Three changes in evaluator.sx:
- step-sf-context: track context names (not frames) to *bind-tracking*
  — names work across cek_run boundaries via scope-peek fallback
- bind continue: resolve tracked names to frames via kont-find-provide
  on rest-k before registering subscribers
- subscriber: use empty kont instead of kont-extract-provides — old
  approach created provide frames whose continue handlers called
  scope-pop!, corrupting the scope stack

2752/2768 OCaml tests pass (all 7 bind subscriber tests fixed).
32/32 WASM native tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 11:05:17 +00:00
parent a965731a33
commit 44b520a9e9
6 changed files with 5366 additions and 8054 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,7 @@
(define-library (sx highlight) (define-library
(sx highlight)
(export (export
sx-specials sx-specials
sx-special? sx-special?
@@ -16,7 +17,6 @@
highlight-sx highlight-sx
highlight) highlight)
(begin (begin
(define (define
sx-specials sx-specials
(list (list
@@ -54,16 +54,32 @@
"for-each" "for-each"
"&key" "&key"
"&rest" "&rest"
"set!")) "set!"
"satisfies?"
"match"
"let-match"
"define-protocol"
"implement"
"->>"
"|>"
"as->"
"define-library"
"import"
"perform"
"guard"
"call/cc"
"raise"
"define-syntax"
"syntax-rules"
"make-parameter"
"parameterize"))
(define sx-special? (fn (s) (some (fn (x) (= x s)) sx-specials))) (define sx-special? (fn (s) (some (fn (x) (= x s)) sx-specials)))
(define hl-digit? (fn (c) (and (>= c "0") (<= c "9")))) (define hl-digit? (fn (c) (and (>= c "0") (<= c "9"))))
(define (define
hl-alpha? hl-alpha?
(fn (c) (or (and (>= c "a") (<= c "z")) (and (>= c "A") (<= c "Z"))))) (fn
(c)
(or (and (>= c "a") (<= c "z")) (and (>= c "A") (<= c "Z")))))
(define (define
hl-sym-char? hl-sym-char?
(fn (fn
@@ -83,11 +99,10 @@
(= c "=") (= c "=")
(= c "&") (= c "&")
(= c ".")))) (= c "."))))
(define
(define hl-ws? (fn (c) (or (= c " ") (= c "\n") (= c "\t") (= c "\r")))) hl-ws?
(fn (c) (or (= c " ") (= c "\n") (= c "\t") (= c "\r"))))
(define hl-escape (fn (s) s)) (define hl-escape (fn (s) s))
(define (define
hl-span hl-span
(fn (fn
@@ -96,7 +111,6 @@
(= class "") (= class "")
(list (quote span) text) (list (quote span) text)
(list (quote span) (make-keyword "class") class text)))) (list (quote span) (make-keyword "class") class text))))
(define (define
tokenize-sx tokenize-sx
(fn (fn
@@ -196,7 +210,8 @@
tokens tokens
(append (append
tokens tokens
(list (list "component" (substring code start i)))))) (list
(list "component" (substring code start i))))))
(if (if
(or (or
(= c "(") (= c "(")
@@ -229,7 +244,8 @@
tokens tokens
(append (append
tokens tokens
(list (list "number" (substring code start i)))))) (list
(list "number" (substring code start i))))))
(if (if
(hl-sym-char? c) (hl-sym-char? c)
(let (let
@@ -240,7 +256,8 @@
(when (when
(and (and
(< i len) (< i len)
(hl-sym-char? (substring code i (+ i 1)))) (hl-sym-char?
(substring code i (+ i 1))))
(set! i (+ i 1)) (set! i (+ i 1))
(scan))) (scan)))
(let (let
@@ -284,7 +301,8 @@
tokens tokens
(append (append
tokens tokens
(list (list "ws" (substring code start i)))))) (list
(list "ws" (substring code start i))))))
(do (do
(set! (set!
tokens tokens
@@ -292,9 +310,7 @@
(set! i (+ i 1)))))))))))) (set! i (+ i 1))))))))))))
(loop))) (loop)))
tokens))) tokens)))
(define sx-token-classes {:boolean "text-orange-600" :component "text-rose-600 font-semibold" :number "text-amber-700" :string "text-emerald-700" :special "text-sky-700 font-semibold" :paren "text-stone-400" :keyword "text-violet-600" :comment "text-stone-400 italic"}) (define sx-token-classes {:boolean "text-orange-600" :component "text-rose-600 font-semibold" :number "text-amber-700" :string "text-emerald-700" :special "text-sky-700 font-semibold" :paren "text-stone-400" :keyword "text-violet-600" :comment "text-stone-400 italic"})
(define (define
render-sx-tokens render-sx-tokens
(fn (fn
@@ -306,20 +322,19 @@
((cls (or (dict-get sx-token-classes (first tok)) ""))) ((cls (or (dict-get sx-token-classes (first tok)) "")))
(hl-span cls (nth tok 1)))) (hl-span cls (nth tok 1))))
tokens))) tokens)))
(define highlight-sx (fn (code) (-> code tokenize-sx render-sx-tokens)))
(define highlight-sx (fn (code) (render-sx-tokens (tokenize-sx code))))
(define (define
highlight highlight
(fn (fn
(code lang) (code lang)
(if (if
(or (= lang "lisp") (= lang "sx") (= lang "sexp") (= lang "scheme")) (or
(= lang "lisp")
(= lang "sx")
(= lang "sexp")
(= lang "scheme"))
(highlight-sx code) (highlight-sx code)
(list (quote code) code)))) (list (quote code) code)))))) ;; end define-library
)) ;; end define-library
;; Re-export to global namespace for backward compatibility ;; Re-export to global namespace for backward compatibility
(import (sx highlight)) (import (sx highlight))

File diff suppressed because one or more lines are too long

View File

@@ -1792,7 +1792,7 @@
blake2_js_for_wasm_create: blake2_js_for_wasm_create}; blake2_js_for_wasm_create: blake2_js_for_wasm_create};
} }
(globalThis)) (globalThis))
({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["sx-418217b8",[2]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,4]],["dune__exe__Sx_browser-0734e8ba",[2,3,5]],["std_exit-10fb8830",[2]],["start-f5d3f095",0]],"generated":(b=>{var ({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["sx-b2cc3269",[2]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,4]],["dune__exe__Sx_browser-9b135b3a",[2,3,5]],["std_exit-10fb8830",[2]],["start-f5d3f095",0]],"generated":(b=>{var
c=b,a=b?.module?.export||b;return{"env":{"caml_ba_kind_of_typed_array":()=>{throw new c=b,a=b?.module?.export||b;return{"env":{"caml_ba_kind_of_typed_array":()=>{throw new
Error("caml_ba_kind_of_typed_array not implemented")},"caml_exn_with_js_backtrace":()=>{throw new Error("caml_ba_kind_of_typed_array not implemented")},"caml_exn_with_js_backtrace":()=>{throw new
Error("caml_exn_with_js_backtrace not implemented")},"caml_int64_create_lo_mi_hi":()=>{throw new Error("caml_exn_with_js_backtrace not implemented")},"caml_int64_create_lo_mi_hi":()=>{throw new

View File

@@ -2745,10 +2745,10 @@
nil)) nil))
(frame (kont-find-provide kont name))) (frame (kont-find-provide kont name)))
(when (when
(and frame *bind-tracking*) *bind-tracking*
(when (when
(not (contains? *bind-tracking* frame)) (not (contains? *bind-tracking* name))
(append! *bind-tracking* frame))) (append! *bind-tracking* name)))
(make-cek-value (make-cek-value
(if (if
frame frame
@@ -3597,14 +3597,18 @@
(prev (get frame "prev-tracking"))) (prev (get frame "prev-tracking")))
(set! *bind-tracking* prev) (set! *bind-tracking* prev)
(let (let
((subscriber (fn (fire-kont) (let ((provide-kont (kont-extract-provides fire-kont))) (cek-run (make-cek-state body fenv provide-kont)))))) ((subscriber (fn (fire-kont) (cek-run (make-cek-state body fenv (list))))))
(for-each (for-each
(fn (fn
(pf) (name)
(let
((pf (kont-find-provide rest-k name)))
(when
pf
(dict-set! (dict-set!
pf pf
"subscribers" "subscribers"
(append (get pf "subscribers") (list subscriber)))) (append (get pf "subscribers") (list subscriber))))))
tracked)) tracked))
(make-cek-value value fenv rest-k))) (make-cek-value value fenv rest-k)))
("provide-set" ("provide-set"