165 lines
8 KiB
Markdown
165 lines
8 KiB
Markdown
# Jolt — Complete Implementation Plan
|
|
|
|
## Architecture Goal
|
|
|
|
Minimal Janet bootstrap → SCI/CLJS Clojure source runs on Jolt.
|
|
|
|
Three layers:
|
|
1. **Janet runtime**: types.janet, reader.janet, evaluator.janet, compiler.janet (~4,200 lines)
|
|
2. **Clojure core**: core.janet (~1,400 lines), phm.janet (~200 lines)
|
|
3. **Clojure source** (.clj files loadable at runtime): stdlib modules, SCI
|
|
|
|
## Current State
|
|
|
|
| Metric | Value |
|
|
|--------|-------|
|
|
| Total tests | 317 |
|
|
| Passing | 317 |
|
|
| Failing | 0 |
|
|
| CLJS ported test files | 16 (1/1a/1b/2/3/3b/4/5/6/7/8/9/10/test + test-sci-runtime + eval-test) |
|
|
| Total assertions | 440 across 31 test files |
|
|
| Source lines | ~5,800 (7 core .janet files) |
|
|
| SCI source files loading | 9/9 |
|
|
| New features | `eval` special form, `with-meta` core binding, `var-dynamic?` core binding, `load-string` API, `^:dynamic` def handler |
|
|
|
|
## Phase Plan
|
|
|
|
### Phase 0-10: Foundation ✓
|
|
|
|
| Phase | Description | Status |
|
|
|-------|-------------|--------|
|
|
| 0 | `defn` bug fix, bare symbol resolution | ✓ |
|
|
| 1 | Var/Namespace system, ns form extensions | ✓ |
|
|
| 2 | PersistentHashMap implementation | ✓ |
|
|
| 3 | Var system: var-get/set/?, alter-var-root, intern, binding | ✓ |
|
|
| 4 | deftype/defrecord completion | ✓ |
|
|
| 5 | Multimethods + Hierarchy | ✓ |
|
|
| 6 | Reader extensions: tagged literals, :jolt/tagged handler | ✓ |
|
|
| 7 | LazySeq + PersistentHashSet | ✓ |
|
|
| 8 | Protocol system: defprotocol, extend-type, extend-protocol, reify, satisfies? | ✓ |
|
|
| 9 | REPL fixes: buffer-based output, collection rendering, cond fix | ✓ |
|
|
| 10 | Standard Library: clojure.string, clojure.set, clojure.walk, clojure.zip, clojure.edn, clojure.java_io, jolt.interop, jolt.shell, jolt.http | ✓ |
|
|
|
|
### Phase 11: Fix Pre-existing Failures ✓
|
|
|
|
- `types.janet`: `ns?` now accepts both structs and tables
|
|
- `core.janet`: `comment` macro wired into core-bindings
|
|
- `sci/lang_stubs.clj`: minimal SCI type stubs for bootstrap
|
|
- `test-load-sci.janet`: load stubs before SCI source files
|
|
- **Result: SciVar fixed. 1 remaining (deftype with `#?@` — Phase 15)**
|
|
|
|
### Phase 12: Core Feature Completion ✓
|
|
|
|
- `apply` support in evaluator + compiler
|
|
- `str` handles nil correctly
|
|
- 6 CLJS test files created (~120 assertions)
|
|
- `#()` anonymous fn reader with `%`, `%1`, `%2` arg handling
|
|
|
|
### Phase 13: Protocol Completion ✓
|
|
|
|
- reify dispatch: protocol methods work on reified objects
|
|
- `#()` reader macro with gensym-based `%` arg handling
|
|
- IFn protocol support in default invocation arm
|
|
- clojure.walk loads and `keywordize-keys` works
|
|
- 4 test sections: reify dispatch, anon fn, extend-type, walk loading
|
|
|
|
### Phase 14: Extend CLJS Ported Tests ✓
|
|
|
|
- `cljs-port-2.janet` expanded: 10 sections (12-21), 35→60 assertions
|
|
- `cljs-port-5.janet` created: sections 22-24, destructuring, metadata, fn composition
|
|
- `pr-str` compiler fix: maps to new `core-pr-str` (not `core-str`)
|
|
- `every-pred` added to core.janet
|
|
- `var-dynamic?` and `with-meta` tests restored
|
|
|
|
### Phase 15: SCI Bootstrap ✓
|
|
|
|
- ✅ `sci.lang` namespace loads completely (all 10 forms, including Var, Type, Namespace deftypes)
|
|
- ✅ 9 SCI source files load without errors (impl/macros, impl/protocols, impl/types, impl/unrestrict, impl/vars, lang, impl/utils, impl/namespaces, core)
|
|
- ✅ `prefer-method`/`remove-method`/`remove-all-methods` promoted to special forms (fix: auto-deref gave functions to `get`/`put`)
|
|
- ✅ All 5 pre-existing test failures fixed:
|
|
- `cljs-port-1.janet` — `#{}` Janet comment issue replaced with count-based comparisons
|
|
- `cljs-port-2.janet` — `with-meta` added as core binding with table/setproto
|
|
- `cljs-port-3b.janet` — `load-string` multi-form loader for string.clj and set.clj
|
|
- `cljs-port-5.janet` — `var-dynamic?` core binding + `^:dynamic` def handler fix
|
|
- `phase5-test.janet` — `remove-method` special form fixed to eval-form first arg
|
|
- New core infrastructure: `core-with-meta` (supports structs/tables via prototype), `core-var-dynamic?`, `load-string` API, `^:dynamic` propagation in `def` handler
|
|
- `core-str` now returns `"nil"` for nil (Clojure-compatible)
|
|
- `core-meta` checks `:jolt/meta` for with-meta'd values
|
|
- Test suite: **317/317 pass, 0 fail**
|
|
|
|
### Phase 16: Remaining Core Library + Tests ✅
|
|
|
|
- ✅ `eval` implemented as special form (interpreter + compiler), tested in `eval-test.janet` (4 assertions)
|
|
- ✅ `&` rest destructuring, `seq` nil handling, `vector`/`list` equality verified working
|
|
- ✅ `syntax-quote` confirmed working with unquote
|
|
- ✅ 5 new CLJS ported test files (cljs-port-6 through -10): anon fns, symbols/keywords/lists, destructuring, range/concat/partition/sort, seq predicates/complement, when/if-let/doto
|
|
- ✅ 16 total CLJS ported test files, 440 assertions across 31 test files
|
|
- ✅ 317/317 tests pass, 0 failing scripts
|
|
|
|
### Phase 19: Clojure Conformance Hardening ✅
|
|
|
|
Added `test/conformance.janet` — a harness that evaluates `(= expected actual)`
|
|
inside jolt (using jolt's own `=`, i.e. real Clojure semantics), seeded from
|
|
`~/src/clojure/test`. Drove fixes for a large class of real-Clojure idioms the
|
|
bespoke `.janet` suite never exercised. **80/80 conformance, 46/46 legacy suite,
|
|
0 SCI-load failures.**
|
|
|
|
CRITICAL (core semantics):
|
|
- Collections as IFn (`([v] i)`, `({m} k)`, `(#{s} x)`) via unified `jolt-invoke`
|
|
- Unified vector representation on Janet tuples (PersistentVector was broken/disconnected)
|
|
- `=`/`reduce`/`vec`/`into` now realize lazy-seqs; `into {}`/`into ()` fixed
|
|
- Lazy `iterate`/`range`(infinite)/single-coll `map` (over lazy input)
|
|
- Truly lazy `concat` → self-referential `lazy-cat`/`lazy-seq` work (`fib-seq`)
|
|
|
|
HIGH:
|
|
- Unified recursive destructuring (nested seq/map, `:strs`/`:syms`/`:or`/`:as`, fn-params)
|
|
- `defn` docstring/attr-map handling (docstring'd fns were silently param-less)
|
|
- Clojure `str`/`pr-str` (nil→"", keywords/symbols, collections render readably)
|
|
- `update`/`update-in`/`assoc-in` on immutable maps; multimethod `:default` key dispatch
|
|
- defrecord inline protocol methods with field scope
|
|
- `require` loads stdlib namespaces from disk + aliased-ns resolution (`s/join`)
|
|
|
|
MED:
|
|
- New: peek/pop/subvec/reduce-kv/cycle/partition-all/reductions/dedupe/
|
|
keep-indexed/map-indexed/trampoline/format/read-string/fnil + letfn/doseq macros
|
|
- Recursive `jolt-equal?` (nested sequential + order-independent map equality)
|
|
- Lazy `filter`/`take-while`/`remove` over lazy input
|
|
- REPL: lazy-seq printer walks full chain (capped); `def`/`defn` print `#'ns/name`
|
|
|
|
**Gap-closing batch** (conformance grew to 157 cases): full atoms; typed
|
|
volatiles + delays (deref/force/realized?); quot/rem/mod sign semantics; a regex
|
|
subsystem (`src/jolt/regex.janet`, regex→PEG, `#"..."` literals, re-find/matches/
|
|
seq, string split/replace); sorted-map/sorted-set; `Math/*` statics; ex-info/
|
|
ex-data/ex-message; namespaced keywords; ~40 added core fns (split-at, take-nth,
|
|
butlast, filterv/mapv, reduced, min/max-key, find, some-fn, sequential?/ifn?/…)
|
|
plus defonce/macroexpand-1/letfn/doseq; and fixes to doto, assoc/update-on-vector,
|
|
frequencies, coll?, sort, partition.
|
|
|
|
**Feature batch** (conformance now 184): proper **char type** (`\a` reads to a
|
|
char value, char?/char/int/str, string seq/first/nth yield chars, `\a` printing);
|
|
**transducers** (map/filter/take/… no-coll arity returns a transducer; transduce/
|
|
into-xform/sequence/eduction/reduced; reduce honors reduced); **compiler-path
|
|
IFn dispatch** (jolt-call makes collections callable in `:compile?` mode; compiled
|
|
set/char literals); and a **multi-line REPL** (accumulates until the form is
|
|
balanced).
|
|
|
|
Deferred: full regex (lookaround/backrefs — the PEG-backed engine covers the
|
|
common subset). STM (refs/agents/dosync) intentionally skipped.
|
|
|
|
### Phase 17: Optimization
|
|
|
|
- Compiler improvements: inline small core functions
|
|
- PersistentHashMap dynamic bucket growth
|
|
- Benchmarks
|
|
|
|
### Phase 18: Standard Library Completion
|
|
|
|
- Complete EDN reader/writer
|
|
- Complete java.io wrappers
|
|
- clojure.zip tests
|
|
|
|
## Implementation Order
|
|
|
|
1. ✅ Phases 0-16 (completed)
|
|
2. Phase 17 (optimization: compiler inlining, PHM bucket growth, benchmarks)
|
|
3. Phase 18 (stdlib: EDN reader/writer, java.io wrappers, clojure.zip tests)
|