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).
39 lines
2.8 KiB
Text
39 lines
2.8 KiB
Text
# Specification: Stage 3 turn 2b — host-classified IO fns, ns introspection,
|
|
# the thread-binding family, and load-string/eval as values. These were
|
|
# previously either missing or silently leaked from Janet's root environment.
|
|
(use ../support/harness)
|
|
|
|
(defspec "io / slurp, spit, printf, flush (host-classified)"
|
|
["slurp returns string" "true" "(string? (slurp \"project.janet\"))"]
|
|
["slurp content" "true" "(do (require (quote [clojure.string :as s])) (s/includes? (slurp \"project.janet\") \"jolt\"))"]
|
|
["spit + slurp round" "\"hello\"" "(do (spit \"/tmp/jolt-spit-test.txt\" \"hello\") (slurp \"/tmp/jolt-spit-test.txt\"))"]
|
|
["spit append" "\"ab\"" "(do (spit \"/tmp/jolt-spit-test.txt\" \"a\") (spit \"/tmp/jolt-spit-test.txt\" \"b\" :append true) (slurp \"/tmp/jolt-spit-test.txt\"))"]
|
|
["printf formats" "\"x=1 y=a\"" "(with-out-str (printf \"x=%d y=%s\" 1 \"a\"))"]
|
|
["printf no newline" "false" "(do (require (quote [clojure.string :as s])) (s/includes? (with-out-str (printf \"%d\" 1)) \"\\n\"))"]
|
|
["flush returns nil" "nil" "(flush)"]
|
|
["file-seq finds files" "true" "(do (require (quote [clojure.string :as s])) (boolean (some (fn [p] (s/ends-with? p \"project.janet\")) (file-seq \".\"))))"])
|
|
|
|
(defspec "ns / ns-map, ns-unmap, ns-refers"
|
|
["ns-map has var" "true" "(do (def nmv 1) (some? (get (ns-map (quote user)) (quote nmv))))"]
|
|
["ns-unmap removes" "nil" "(do (def nuv 1) (ns-unmap (quote user) (quote nuv)) (resolve (quote nuv)))"]
|
|
["ns-refers sees refer" "true" "(do (require (quote clojure.string)) (refer (quote clojure.string)) (some? (get (ns-refers (quote user)) (quote join))))"])
|
|
|
|
(defspec "vars / thread-binding family"
|
|
["bound? on def" "true" "(do (def bvv 1) (bound? (var bvv)))"]
|
|
["with-bindings* binds" "5"
|
|
"(do (def ^:dynamic dynv 1) (with-bindings* (array-map (var dynv) 5) (fn [] dynv)))"]
|
|
["with-bindings* restores" "1"
|
|
"(do (def ^:dynamic dynw 1) (with-bindings* (array-map (var dynw) 5) (fn [] nil)) dynw)"]
|
|
["with-bindings macro" "7"
|
|
"(do (def ^:dynamic dynx 1) (with-bindings (array-map (var dynx) 7) dynx))"]
|
|
["thread-bound? inside" "[true false]"
|
|
"(do (def ^:dynamic dyny 1) [(with-bindings* (array-map (var dyny) 2) (fn [] (thread-bound? (var dyny)))) (thread-bound? (var dyny))])"]
|
|
["bound-fn* conveys" "9"
|
|
"(do (def ^:dynamic dynz 1) (def f (with-bindings* (array-map (var dynz) 9) (fn [] (bound-fn* (fn [] dynz))))) (f))"]
|
|
["get-thread-bindings" "3"
|
|
"(do (def ^:dynamic dyng 1) (with-bindings* (array-map (var dyng) 3) (fn [] (get (get-thread-bindings) (var dyng)))))"])
|
|
|
|
(defspec "eval & load-string as values"
|
|
["load-string evals all" "3" "(load-string \"(def lsv 1) (+ lsv 2)\")"]
|
|
["eval as value" "[2 3]" "(mapv eval [(quote (+ 1 1)) (quote (+ 1 2))])"]
|
|
["eval special still works" "3" "(eval (quote (+ 1 2)))"])
|