Refactor phase 5d/5e: seed↔overlay registry + rep↔API boundary docs (jolt-bvek)

5d: document the seed↔overlay boundary and add a drift check. core fns split
across a Janet seed (core-X, registered in core-bindings) and a Clojure overlay;
five names (char?/sorted?/sorted-map?/sorted-set?/transduce) carry a defn in
both, with the overlay copy authoritative and the seed copy internal-only. The
into-vs-transduce home asymmetry was undocumented. Adds docs/seed-overlay-registry.md,
SEED-TWIN: comments at the five seed sites, and a build-time drift check
(test/unit/seed-overlay-registry-test.janet) that recomputes the twin set from
source and fails if it diverges or a twin leaks into core-bindings.

5e: rep↔API pointer comments in pv/plist/phm/phs/lazyseq (representation lives
here; Clojure-facing ops dispatch in core_coll/core_types) and back-pointers in
core_coll. No behavior change — comments, docs, one source-analysis test.

Full gate green (suite ≥4695 pass / ≥88 clean files), drift check passes.
This commit is contained in:
Yogthos 2026-06-15 04:22:05 -04:00
parent 6c0142e625
commit 793b55f1f3
9 changed files with 226 additions and 1 deletions

View file

@ -1,5 +1,11 @@
# Jolt Core — collections, transducers, seqs, HOFs, constructors
# Extracted from core.janet (jolt-nma8, phase 2b split).
#
# REP vs API: this file holds the Clojure-facing collection ops and dispatches
# on `:jolt/type` over the internal persistent structures, whose representations
# live elsewhere: persistent vector → pv.janet, list → plist.janet, hash map →
# phm.janet, set → phs.janet, lazy seq → lazyseq.janet. Grep a structure's file
# header for the primitive (pv-*/pl-*/phm-*/phs-*/ls-*) it exposes.
(use ./types)
(use ./phm)
@ -535,6 +541,10 @@
[rf init coll]
(reduce-with-reduced rf init coll))
# SEED-TWIN: transduce is overlay-public (jolt-core/clojure/core/20-coll.clj);
# this seed copy is NOT registered in core-bindings. It survives only as the
# helper core-into calls below — user `transduce` resolves to the overlay. The
# asymmetry with `into` (seed-public) is intentional; docs/seed-overlay-registry.md.
(defn core-transduce
"(transduce xform f coll) or (transduce xform f init coll)."
[xform f & rest]

View file

@ -50,6 +50,10 @@
# Sorted-coll tag checks + entries view, defined this early because canon-key,
# empty?, and jolt-equal? (all below) need them. The sorted-coll SEMANTICS are
# pure Clojure (core/25-sorted.clj); see the dispatch section further down.
# SEED-TWIN: sorted-map?/sorted-set?/sorted? also live in the overlay
# (jolt-core/clojure/core/25-sorted.clj); the overlay copies are the public ones
# (NOT in core-bindings). These seed copies exist only for earlier-tier seed
# dispatch. Change both copies together — docs/seed-overlay-registry.md.
(defn core-sorted-map? [x] (and (table? x) (= :jolt/sorted-map (x :jolt/type))))
(defn core-sorted-set? [x] (and (table? x) (= :jolt/sorted-set (x :jolt/type))))
(defn core-sorted? [x] (or (core-sorted-map? x) (core-sorted-set? x)))
@ -194,6 +198,9 @@
# Predicates
# ============================================================
# SEED-TWIN: char? is also defined in the overlay (jolt-core/clojure/core/
# 20-coll.clj) and the overlay copy is the public one (NOT in core-bindings).
# This seed copy is internal type dispatch only. docs/seed-overlay-registry.md.
(defn core-char? [x] (and (struct? x) (= :jolt/char (x :jolt/type))))
(defn char-code [c] (c :ch))
(defn char->string [c] (string/from-bytes (c :ch)))

View file

@ -3,7 +3,11 @@
# Model: a thunk returns nil (empty) or a [first-val, rest-thunk] pair; each
# step produces one element + a thunk for the rest. Supports self-referencing
# sequences like fib-seq. Self-contained (janet builtins only) — the Clojure
# seq layer (core.janet) and the interpreter build on these primitives.
# seq layer (core_coll.janet) and the interpreter build on these primitives.
#
# REP vs API: this file is ONLY the lazy-cell representation (ls-* primitives).
# The Clojure-facing seq ops (first/rest/seq/cons/count dispatch, realization)
# live in core_coll.janet, branching on `:jolt/type :jolt/lazy-seq`.
#
# Extracted from phm.janet (jolt-bvek): a lazy sequence has nothing to do with
# hash maps; both were tagged tables, which is why they shared a file.

View file

@ -5,6 +5,12 @@
# ~12-entry linear scan per get (the jolt-s3y map-read regression). The bucket
# count is derived from (length (m :buckets)), so marshaled images from before
# this change keep working.
#
# REP vs API: this file is ONLY the hash-map representation (phm-* primitives).
# The Clojure-facing map ops (assoc/dissoc/get/conj/count/seq dispatch, nil-key
# handling, merge) live in core_coll.janet / core_types.janet, which recognize
# phm by its `:jolt/deftype` string. PersistentHashSet is layered on top in
# phs.janet; LazySeq (historically here) now lives in lazyseq.janet.
(def- initial-buckets 8)

View file

@ -1,6 +1,11 @@
# PersistentHashSet — a set backed by a PersistentHashMap (members are keys
# mapped to true). Extracted from phm.janet (jolt-bvek) so phm.janet is purely
# the hash map; the set is a thin layer over it.
#
# REP vs API: this file is ONLY the set representation (phs-* primitives). The
# Clojure-facing set ops (conj/disj/contains?/count/seq dispatch, set-as-fn
# membership) live in core_coll.janet / core_types.janet, branching on
# `:jolt/type :jolt/set`.
(use ./phm)

View file

@ -12,6 +12,10 @@
#
# `:rest` may be a plain array/tuple so `(conj some-list x)` needn't copy the
# original list — the node just references it. pl->array materializes the chain.
#
# REP vs API: this file is ONLY the cons-list representation (pl-* primitives).
# The Clojure-facing list/seq ops (conj/cons/first/rest/count/seq dispatch) live
# in core_coll.janet, which branches on `:jolt/type :jolt/plist`.
(defn plist? [x]
(and (table? x) (= :jolt/plist (get x :jolt/type))))

View file

@ -11,6 +11,11 @@
# :tail tail} a tuple of up to 32 trailing elements (append fast-path)
#
# Trie nodes are immutable tuples so unchanged subtrees are shared by identity.
#
# REP vs API: this file is ONLY the trie representation (pv-* primitives). The
# Clojure-facing vector ops (nth/conj/assoc/subvec, the count/seq/first/rest
# dispatch, and tuple↔pvec polymorphism) live in core_coll.janet /
# core_types.janet, which dispatch on `:jolt/type :jolt/pvec`.
(def- bits 5)
(def- width 32) # 2^bits