Clean up codebase: rename stdlib layer, strip porting residue, fix tooling
Rename src/jolt -> stdlib (the runtime-loaded layer; jolt-core stays the seed-baked layer) and update the loader / emit-image / doc paths. Drop dead code: the spike/ experiments, the duplicate clojuredocs-export.edn (json moves to tools/), the Janet-era jolt.http binding, and the orphaned persistent_vector.clj whose ns/path didn't even match. Strip porting residue from comments and docstrings across host/chez, jolt-core, stdlib, tests, and docs: internal issue ids, "Phase N" markers, and the "vs Janet" historical exposition, leaving present-tense descriptions and the real JVM-Clojure semantic contrasts. Same pass over the corpus suite labels. The seed is unchanged (docstrings/comments aren't emitted), so the self-host fixpoint and corpus are untouched. Port tools/spec_coverage.py off the dead janet probe to bin/joltc and regenerate coverage.md; drop the dead :host/janet rule from certify.clj and regenerate the conformance profile. Add docs/host-interop.md (the JVM shims and how to register your own host class from a library) and a writing-style note in CLAUDE.md. Stabilize the four racy concurrency corpus cases (future-cancel and agent send/send-off): give the future a sleeping body and the agent a slow action, so cancel reliably catches an in-flight future and deref reliably reads the pre-update snapshot. They certify deterministically now, so drop their :flaky allowlist entries and the orphaned legend.
This commit is contained in:
parent
c18f8087f0
commit
33eff7c7d8
112 changed files with 970 additions and 1621 deletions
|
|
@ -25,7 +25,7 @@
|
|||
(throw (str "zero? requires a number, got: " x)))))
|
||||
|
||||
;; pos? checks number? explicitly: this tier is recompiled by the staged pass,
|
||||
;; where a bare (> x 0) emits the native janet op that happily orders strings
|
||||
;; where a bare (> x 0) emits the native op that happily orders strings
|
||||
;; (the documented native-ops relaxation) — the guard keeps Clojure's throw.
|
||||
(def pos?
|
||||
(fn* pos? [x]
|
||||
|
|
@ -111,7 +111,7 @@
|
|||
;; of 00-syntax has loaded, so using them here is fine.
|
||||
(defmacro ns [nm & clauses]
|
||||
;; ^{:map} metadata on the ns name reads as a (with-meta sym {...}) form, not an
|
||||
;; annotated symbol (jolt-8w2). Real libraries put :author/:doc there
|
||||
;; annotated symbol. Real libraries put :author/:doc there
|
||||
;; (clojure.tools.logging), so unwrap to the bare symbol; jolt does not track
|
||||
;; namespace metadata, so the map is dropped.
|
||||
(let [nm (if (and (seq? nm) (= 'with-meta (first nm))) (second nm) nm)
|
||||
|
|
@ -152,7 +152,7 @@
|
|||
|
||||
;; Forward declaration interns unbound vars (Clojure semantics). The interpreter
|
||||
;; resolves forward refs lazily either way, but the COMPILER classifies globals at
|
||||
;; compile time: without the var, a declared name that collides with a Janet root
|
||||
;; compile time: without the var, a declared name that collides with a host root
|
||||
;; binding (parse, hash, …) would compile to the host fn instead of the var.
|
||||
(defmacro declare [& syms]
|
||||
`(do ~@(map (fn* [s] `(def ~s)) syms)))
|
||||
|
|
@ -309,8 +309,8 @@
|
|||
(if (seq ps)
|
||||
(if (symbol? (first ps))
|
||||
(go (next ps) (conj nps (first ps)) lets)
|
||||
;; bare (gensym) here is Janet's (a Janet symbol the destructurer
|
||||
;; rejects); round-trip through str for a jolt symbol.
|
||||
;; a bare (gensym) returns a host symbol the destructurer rejects;
|
||||
;; round-trip through str for a jolt symbol.
|
||||
(let [g (symbol (str (gensym)))]
|
||||
(go (next ps) (conj nps g) (conj (conj lets (first ps)) g))))
|
||||
[nps lets]))
|
||||
|
|
@ -348,18 +348,18 @@
|
|||
body (if (and (seq body) (map? (first body)) (not (symbol? (first body))))
|
||||
(rest body) body)
|
||||
;; ^{:map} metadata on the name reads as a (with-meta sym …) form, not an
|
||||
;; annotated symbol (jolt-8w2). def attaches the metadata, but fn needs a
|
||||
;; annotated symbol. def attaches the metadata, but fn needs a
|
||||
;; bare symbol, so unwrap it for the fn name.
|
||||
fn-only-name (if (symbol? fn-name) fn-name (first (rest fn-name)))]
|
||||
;; pass the name through to fn: the compiled fn's janet name carries it,
|
||||
;; so stack traces read app.deep/level3 instead of a gensym (jolt-2o7.1)
|
||||
;; pass the name through to fn: the compiled fn's host name carries it,
|
||||
;; so stack traces read app.deep/level3 instead of a gensym
|
||||
`(def ~fn-name (fn ~fn-only-name ~@body))))
|
||||
|
||||
;; Jolt doesn't enforce privacy, so defn- is just defn (matching how Clojure's own
|
||||
;; defn- delegates to defn with :private metadata).
|
||||
(defmacro defn- [fn-name & body] `(defn ~fn-name ~@body))
|
||||
|
||||
;; A fresh jolt symbol inside a macro body (a bare (gensym) returns a Janet symbol
|
||||
;; A fresh jolt symbol inside a macro body (a bare (gensym) returns a host symbol
|
||||
;; the destructurer rejects). This defn compiles fine: by the time a tier triggers
|
||||
;; the analyzer build the kernel is in place (the build is gated until then).
|
||||
(defn- fresh-sym [] (symbol (str (gensym))))
|
||||
|
|
@ -422,9 +422,9 @@
|
|||
;; Per binding group: :when wraps the inner form in (if test (list inner) []) so
|
||||
;; mapcat drops it when false; :let wraps it in a let*; :while wraps the coll in
|
||||
;; take-while. The last group with no modifiers is a plain map (no flatten needed).
|
||||
;; Faithful port of the prior Janet macro (single body expr). The body uses only
|
||||
;; kernel/seed fns so it runs at analyzer-build time. `fn` (not fn*) carries the
|
||||
;; binding so destructuring forms work.
|
||||
;; Single body expr. The body uses only kernel/seed fns so it runs at
|
||||
;; analyzer-build time. `fn` (not fn*) carries the binding so destructuring forms
|
||||
;; work.
|
||||
(defmacro for [bindings body]
|
||||
(let [scan (fn scan [bvec i bind coll mods]
|
||||
(if (and (< i (count bvec)) (keyword? (nth bvec i)))
|
||||
|
|
@ -471,9 +471,9 @@
|
|||
(build 0 (parse-groups bindings 0 []))
|
||||
body)))
|
||||
|
||||
;; doseq runs body for side effects across the bindings, returning nil. Same
|
||||
;; shortcut as the prior Janet macro: realize a `for` comprehension with count
|
||||
;; (for handles :when/:let/:while and multiple bindings).
|
||||
;; doseq runs body for side effects across the bindings, returning nil. Realizes
|
||||
;; a `for` comprehension with count (for handles :when/:let/:while and multiple
|
||||
;; bindings).
|
||||
(defmacro doseq [bindings & body]
|
||||
`(do (count (for ~bindings (do ~@body nil))) nil))
|
||||
|
||||
|
|
@ -489,7 +489,7 @@
|
|||
;; lazy-seq / lazy-cat live here (not 30-macros) because the seq/coll tiers use
|
||||
;; them and compile-as-they-load: the macro must be registered before those tiers
|
||||
;; or (lazy-seq …) compiles to a call of the macro-as-function and leaks its
|
||||
;; expansion at runtime (jolt-r81). They use only seed fns (make-lazy-seq/
|
||||
;; expansion at runtime. They use only seed fns (make-lazy-seq/
|
||||
;; coll->cells/concat) + map, all available from the start.
|
||||
;; lazy-seq defers its body: make-lazy-seq holds a thunk that realizes the body
|
||||
;; to cells when forced. lazy-cat wraps each coll in a lazy-seq and concats.
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@
|
|||
;; mode these self-host through the now-built analyzer (interpreted otherwise).
|
||||
;;
|
||||
;; Migration rule for adding fns here: the fn must (1) NOT be in
|
||||
;; compiler/core-renames (that map emits core-X Janet symbols directly), (2) have
|
||||
;; no internal Janet callers of its core-X binding, and (3) NOT be used by the
|
||||
;; compiler/core-renames (that map emits core-X symbols directly), (2) have
|
||||
;; no internal callers of its core-X binding, and (3) NOT be used by the
|
||||
;; self-hosted compiler (jolt-core/jolt/*.clj). Compiler-facing structural fns go
|
||||
;; in the kernel tier (00-kernel) instead — see its header.
|
||||
|
||||
;; Volatiles (moved up from 20-coll: this tier's transducers use them, and the
|
||||
;; analyzer now ERRORS on unresolved forward references — jolt-2o7.3). The
|
||||
;; constructor (volatile!) stays native; these are pure over ref-put!/get.
|
||||
;; Volatiles (this tier's transducers use them, and the analyzer ERRORS on
|
||||
;; unresolved forward references). The constructor (volatile!) stays native;
|
||||
;; these are pure over ref-put!/get.
|
||||
(defn vreset! [vol newval]
|
||||
(jolt.host/ref-put! vol :val newval) newval)
|
||||
(defn vswap! [vol f & args]
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
(defn fnext [coll] (first (next coll)))
|
||||
(defn nnext [coll] (next (next coll)))
|
||||
|
||||
;; Canonical Clojure defs: pure first/next/loop/recur, no Janet realize-for-iteration.
|
||||
;; Canonical Clojure defs: pure first/next/loop/recur.
|
||||
(defn last [s]
|
||||
(if (next s) (recur (next s)) (first s)))
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
;; redefinable. Loaded after the seq tier; self-hosted in compile mode.
|
||||
;;
|
||||
;; Same migration rule as the seq tier (see 10-seq.clj): not in core-renames, no
|
||||
;; internal Janet callers, not used by the self-hosted compiler.
|
||||
;; internal callers, not used by the self-hosted compiler.
|
||||
|
||||
;; Tiny leaves first — fns below in this tier (and 25-sorted) use them.
|
||||
(defn some? [x] (not (nil? x)))
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
;; overlay versions cost an extra call layer per element (seq-pipe bench 4x).
|
||||
|
||||
;; Variadic bit ops — canonical Clojure arities folding the binary host op
|
||||
;; (__bit-* seams). 2-arg call sites still compile to the native janet op via
|
||||
;; (__bit-* seams). 2-arg call sites still compile to the native op via
|
||||
;; the backend's native-ops table, so the binary fast path is unchanged.
|
||||
(defn bit-and
|
||||
([x y] (__bit-and x y))
|
||||
|
|
@ -87,8 +87,8 @@
|
|||
;; Distinct keys are recorded in a side vector so the buckets can be frozen in
|
||||
;; place (no second map rebuild). A bucket's FIRST element is stored as a cheap
|
||||
;; persistent [x]; only the second element promotes it to a transient — so an
|
||||
;; all-singletons grouping pays no transient alloc and matches the old cost,
|
||||
;; while any bucket that actually grows rides the O(1) push.
|
||||
;; all-singletons grouping pays no transient alloc, while any bucket that
|
||||
;; actually grows rides the O(1) push.
|
||||
(defn group-by [f coll]
|
||||
(let [tm (transient {})
|
||||
ks (reduce (fn [ks x]
|
||||
|
|
@ -355,7 +355,7 @@
|
|||
(make-hierarchy) (partition 2 deriv-seq))
|
||||
h))))
|
||||
|
||||
;; --- Stage 3 tier shrink: pure-over-core leaves moved off the host primitives ----
|
||||
;; --- pure-over-core leaves expressed off the host primitives -----------------
|
||||
|
||||
;; Representation predicates over the overlay's own predicates.
|
||||
(defn sequential? [x] (or (vector? x) (seq? x)))
|
||||
|
|
@ -364,7 +364,7 @@
|
|||
(or (vector? x) (map? x) (set? x) (list? x) (string? x)))
|
||||
(defn indexed? [x] (vector? x))
|
||||
;; sorted? is defined by the next tier (25-sorted) — declared here so this
|
||||
;; tier compiles (forward references are analysis errors now, jolt-2o7.3).
|
||||
;; tier compiles (forward references are analysis errors).
|
||||
(declare sorted?)
|
||||
|
||||
(defn reversible? [x] (or (vector? x) (sorted? x)))
|
||||
|
|
@ -377,7 +377,7 @@
|
|||
(defn infinite? [x] (and (number? x) (or (= x ##Inf) (= x ##-Inf))))
|
||||
|
||||
;; qualified-/simple- keyword?/symbol? moved above qualified-ident? (forward
|
||||
;; references are analysis errors now — jolt-2o7.3).
|
||||
;; references are analysis errors).
|
||||
|
||||
|
||||
;; realized?: defined on the pending types only (delay/lazy-seq/future read
|
||||
|
|
@ -453,7 +453,7 @@
|
|||
(defn println-str [& xs] (__with-out-str (fn* [] (apply println xs))))
|
||||
(defn prn-str [& xs] (__with-out-str (fn* [] (apply prn xs))))
|
||||
|
||||
;; --- Phase 2 leaf batch 4 (jolt-ded): over the rand / sort host seams --------
|
||||
;; --- leaves over the rand / sort host seams ----------------------------------
|
||||
|
||||
;; Canonical truncation toward zero via int (the kernel fn floored, which is
|
||||
;; wrong for a negative n).
|
||||
|
|
@ -549,11 +549,11 @@
|
|||
|
||||
;; file-seq: the tree of paths under root (root included), directories walked
|
||||
;; via the host dir primitives. Paths (strings), not File objects. (Lives below
|
||||
;; tree-seq: forward references are analysis errors now — jolt-2o7.3.)
|
||||
;; tree-seq: forward references are analysis errors.)
|
||||
(defn file-seq [root]
|
||||
(if (__file? root)
|
||||
;; java.io.File tree: walk via the File method surface so leaves are File
|
||||
;; values callers can invoke .isFile/.getName/slurp on (jolt-hjw).
|
||||
;; values callers can invoke .isFile/.getName/slurp on.
|
||||
(tree-seq (fn [f] (.isDirectory f)) (fn [f] (seq (.listFiles f))) root)
|
||||
(tree-seq __dir? __list-dir root)))
|
||||
|
||||
|
|
@ -587,10 +587,6 @@
|
|||
;; No ratio type on Jolt, so rationalize is identity.
|
||||
(defn rationalize [x] x)
|
||||
|
||||
;; trampoline: repeatedly calls f with args until a non-function result.
|
||||
|
||||
;; rand-int: random integer in [0, n). Uses Janet math/random.
|
||||
|
||||
;; 0-arg: a stateful transducer (tracks [seen? prev] in a volatile, so no sentinel
|
||||
;; value is needed). 1-arg: eager dedupe of consecutive equal elements.
|
||||
(defn dedupe
|
||||
|
|
@ -625,8 +621,7 @@
|
|||
;; canonical Clojure 1.11 shape (core.clj seq-to-map-for-destructuring):
|
||||
;; even pairs build a map (later keys win, as createAsIfByAssoc), a SINGLE
|
||||
;; element is returned as-is (the trailing-map calling convention), and an
|
||||
;; unpaired key past pairs throws. The old jolt version silently dropped the
|
||||
;; trailing element, losing (f {:b 2}) kwargs calls.
|
||||
;; unpaired key past pairs throws.
|
||||
(defn seq-to-map-for-destructuring [s]
|
||||
(if (next s)
|
||||
(loop [m {} xs (seq s)]
|
||||
|
|
@ -637,8 +632,8 @@
|
|||
m))
|
||||
(if (seq s) (first s) {})))
|
||||
|
||||
;; Phase 4 (jolt-1j0): host-coupled fns that are pure logic over existing core
|
||||
;; primitives, so they need no new jolt.host surface.
|
||||
;; Host-coupled fns that are pure logic over existing core primitives, so they
|
||||
;; need no new jolt.host surface.
|
||||
|
||||
;; vary-meta: f applied to obj's metadata (+ extra args), reattached. meta and
|
||||
;; with-meta are the irreducible host primitives; vary-meta is just their compose.
|
||||
|
|
@ -650,9 +645,8 @@
|
|||
(apply str (map (fn [c] (if (= c \-) \_ c)) (seq (str s)))))
|
||||
|
||||
;; reduce-kv over a map (k v) or vector (index v). Both branches go through reduce,
|
||||
;; so reduced short-circuits — and the vector path indexes correctly. (The prior
|
||||
;; Janet version saw a pvec as a table and folded over its internal keys; it also
|
||||
;; ignored reduced.) nil folds to init, matching Clojure.
|
||||
;; so reduced short-circuits — and the vector path indexes correctly. nil folds
|
||||
;; to init, matching Clojure.
|
||||
(defn reduce-kv [f init coll]
|
||||
(cond
|
||||
(vector? coll) (reduce (fn [acc i] (f acc i (nth coll i))) init (range (count coll)))
|
||||
|
|
@ -660,7 +654,7 @@
|
|||
(nil? coll) init
|
||||
:else (throw (str "reduce-kv not supported on: " coll))))
|
||||
|
||||
;; ex-info accessors. The Janet constructor (ex-info) stays — it builds the tagged
|
||||
;; ex-info accessors. The constructor (ex-info) stays native — it builds the tagged
|
||||
;; value and wires into throw — but the value exposes :jolt/type/:message/:data/
|
||||
;; :cause via get, so the accessors are pure over get. A thrown non-ex-info arrives
|
||||
;; wrapped as {:jolt/type :jolt/exception :value v}; unwrap that first.
|
||||
|
|
@ -724,7 +718,7 @@
|
|||
(when (< i (count vars))
|
||||
(var-set (nth vars i) (nth saved i))
|
||||
(recur (inc i))))))))
|
||||
;; Jolt has no chunked seqs (Phase 5 territory), so this is always false.
|
||||
;; Jolt has no chunked seqs, so this is always false.
|
||||
(defn chunked-seq? [x] false)
|
||||
|
||||
;; Atom peripheral operations. atom/swap!/reset!/deref stay native — the compiler
|
||||
|
|
@ -733,7 +727,7 @@
|
|||
;; slot; add-watch/remove-watch/set-validator! mutate the atom (or its watches
|
||||
;; sub-table) through the one host primitive jolt.host/ref-put! — the minimal
|
||||
;; mutation kernel the overlay can't express over core fns (a nil value removes the
|
||||
;; key). compare-and-set! compares by value, matching the prior Janet behavior.
|
||||
;; key). compare-and-set! compares by value.
|
||||
(defn swap-vals! [a f & args]
|
||||
(let [old (deref a)] [old (apply swap! a f args)]))
|
||||
(defn reset-vals! [a newval]
|
||||
|
|
@ -777,7 +771,7 @@
|
|||
(jolt.host/ref-put! target (nth idxs+val (- n 2)) val)
|
||||
val))
|
||||
|
||||
;; --- Phase 2 leaf batch (jolt-ded): fn combinators + host-free stubs ---------
|
||||
;; --- fn combinators + host-free stubs ----------------------------------------
|
||||
|
||||
(defn complement
|
||||
"Takes a fn f and returns a fn that takes the same arguments as f, has the
|
||||
|
|
@ -785,8 +779,7 @@
|
|||
[f]
|
||||
(fn [& args] (not (apply f args))))
|
||||
|
||||
;; Canonical Clojure fnil: patches only the FIRST 1-3 arguments (the old Janet
|
||||
;; kernel patched every position it had a default for, which Clojure does not).
|
||||
;; Canonical Clojure fnil: patches only the FIRST 1-3 arguments.
|
||||
(defn fnil
|
||||
([f x]
|
||||
(fn [a & args] (apply f (if (nil? a) x a) args)))
|
||||
|
|
@ -818,7 +811,7 @@
|
|||
(let [t (:test (meta v))]
|
||||
(if t (do (t) :ok) :no-test)))
|
||||
|
||||
;; --- Phase 2 leaf batch 2 (jolt-ded): canonical Clojure ports ----------------
|
||||
;; --- canonical Clojure ports -------------------------------------------------
|
||||
;; key/val/find first — merge-with and memoize below use them.
|
||||
|
||||
;; Strict, as in Clojure: an entry is what (seq m) yields (a host tuple), NOT
|
||||
|
|
@ -882,8 +875,7 @@
|
|||
(recur nxt (next ks))))
|
||||
m)))))
|
||||
|
||||
;; find-based, so nil RESULTS are cached too (the old kernel fn re-computed
|
||||
;; them); args canonicalize as a collection key.
|
||||
;; find-based, so nil RESULTS are cached too; args canonicalize as a collection key.
|
||||
(defn memoize [f]
|
||||
(let [mem (atom (hash-map))]
|
||||
(fn [& args]
|
||||
|
|
@ -920,11 +912,9 @@
|
|||
|
||||
(defn reverse [coll] (reduce conj (list) coll))
|
||||
|
||||
;; --- Phase 2 leaf batch 3 (jolt-ded) -----------------------------------------
|
||||
|
||||
;; An empty coll of the same category; sorted colls keep their comparator (the
|
||||
;; value's own :empty op). Strings and scalars are nil, as in Clojure; a lazy
|
||||
;; seq empties to () (the old kernel fn returned a host table for it).
|
||||
;; seq empties to ().
|
||||
(defn empty [coll]
|
||||
(cond
|
||||
(nil? coll) nil
|
||||
|
|
@ -948,8 +938,6 @@
|
|||
(assoc m k (apply f (get m k) args)))))]
|
||||
(up m ks f args)))
|
||||
|
||||
;; --- jolt-brh: the last missing-portable vars --------------------------------
|
||||
|
||||
;; jolt keywords have no intern table (any keyword "exists"), so find-keyword
|
||||
;; always finds — babashka makes the same call.
|
||||
(defn find-keyword
|
||||
|
|
@ -962,7 +950,7 @@
|
|||
|
||||
;; Canonical comp — here rather than a host primitive so each stage is invoked with
|
||||
;; jolt call semantics: (comp seq :content) works because the keyword stage
|
||||
;; goes through IFn dispatch (raw Janet keyword application does not).
|
||||
;; goes through IFn dispatch.
|
||||
(defn comp
|
||||
([] identity)
|
||||
([f] f)
|
||||
|
|
@ -977,17 +965,15 @@
|
|||
([x y z & args] (f (apply g x y z args)))))
|
||||
([f g & fs] (reduce comp (comp f g) fs)))
|
||||
|
||||
;; Canonical IFn set (jolt-1vx): fns, keywords, symbols, maps (sorted incl.),
|
||||
;; Canonical IFn set: fns, keywords, symbols, maps (sorted incl.),
|
||||
;; sets, vectors, and vars — NOT lists ((ifn? '(1 2)) is false in Clojure).
|
||||
;; Mutable-mode caveat: vectors and lists share the array representation
|
||||
;; there, so vector? can't separate them and lists read as ifn?.
|
||||
(defn ifn? [x]
|
||||
(or (fn? x) (keyword? x) (symbol? x) (map? x) (set? x) (vector? x) (var? x)))
|
||||
|
||||
;; Auto-promoting (') and unchecked arithmetic. Jolt numbers don't overflow,
|
||||
;; so all of these are the checked ops; fixed arities mirror Clojure's
|
||||
;; signatures. unchecked-divide-int goes through quot, so dividing by zero
|
||||
;; throws as on the JVM (the old seed fn silently truncated infinity).
|
||||
;; throws as on the JVM.
|
||||
(def +' +)
|
||||
(def -' -)
|
||||
(def *' *)
|
||||
|
|
@ -1079,7 +1065,7 @@
|
|||
(defn unchecked-float [x] (double x))
|
||||
(defn unchecked-double [x] (double x))
|
||||
|
||||
;; --- transduce / into / eduction (seed-shrink round 5) ---------------------
|
||||
;; --- transduce / into / eduction ---------------------------------------------
|
||||
;; Canonical transduce: build the stacked rf once, reduce (which honors
|
||||
;; `reduced` and steps lazy seqs incrementally), then run the completion arity.
|
||||
(defn transduce
|
||||
|
|
@ -1089,9 +1075,9 @@
|
|||
(xf (reduce xf init coll)))))
|
||||
|
||||
;; into stays a host primitive: it's perf-wall hot (the into-vec bench pays ~11%
|
||||
;; through the overlay call layers — same lesson as even?/odd? in round 4).
|
||||
;; through the overlay call layers — same lesson as even?/odd?).
|
||||
|
||||
;; eduction is EAGER on jolt (documented divergence, as before): the composed
|
||||
;; eduction is EAGER on jolt (documented divergence): the composed
|
||||
;; xforms applied to coll, realized into a vector.
|
||||
(defn eduction [& args]
|
||||
(let [coll (last args)
|
||||
|
|
@ -1102,7 +1088,7 @@
|
|||
|
||||
(defn ->Eduction [xform coll] (into [] xform coll))
|
||||
|
||||
;; --- JVM-shape stubs and trivial shells (seed-shrink batch 2) --------------
|
||||
;; --- JVM-shape stubs and trivial shells --------------------------------------
|
||||
;; Pure compositions or documented jolt stubs; the host keeps nothing.
|
||||
(defn enumeration-seq [e] (seq e))
|
||||
(defn iterator-seq [i] (seq i))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
;; clojure.core — sorted collections tier (stage 3, jolt-0lj).
|
||||
;; clojure.core — sorted collections tier.
|
||||
;;
|
||||
;; A sorted-map / sorted-set is a tagged host table
|
||||
;; {:jolt/type :jolt/sorted-map|:jolt/sorted-set
|
||||
|
|
@ -10,8 +10,7 @@
|
|||
;; The tree is a left-leaning-free red-black tree — Rich Hickey's algorithm,
|
||||
;; ported from the ClojureScript PersistentTreeMap (cljs.core: tree-map-add /
|
||||
;; balance-left / balance-right / tree-map-append / balance-*-del). assoc / get /
|
||||
;; dissoc / contains are O(log n); the old sorted-VECTOR rep was O(n) per assoc,
|
||||
;; O(n^2) to build (jolt-684u's sibling, jolt-0hbr). cljs uses BlackNode/RedNode
|
||||
;; dissoc / contains are O(log n). cljs uses BlackNode/RedNode
|
||||
;; deftypes, but this tier loads before 30-macros (no deftype), so a node is a
|
||||
;; plain vector [color k v left right] (color :red/:black; left/right node|nil)
|
||||
;; and the methods become functions — the algorithm is identical.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
;; clojure.core — macro tier. Macros expressed in Clojure (defmacro + syntax-quote)
|
||||
;; rather than as hand-built Janet form-transformers. Loaded after the fn tiers,
|
||||
;; so a macro here may use any already-frozen core fn/macro.
|
||||
;; clojure.core — macro tier. Macros expressed in Clojure (defmacro + syntax-quote).
|
||||
;; Loaded after the fn tiers, so a macro here may use any already-frozen core
|
||||
;; fn/macro.
|
||||
;;
|
||||
;; IMPORTANT — only macros NOT used by the self-hosted compiler (jolt-core/jolt/*)
|
||||
;; or by the earlier overlay tiers belong here; those (and/or/when/when-not/
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
(defmacro defmethod [mm dispatch-val & fn-tail]
|
||||
`(defmethod-setup (quote ~mm) ~dispatch-val (fn ~@fn-tail)))
|
||||
|
||||
;; Multimethod table ops (tier 6c): a multimethod's method table lives on its
|
||||
;; Multimethod table ops: a multimethod's method table lives on its
|
||||
;; VAR (the value is just the dispatch closure), so these pass the name quoted
|
||||
;; to ctx-capturing setups — the same shape as defmulti/defmethod above.
|
||||
(defmacro prefer-method [mm dval-a dval-b]
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
;; methods/get-method take the multimethod VALUE (Clojure semantics); the setup
|
||||
;; maps it back to its var via the registry, so a bare multifn ref works from a
|
||||
;; compiled fn in any namespace (jolt multimethod table-visibility fix).
|
||||
;; compiled fn in any namespace.
|
||||
(defmacro get-method [mm dval]
|
||||
`(get-method-setup ~mm ~dval))
|
||||
|
||||
|
|
@ -75,7 +75,7 @@
|
|||
`(do ~x ~@body))
|
||||
|
||||
;; defonce: define name only if it isn't already bound to a non-nil root;
|
||||
;; returns the existing var untouched otherwise (matching the prior arm).
|
||||
;; returns the existing var untouched otherwise.
|
||||
;; time: evaluate expr, print the elapsed wall-clock, return the value.
|
||||
;; current-time-ms is the host's monotonic clock.
|
||||
(defmacro time [expr]
|
||||
|
|
@ -164,14 +164,12 @@
|
|||
(loop [~i 0]
|
||||
(when (< ~i n#) ~@body (recur (inc ~i)))))))
|
||||
|
||||
;; A fresh jolt symbol inside a macro body: (gensym) here resolves to Janet's
|
||||
;; builtin (a Janet symbol the destructurer rejects), so round-trip through str.
|
||||
;; A fresh jolt symbol inside a macro body: a bare (gensym) returns a host symbol
|
||||
;; the destructurer rejects, so round-trip through str.
|
||||
(defn- fresh-sym [] (symbol (str (gensym))))
|
||||
|
||||
;; Lazy-safe: take only the head via first (Clojure uses (seq coll), but Jolt's
|
||||
;; eager seq would realize an infinite coll like (repeat nil) and hang). Matches
|
||||
;; the prior Janet behavior; the nil/false-head distinction waits on Phase 5
|
||||
;; laziness.
|
||||
;; eager seq would realize an infinite coll like (repeat nil) and hang).
|
||||
(defmacro when-first [bindings & body]
|
||||
(let [x (bindings 0) coll (bindings 1)]
|
||||
`(when-let [~x (first ~coll)] ~@body)))
|
||||
|
|
@ -289,7 +287,7 @@
|
|||
;; a seq of field keywords; spliced into a vector LITERAL below ([~@…]) so
|
||||
;; the analyzer sees a vector form, not a runtime pvec value.
|
||||
field-kws (map (fn [f] (keyword (name f))) fields)
|
||||
;; per-field TYPE HINT (jolt-3ko): ^Vec3 origin -> "Vec3" (a record type
|
||||
;; per-field TYPE HINT: ^Vec3 origin -> "Vec3" (a record type
|
||||
;; name), ^:num x -> "num", else nil. Lets the inference know a field's
|
||||
;; exact type up front, so reading it back carries that type (not :any) —
|
||||
;; the key to fast nested-record code. Spliced as a vector literal too.
|
||||
|
|
@ -298,7 +296,7 @@
|
|||
(and mt (:num mt)) "num"
|
||||
:else nil)))
|
||||
fields)
|
||||
;; per-field MUTABILITY (jolt-c3q): ^:unsynchronized-mutable / ^:volatile-
|
||||
;; per-field MUTABILITY: ^:unsynchronized-mutable / ^:volatile-
|
||||
;; mutable marks a field set!-able. A type with any mutable field opts out
|
||||
;; of the immutable shape-rec layout and uses the mutable table form, so
|
||||
;; set! can mutate it (the ctor reads this vector). Spliced as a literal.
|
||||
|
|
@ -309,7 +307,7 @@
|
|||
fields)
|
||||
;; mutable field symbols (^:unsynchronized-mutable / ^:volatile-mutable):
|
||||
;; (set! field v) in a method body lowers to (set! (.-field inst) v), the
|
||||
;; in-place field write the analyzer compiles to jolt-set-field! (jolt-c3q).
|
||||
;; in-place field write the analyzer compiles to jolt-set-field!.
|
||||
mutable-syms (map first (filter second (map vector fields field-muts)))
|
||||
mutable? (fn [s] (boolean (some (fn [m] (= m s)) mutable-syms)))
|
||||
rewrite-set (fn rw [inst form]
|
||||
|
|
@ -359,7 +357,7 @@
|
|||
{} sigs)]
|
||||
`(do
|
||||
(def ~pname (make-protocol ~(name pname) ~methods))
|
||||
;; register method var-keys for devirtualization (jolt-41m); the inference
|
||||
;; register method var-keys for devirtualization; the inference
|
||||
;; reads this (via infer-unit!) to resolve a protocol call on a known record
|
||||
(register-protocol-methods! ~(name pname) [~@(map (fn [s] (name (first s))) sigs)])
|
||||
~@(map (fn [sig]
|
||||
|
|
@ -431,8 +429,7 @@
|
|||
`(do ~@(map (fn [g] `(extend-type ~(first g) ~psym ~@(rest g)))
|
||||
(group-by-head type-impls))))
|
||||
|
||||
;; extend (the fn form) is not supported — stub to nil, as before.
|
||||
;; extend is a real FUNCTION now — defined above extend-type.
|
||||
;; extend is a real FUNCTION — defined above extend-type.
|
||||
;; JVM proxies are unsupported.
|
||||
(defmacro proxy [& args] nil)
|
||||
;; definterface is JVM-only; bind the name to a marker and return the name (not a
|
||||
|
|
@ -474,7 +471,7 @@
|
|||
(let [argv (nth spec 1)
|
||||
inst (first argv)
|
||||
;; hint `this` with the record type so the inference
|
||||
;; types it (jolt-3ko) and its field reads bare-index
|
||||
;; types it and its field reads bare-index
|
||||
;; instead of going through the runtime tag guard.
|
||||
hinted (assoc argv 0 (vary-meta inst assoc :tag (name name-sym)))
|
||||
binds (vec (mapcat (fn [f] [f `(get ~inst ~(keyword (name f)))]) fields))]
|
||||
|
|
@ -492,8 +489,8 @@
|
|||
;; lazy-seq / lazy-cat moved to the 00-syntax tier: the seq/coll tiers (10-seq,
|
||||
;; 20-coll) use lazy-seq, and in compile mode a tier's forms are compiled as it
|
||||
;; loads — so the macro must be registered BEFORE those tiers, else (lazy-seq …)
|
||||
;; compiles as a call to the macro-as-function and leaks its expansion at runtime
|
||||
;; (jolt-r81). They only need seed fns (make-lazy-seq/coll->cells/concat).
|
||||
;; compiles as a call to the macro-as-function and leaks its expansion at runtime.
|
||||
;; They only need seed fns (make-lazy-seq/coll->cells/concat).
|
||||
|
||||
;; memfn: a fn wrapping a method call, (memfn toUpperCase) => #(.toUpperCase %).
|
||||
;; The method symbol is rewritten to jolt's .method call sugar; extra arg names
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@
|
|||
;; --- partition-all --- (transducer + [n coll] + [n step coll])
|
||||
;; The collection arities realize EXACTLY n per chunk via a first/rest loop and
|
||||
;; continue from the advanced cursor (not a re-drop / nthrest), so they realize
|
||||
;; minimally — the §6.3 laziness counters depend on this.
|
||||
;; minimally — the laziness counters depend on this.
|
||||
;; (A take/nthrest form is correct but over-realizes.)
|
||||
(defn partition-all
|
||||
([n]
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
(cons (take n s) (go (nthrest s step))))))]
|
||||
(go coll))))
|
||||
|
||||
;; --- Phase 2 leaf batch 3 (jolt-ded): canonical lazy + transducer arities ----
|
||||
;; --- canonical lazy + transducer arities -------------------------------------
|
||||
|
||||
(defn interpose
|
||||
([sep]
|
||||
|
|
@ -176,7 +176,7 @@
|
|||
(when-let [s (seq coll)]
|
||||
(cons (first s) (take-nth n (drop n s)))))))
|
||||
|
||||
;; --- pmap family (jolt-oeu): parallel map over real-thread futures ----------
|
||||
;; --- pmap family: parallel map over real-thread futures ----------------------
|
||||
;; Each element's work runs on its own OS thread with SNAPSHOT semantics
|
||||
;; (futures marshal captured state — pure fns only, mutations don't propagate
|
||||
;; back). All futures are spawned up front (doall), then derefed in order:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
;; clojure.core — IO tier: the *in* reader family (jolt-0d9).
|
||||
;; clojure.core — IO tier: the *in* reader family.
|
||||
;;
|
||||
;; *in* is a dynamic var holding a READER: a plain map whose two ops close
|
||||
;; over their source — :read-line-fn (next line, newline
|
||||
|
|
@ -135,7 +135,7 @@
|
|||
(when line
|
||||
(cons line (line-seq rdr)))))))
|
||||
|
||||
;; --- print-method (jolt-g1r) ------------------------------------------------
|
||||
;; --- print-method ------------------------------------------------
|
||||
;; Canonical dispatch (clojure/core.clj 3693): the :type metadata when it's a
|
||||
;; keyword, else the value's type. On jolt, type is the keyword tag for
|
||||
;; builtins and the deftype name SYMBOL for records — so a record method is
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue