- loader.janet: load-ns with compile? dispatch, compiled-cache, compiled?, clear-compiled-cache
- compiler.janet: compile-ast (Janet data structures for direct eval), compile-and-eval
- api.janet: compile-string, compile-file, eval-string dispatches to compile-and-eval when :compile? is true
- types.janet: :compile? flag and :compiled-cache table in context env
- Stateful forms (def, defmacro, ns, deftype, defmulti, defmethod) fall back to interpreter
- All 317 tests pass + 16 new Phase 3 tests
Root cause of HAMT failure: Janet uses 64-bit doubles, bit operations
require 32-bit signed ints. Hash values from Janet exceed this range.
Solution: Replaced bit-trie HAMT with simple array-based implementation:
- find-key-index: linear scan for key lookup
- node-assoc: append-to-array on insert, clone+update on replace
- node-find: linear scan for value retrieval
All operations work correctly:
(hash-map :a 1) → {:root [:a 1], :count 1}
(hash-map :a 1 :b 2) → {:root [:a 1 :b 2], :count 2}
phm-assoc / phm-get / phm-count all verified
O(n) lookup (acceptable for small maps). HAMT can be reintroduced
once Janet gets proper 32-bit int support or we implement bit ops
in pure Janet.
Root cause of bmn-assoc failure: < operator missing from core-bindings.
All loop conditions in HAMT hash map use (< i idx) which silently
failed, causing loops to return nil. Added core-<, core->, core-<=,
core->= bound to Janet's <, >, <=, >=.
Also removed leftover test files from debugging session.
Add binding-get helper that walks Janet table prototype chain.
resolve-sym now uses two-stage lookup: direct get first,
then prototype walk as fallback. This fixes access to outer
let bindings from inner let forms without breaking fn parameter
resolution (which uses direct table keys).
All 9 test suites pass including macro-test.
Added 22 new clojure.core bindings needed to implement persistent
data structures as Clojure source files:
Array operations: alength, aget, aset, aclone, object-array, int-array,
to-array (host interop for trie arrays)
Bit operations: bit-and, bit-or, bit-xor, bit-not, bit-shift-left,
bit-shift-right, unsigned-bit-shift-right (for 32-way trie indexing)
Integer ops: int (trunc), unchecked-inc/dec/add/subtract
Other: hash, namespace, set! support for (set! (. obj -field) val)
instance? support for deftype types via :jolt/deftype tag
All 9 test suites pass. 317/317 SCI forms load.
- Add SCI as git submodule at vendor/sci (replaces absolute path)
- Fix defrecord macro: emit array-map at expansion time, no interleave dep
- Remove stale test files (test-ctor, test-parser, edamame_shim)
- All 317 SCI forms load with 0 failures, 9 test suites green
Replace SCI's internal interpreter/parser/analyzer pipeline with
Jolt-native eval-string that delegates to Jolt's reader and evaluator.
All 317 SCI source forms load, 9 namespaces populated, 46 total ns.
eval-string result: (+ 1 2 3) → 6, (def x 42) x → 42
Removed edamame/core shim — no longer needed since we bypass
the SCI internal eval pipeline entirely.
Add edamame.core + clojure.tools.reader.reader-types shim to core.janet.
init-edamame-shim! takes parse-string and read-form as args to avoid
circular module dependencies. Creates shim namespaces after SCI loads.
SCI eval-string is found and callable — next step is loading the 4
internal namespaces (interpreter, parser, analyzer, opts) whose source
files aren't loaded by the ns :require handler.
Janet's (put table key nil) silently drops the key. This caused
nil-valued fn/let/loop/macro parameters to be invisible to resolve-sym,
making them fall through to global symbol resolution.
Added bind-put helper that uses :jolt/nil sentinel for nil values,
and resolve-sym unwraps it back to nil.