diff --git a/.dirge/memory/MEMORY.md b/.dirge/memory/MEMORY.md index 40b1a3d..921f161 100644 --- a/.dirge/memory/MEMORY.md +++ b/.dirge/memory/MEMORY.md @@ -1,7 +1,5 @@ REPL print-value uses buffer-based output: write-value/v buf appends formatted strings via buffer/push-string, then print-value creates buffer, builds string, and does a single (print (string buf)). This prevents Janet C runtime from interleaving native output between prin statements in jpm build executables. Cond catch-all must use true clause: Janet's cond treats plain expressions as tests, so (push-str buf (string v)) at end of cond would be evaluated as a test — need true before it. § -Post-Phase 11: 316 passing, 1 fail (pre-existing array/table/buffer in SCI lang.cljc, deferred to Phase 15). 7,800+ lines across ~20 source/test files. 9 .clj stdlib modules (clojure/string.clj, set.clj, walk.clj, zip.clj, edn.clj, java_io.clj; jolt/interop.clj, shell.clj, http.clj). 85 CLJS-ported assertions. SCI stub file at src/jolt/clojure/sci/lang_stubs.clj provides 5 protocols + 3 deftypes. 24 test files. All builds/runs via `jpm test`. -§ -Project stats after Phase 12: 7,800+ lines across 30+ source/test files. Key sources: compiler.janet (848 lines), evaluator.janet (869 lines), core.janet (1387 lines), types.janet (441 lines), reader.janet (472 lines), phm.janet (199 lines), main.janet (125 lines), api.janet (93 lines), loader.janet (79 lines). Test suite: 316 ok, 1 fail (pre-existing deftype in lang.cljc). 17 CLJS-ported test files + 6 custom test files. 9 .clj standard library modules under src/jolt/clojure/ and src/jolt/jolt/. All builds/runs via `jpm test`. +Post-Phase 13: 316/317 passing, 1 fail (pre-existing deftype in SCI lang.cljc, deferred to Phase 15). 8,000+ lines across ~25 source/test files. Key sources: compiler.janet (848), evaluator.janet (877), core.janet (1387), types.janet (441), reader.janet (500), phm.janet (199). 9 .clj stdlib modules (clojure/string.clj, set.clj, walk.clj, zip.clj, edn.clj, java_io.clj; jolt/interop.clj, shell.clj, http.clj). SCI stub file at src/jolt/clojure/sci/lang_stubs.clj provides 5 protocols + 3 deftypes. ~25 test files with 850+ assertions. CLJS-ported tests: 6 files, 27 sections, ~120 assertions. All builds/runs via `jpm test`. § Protocol system: Type registry in context env (:type-registry) maps type-tag→proto-name→method-name→fn. Three dispatch special forms: protocol-dispatch (resolves method via registry or reified methods), register-method (stores impl in registry), make-reified (creates anonymous object with :jolt/protocol-methods). fn* forms emitted by extend-type/extend-protocol MUST be @[...] (array) for eval-list dispatch. Protocols are maps with :jolt/type :jolt/protocol and :methods map. diff --git a/.dirge/memory/PITFALLS.md b/.dirge/memory/PITFALLS.md index b358708..e0a92b9 100644 --- a/.dirge/memory/PITFALLS.md +++ b/.dirge/memory/PITFALLS.md @@ -1,5 +1,3 @@ Janet `and` returns last truthy value, not boolean. `(and table? deftype)` returns the deftype string, not true. Predicate-like functions (core-map?, core-contains?, etc.) that check type tags via `(and ...)` must wrap in `(if ... true false)`. Hit us with core-map? returning the deftype string instead of boolean true for record instances. Also hit type-satisfies? which had to replace `(boolean ...)` (nonexistent) with `(if ... true false)`. § -Janet `and` returns last truthy value, not boolean. `(and table? deftype)` returns the deftype string, not true. Predicate-like functions (core-map?, core-contains?, etc.) that check type tags via `(and ...)` must wrap in `(if ... true false)`. Examples: core-map? returning deftype string instead of boolean true for record instances. Also applies to type-satisfies? which must use `(if (and ...) true false)` — Janet has no `boolean` function. -§ Clojure .clj source files loaded via eval-form cannot have docstrings. If a defn form has 5 elements (defn, name, docstring, params, body), the evaluator's defn macro handler gets 4 args instead of 3, breaking with "macro arity mismatch". All .clj files in src/jolt/clojure/ must use 4-element defn forms: (defn name [params] body). Docstrings on defn are a Clojure feature not supported by Jolt's defn macro. diff --git a/.dirge/skills/.usage.json b/.dirge/skills/.usage.json index 3148d95..26717af 100644 --- a/.dirge/skills/.usage.json +++ b/.dirge/skills/.usage.json @@ -1,23 +1,23 @@ { - "jolt-gotchas": { + "jolt-dev": { "created_by": "agent", - "use_count": 4, - "view_count": 256, - "patch_count": 4, - "last_used_at": "2026-06-03T16:12:06.850822+00:00", - "last_viewed_at": "2026-06-03T17:19:39.580796+00:00", - "last_patched_at": "2026-06-03T16:12:23.546648+00:00", - "created_at": "2026-06-03T03:50:41.474730+00:00", + "use_count": 41, + "view_count": 342, + "patch_count": 48, + "last_used_at": "2026-06-03T17:22:40.281198+00:00", + "last_viewed_at": "2026-06-03T21:12:16.003609+00:00", + "last_patched_at": "2026-06-03T17:02:24.207040+00:00", + "created_at": "2026-06-01T21:26:06.614465+00:00", "state": "active", "pinned": false }, "jolt-bootstrap": { "created_by": "agent", "use_count": 9, - "view_count": 277, + "view_count": 310, "patch_count": 10, "last_used_at": "2026-06-02T18:45:23.336653+00:00", - "last_viewed_at": "2026-06-03T17:19:39.564734+00:00", + "last_viewed_at": "2026-06-03T21:12:15.990953+00:00", "last_patched_at": "2026-06-02T03:44:45.935676+00:00", "created_at": "2026-06-01T21:49:51.101718+00:00", "state": "active", @@ -26,20 +26,32 @@ "jolt-persistent-structures": { "created_by": "agent", "use_count": 3, - "view_count": 256, + "view_count": 289, "patch_count": 0, "last_used_at": "2026-06-03T16:13:31.440242+00:00", - "last_viewed_at": "2026-06-03T17:19:39.585778+00:00", + "last_viewed_at": "2026-06-03T21:12:16.015079+00:00", "created_at": "2026-06-03T03:35:04.130959+00:00", "state": "active", "pinned": false }, + "jolt-gotchas": { + "created_by": "agent", + "use_count": 5, + "view_count": 290, + "patch_count": 4, + "last_used_at": "2026-06-03T17:22:40.328839+00:00", + "last_viewed_at": "2026-06-03T21:12:16.009503+00:00", + "last_patched_at": "2026-06-03T16:12:23.546648+00:00", + "created_at": "2026-06-03T03:50:41.474730+00:00", + "state": "active", + "pinned": false + }, "jpm-build": { "created_by": "agent", "use_count": 0, - "view_count": 268, + "view_count": 301, "patch_count": 0, - "last_viewed_at": "2026-06-03T17:19:39.591024+00:00", + "last_viewed_at": "2026-06-03T21:12:16.020749+00:00", "created_at": "2026-06-01T20:56:39.144222+00:00", "state": "active", "pinned": false @@ -47,25 +59,13 @@ "jolt-compiler": { "created_by": "agent", "use_count": 12, - "view_count": 269, + "view_count": 302, "patch_count": 10, "last_used_at": "2026-06-03T16:35:41.304993+00:00", - "last_viewed_at": "2026-06-03T17:19:39.570381+00:00", + "last_viewed_at": "2026-06-03T21:12:15.997462+00:00", "last_patched_at": "2026-06-03T16:13:25.725903+00:00", "created_at": "2026-06-02T17:54:38.690279+00:00", "state": "active", "pinned": false - }, - "jolt-dev": { - "created_by": "agent", - "use_count": 40, - "view_count": 308, - "patch_count": 48, - "last_used_at": "2026-06-03T17:02:10.695363+00:00", - "last_viewed_at": "2026-06-03T17:19:39.575770+00:00", - "last_patched_at": "2026-06-03T17:02:24.207040+00:00", - "created_at": "2026-06-01T21:26:06.614465+00:00", - "state": "active", - "pinned": false } } \ No newline at end of file diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..a57a355 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,102 @@ +# 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 | 316 | +| Failing | 1 (lang.cljc deftype — deferred to Phase 15) | +| CLJS test files ported | ~15/60 | +| Total assertions | 860+ across 24 test files | +| Source lines | ~5,600 (7 core .janet files) | + +## 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 + +- Complete `sci.lang` namespace with Var type +- Load remaining SCI namespaces +- SCI test runner +- Fix SciVar `#?@` deftype issue + +### Phase 16: Remaining Core Library + Tests + +- Port ~20 remaining CLJS test files +- Fix found gaps: `&` rest destructuring, `seq` nil handling, vector/list equality +- `eval`, `syntax-quote` completion + +### 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-14 (completed) +2. Phase 15 (SCI bootstrap) — **critical path** +3. Phase 16 (remaining test porting + feature gaps) +4. Phases 17-18 (optimization, stdlib) diff --git a/src/jolt/compiler.janet b/src/jolt/compiler.janet index 761e4db..c25e0b9 100644 --- a/src/jolt/compiler.janet +++ b/src/jolt/compiler.janet @@ -218,7 +218,7 @@ (put t "core-mod" core-mod) (put t "core-apply" apply) (put t "core-some" core-some?) - (put t "core-pr-str" core-str) + (put t "core-pr-str" core-pr-str) (put t "core-nth" core-nth) (put t "core-list" core-list) (put t "core-name" core-name) diff --git a/test/cljs-port-5.janet b/test/cljs-port-5.janet index acf7b87..3e2b875 100644 --- a/test/cljs-port-5.janet +++ b/test/cljs-port-5.janet @@ -8,14 +8,15 @@ (print " ok") (print "23: metadata...") (let [ctx (init)] - (ct-eval ctx "(def ^:dynamic *dyn5* 42)") - (assert (= true (ct-eval ctx "(var-dynamic? (var *dyn5*))")) "dynamic metadata") + (ct-eval ctx "(def ^:dynamic *dyn* 42)") + (assert (= true (ct-eval ctx "(var-dynamic? (var *dyn*))")) "dynamic metadata") (assert (= 1 (ct-eval ctx "(:a (with-meta {:a 1} {:c 3}))")) "with-meta preserves")) (print " ok") (print "24: function composition...") (let [ctx (init)] (assert (= true (ct-eval ctx "((complement odd?) 2)")) "complement") (assert (= 5 (ct-eval ctx "((constantly 5) :anything)")) "constantly") - (assert (= true (ct-eval ctx "((every-pred number? even?) 4)")) "every-pred true")) + (assert (= true (ct-eval ctx "((every-pred number? even?) 4)")) "every-pred") + (assert (= ":hello" (ct-eval ctx "(pr-str :hello)")) "pr-str keyword")) (print " ok") (print "\nAll CLJS Ported Part 5 tests passed!")