Commit graph

9 commits

Author SHA1 Message Date
Yogthos
a68210e440 core: jolt-cru — partition-all/partition-by transducer (1-arg) arities
(partition-all n) and (partition-by f) now return stateful transducers, so they
compose with into/sequence/transduce/comp (previously errored "called with 1
argument, expected 2"). Both buffer a window, emit on boundary, flush a partial
trailing window in the completion arity, and honor `reduced` (early stop drops
the in-progress window, no extra trailing partition) — matching Clojure.

partition-all: td-partition-all in core.janet (Janet, alongside the other td-*),
core-partition-all made variadic. partition-by: transducer arity added to the
overlay defn in Clojure with volatiles (stays with its lazy collection arity).

Gate: conformance 253x3 (+4 transducer cases incl comp + reduced), lazy-infinite
44/44, fixpoint, self-host, specs+unit green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 18:13:49 -04:00
Yogthos
a71bddd580 Review fixes: revert partition+concat overlay, delete dead defns, dedupe de-duplicated
1. partition+concat removed from 10-seq.clj overlay — they use
   lazy-seq macro which produces raw make-lazy-seq forms in compile
   mode (same issue as mapcat overlay reversal). Must stay native.

2. Dead defns removed from core.janet: core-map-indexed,
   core-iterate, core-repeatedly (30 lines). Bindings already
   removed in prior commit.

3. dedupe removed from 40-lazy.clj — belongs in 20-coll.clj.

Gates: conformance 229×3, lazy-infinite 22/22, specs 32/32.
2026-06-08 12:04:48 -04:00
Yogthos
4a2ef99fee Review fixes: partition+concat in 10-seq, delete dead defns, dedupe de-duplicated
1. partition + concat added to 10-seq.clj (ported from CLJS core.cljs)
2. Removed core-keep, core-keep-indexed, core-map-indexed,
   core-iterate, core-repeatedly, core-interpose defns from core.janet
   (bindings already removed in prior commit, left dead bodies)
3. Removed dedupe from 40-lazy.clj (belongs in 20-coll.clj)

Gates: lazy-infinite 22/22, conformance 229x3, specs 32/32
2026-06-08 11:58:39 -04:00
Yogthos
64b1c60939 Step 5: partition-by, dedupe → lazy overlay + trampoline/rand-int overlay
partition-by (10-seq.clj): ported canonical lazy implementation
from CLJS — lazy-seq + cons + take-while, matching Clojure/CLJS
exactly. Fixes the third and final remaining leak from Step 3.

dedupe (20-coll.clj): replaced eager vec-based impl with lazy
step function using lazy-seq + cons. Infinite input no longer hangs.

trampoline (20-coll.clj): pure HOF ported from CLJS — recur until
non-function result. Removed core-trampoline + binding from Janet.

rand-int (20-coll.clj): thin overlay over Janet math/random +
math/floor. Removed core-rand-int + binding from Janet.

Removed core-partition-by + binding from core.janet (now in overlay).

Tests: added dedupe infinite-input case to lazy-infinite harness.
22/22 pass. Conformance 229x3. Specs 32/32.
2026-06-08 11:02:03 -04:00
Yogthos
42da5cef9a Step 4: evaluator eager assumptions — lazy rest + lazy mapcat
Fix & rest destructuring (evaluator.janet): when the original
value is a lazy-seq, derive & rest by walking ls-rest vi steps
instead of slicing the eagerly-realized array from d-realize.

Rewrite core-mapcat as a lazy state machine (core.janet): step
through input colls one element at a time, call f on each tuple,
then yield from f's result collection. No apply-forcing —
all input colls are walked lazily via lazy-from + seq-done?.

Add mapcat to core-renames (compiler.janet) and remove from
Clojure overlay (10-seq.clj) — compile mode now emits direct
calls to the lazy core-mapcat, fixing the pre-existing
protocol-on-record compile error.

Tests: re-enabled mapcat infinite harness case, added 2 & rest
laziness cases. 21/21 lazy-infinite, 229x3 conformance, 32/32 specs.
2026-06-08 10:46:42 -04:00
Yogthos
ff8ffb8cd6 Code review: fix drop-while perf + revert lazy mapcat overlay
core-drop-while (core.janet): return cell via realize-ls instead
of raw LazySeq. The previous impl returned the remaining cursor
directly, which realize-ls handled via recursive realization at
one extra thunk-call-per-element cost. Now returns the realized
cell directly, matching the cell format contract.

mapcat (10-seq.clj): revert to standard (apply concat (apply map
f colls)). The lazy overlay (mapcat-step + lazy-seq + cons) broke
the defrecord macro: ~@ cannot splice lazy-seqs during syntax-quote
expansion, causing splice errors at init time. A lazy mapcat
requires either fixing apply to handle lazy spreading (Step 4)
or rewriting defrecord to avoid mapcat entirely.

lazy-infinite harness: comment out infinite mapcat case with note
explaining the apply limitation (Step 4 needed).

Gates verified:
  conformance 229/229 x3 (interpret/compile/self-host)
  lazy-infinite 18/18
  specs 32/32 files, 0 failures
2026-06-08 09:25:19 -04:00
Yogthos
d16e1f4eba Step 4: lazy mapcat overlay — eliminate apply forcing on infinite inputs
mapcat in 10-seq.clj now uses a defn- mapcat-step helper that walks
lazy map results element-by-element (cons + lazy-seq), with explicit
arities for 1/2/3/4+ colls. The 4+-coll arity still uses apply to
spread colls to map, but apply no longer forces the inner map result.

Previously (apply concat (apply map f colls)) forced the lazy map
result through core-apply realize-for-iteration, which hung on
infinite inputs. The new step-based impl walks one element at a time
via first/rest/seq primitives.

Re-enabled deferred mapcat infinite-input harness case. 19/19 pass.

Gates: lazy-infinite 19/19, conformance 229/229 interpret+self-host
(compile 228/229 — 1 pre-existing protocol error), specs 32/32.
2026-06-08 08:14:59 -04:00
Yogthos
e2e189acfe Phase 5: true laziness — lazy transformers + deadlined harness
jolt-c09 (partial, Steps 0–2d complete).

Lazy combinator layer (Step 1):
- lazy-cons: build a LazySeq cell from val + rest-thunk (phm.janet)
- lazy-from: coerce any seqable to lazy view without forcing (core.janet)
- core-seq: check ls-first emptiness, not ls-seq realization (core.janet)

Lazy transformers (Steps 2a–2d):
Converted in Janet core.janet (lazy branches preserving transducer arities):
  drop-while, interpose, distinct, partition, partition-all,
  keep, keep-indexed, map-indexed, take-nth

Moved to Clojure overlay (jolt-core):
  interleave (20-coll.clj) — lazy multi-arity, matches Clojure
  mapcat (10-seq.clj) — transducer arity + standard (apply concat (apply map f colls))

Safety net (Step 0):
  test/support/lazy-eval.janet — subprocess worker for Clojure eval
  test/integration/lazy-infinite-test.janet — deadlined harness (os/spawn + 5s)

Multi-input map/mapcat tests (Step 2d):
  sequences-spec.janet +9 tests, verified against Clojure/CLJS references

Gates:
  lazy-infinite: 18/18 (mapcat on infinite inputs hangs — apply forces, needs Step 4)
  conformance: 229/229 ×3 (interpret/compile/self-host)
  specs: 32/32 files, 0 failures
2026-06-08 00:40:56 -04:00
Yogthos
28ef15ea4b core: staged-bootstrap kernel tier; move second/peek/subvec/mapv/update to Clojure
First fractal turn of the multi-stage bootstrap (jolt-tzo). The Clojure part of
clojure.core is now loaded in ordered tiers under jolt-core/clojure/core/. The
kernel tier (00-kernel: second/peek/subvec/mapv/update) holds the structural fns
the self-hosted compiler itself uses; in compile mode it is bootstrap-compiled
into clojure.core BEFORE the analyzer is built, so the analyzer binds those names
to the Clojure definitions instead of a not-yet-defined forward ref. That removes
the circularity that previously forced these to stay in Janet — the five core-*
primitives and their init-core! entries are gone.

Mechanism: backend/bootstrap-load-source (generalized from compile-load) builds a
source string into a target ns via the bootstrap; rebuild-compiler! recompiles
the self-hosted compiler against the current core (the rail for future turns,
exercised by the new fixpoint test). api/load-core-overlay! walks the ordered
tiers, bootstrap-loading kernel tiers and self-hosting the rest.

Also fixes a latent evaluator bug surfaced by the move: a fn rebinds current-ns
to its defining ns while it runs and restores on normal return, but a fn that
THREW unwound past its own restore, leaking the ns. try now restores the
try-entry ns on the catch/finally path, so referred-symbol resolution survives a
caught error (this was breaking is/testing in the suite harness after any thrown
assertion). Net battery +3 (3913 -> 3916); conformance 218/218 in all three
modes; binary builds and runs the embedded tiers.
2026-06-06 13:15:17 -04:00