Step 7a complete: ->> |> as-> pipe operators + transpiler fixes

Three new threading operators in evaluator.sx:
- ->> (thread-last): inserts value as last arg
- |> (pipe): alias for ->> (F#/OCaml convention)
- as-> (thread-anywhere): binds value to named variable

  (->> 10 (- 3))           ;; => -7  (thread-last: (- 3 10))
  (-> 10 (- 3))            ;; => 7   (thread-first: (- 10 3))
  (->> 1 (list 2 3))       ;; => (2 3 1)
  (as-> 5 x (+ x 1) (* x 2)) ;; => 12

Two transpiler bugs fixed:
1. Non-recursive functions (let without rec) weren't chained as `and`
   in the let rec block — became local bindings inside previous function
2. CekFrame "extra" field wasn't in the cf_extra key mapping — mode
   was always Nil, making thread-last fall through to thread-first

Also: added missing step-sf-case definition to evaluator.

2644 tests pass, zero regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 14:29:40 +00:00
parent f814193c94
commit cd414b96a7
2 changed files with 13 additions and 7 deletions

View File

@@ -111,7 +111,7 @@ and make_case_frame match_val remaining env =
(* make-thread-frame *)
and make_thread_frame remaining env mode name =
(CekFrame { cf_type = "thread"; cf_env = env; cf_name = name; cf_body = Nil; cf_remaining = remaining; cf_f = Nil; cf_args = Nil; cf_results = Nil; cf_extra = Nil; cf_extra2 = Nil })
(CekFrame { cf_type = "thread"; cf_env = env; cf_name = name; cf_body = Nil; cf_remaining = remaining; cf_f = Nil; cf_args = Nil; cf_results = Nil; cf_extra = mode; cf_extra2 = Nil })
(* thread-insert-arg *)
and thread_insert_arg form value fenv =

View File

@@ -562,6 +562,8 @@
(ef "update-fn")
(some (fn (k) (= k "head-name")) items)
(ef "head-name")
(some (fn (k) (= k "extra")) items)
(ef "extra")
:else "Nil")
"; cf_extra2 = "
(cond
@@ -1843,16 +1845,20 @@
(if
(and (number? nl-idx) (>= nl-idx 0))
(let
((before (slice p 0 (+ nl-idx 1)))
((before (slice p 0 nl-idx))
(after (slice p (+ nl-idx 1))))
(if
(cond
(starts-with? after "let rec ")
(str before "and " (slice after 8))
p))
(if
(str before "\nand " (slice after 8))
(starts-with? after "let ")
(str before "\nand " (slice after 4))
:else p))
(cond
(starts-with? p "let rec ")
(str "and " (slice p 8))
p))))
(starts-with? p "let ")
(str "and " (slice p 4))
:else p))))
(rest parts))))))))
(define