core: Stage 3 turn 2b — host IO, ns introspection, thread-binding family

The names turn 2a's leak removal exposed as honestly missing, now proper:

- slurp/spit/flush (host-classified): path-based IO over Janet files; spit
  takes :append; flush flushes *out*. printf prints formatted (no newline)
  over the existing format. file-seq walks paths via two host dir primitives
  through the overlay's tree-seq.
- ns-map / ns-unmap / ns-refers (ctx fns). ns-refers required fixing the
  refer MODEL: refer/use/:refer now map the SOURCE VAR into the target ns
  (the Clojure model) instead of copying its value into a new var — so
  source-ns redefinitions propagate, the :macro flag travels for free, and
  refers are identifiable by the var's home :ns.
- Thread-binding family: with-bindings*/with-bindings, bound-fn*/bound-fn,
  bound?, thread-bound?, get-thread-bindings. The captured binding map is a
  Janet struct keyed by the var tables — the exact frame representation
  var-get reads — so it re-pushes correctly (a phm frame is invisible to
  var lookup).
- load-string and eval interned as VALUES at the api layer (they need the
  loader's compile-or-interpret routing); the eval special form still
  handles direct calls.

Suite 4532 -> 4572 (baseline floor 4540 across timeout variance, clean 86),
conformance 326x3, stdlib battery, all specs+unit (+21 turn-2b rows).
Coverage: missing-portable 27 -> 10 (left: the *in*-model readers, the
with-local-vars/with-precision/extenders tail).
This commit is contained in:
Yogthos 2026-06-10 12:53:47 -04:00
parent a75a26860b
commit d61c86a068
8 changed files with 197 additions and 34 deletions

View file

@ -73,6 +73,12 @@
[] (partition 2 bindings))]
`(with-redefs-fn (hash-map ~@pairs) (fn [] ~@body))))
(defmacro with-bindings [binding-map & body]
`(with-bindings* ~binding-map (fn [] ~@body)))
(defmacro bound-fn [& fntail]
`(bound-fn* (fn ~@fntail)))
(defmacro defonce [name expr]
`(let [v# (resolve (quote ~name))]
(if (and v# (some? (var-get v#)))