jolt/.dirge/memory/MEMORY.md
Yogthos 979486600a fix: persistent hash map — working with simple array implementation
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.
2026-06-02 13:25:20 -04:00

2 KiB

and/or macros: (and x y)(let* [and__x x] (if and__x (and y) and__x)). (or x y)(let* [or__x x] (if or__x or__x (or y))). Registered as macros in core-macro-names. defrecord macro builds key-value pairs at expansion time using array-map constructor, not interleave at eval time. § SCI added as git submodule at vendor/sci (https://github.com/borkdude/sci.git). Clone with git submodule update --init. 317/317 forms load from 9 core files. Internal namespaces (interop, parser, opts) partially loaded — parser.cljc needs utils/new-var (calls sci.lang.Var. constructor) and edamame/normalize-opts stubs. § :mutable? compile flag in api.janet init: persistent Clojure data structures loaded by default. Pass {:mutable? true} to use Janet native mutable tuples/tables instead. load-persistent-structures function in api.janet loads src/jolt/clojure/lang/persistent_vector.clj (17 forms) and swaps vec/vector/vector? bindings in clojure.core. PersistentHashMap WIP in src/jolt/clojure/lang/persistent_hash_map.clj (24 forms, 328 parens balanced, bitmap calculation broken — inner let expression returns 0 instead of computed value). § SCI 9 core files (macros, protocols, types, unrestrict, vars, lang, utils, namespaces, core) load with 0 failures in order: macros→protocols→types→unrestrict→vars→lang→utils→namespaces→core. 46 namespaces populated. Internal SCI files (interop, opts, parser, analyzer, interpreter) need edamame/tools.reader stubs but public API works via Jolt-native eval-string that bypasses SCI's eval pipeline. § Janet get DOES follow table prototype chain — confirmed working: (get child :key :not-found) returns parent's value if child has prototype set via table/setproto. Earlier confusion about get not following prototypes was incorrect. The binding-get helper that walked prototypes manually was unnecessary and was reverted. Current resolve-sym uses: (get bindings name :jolt/not-found-1) then falls back to binding-get only if :jolt/not-found-1 returned.