jolt/.dirge/memory/MEMORY.md
Yogthos fe22fea3e4 Phase 7: LazySeq + PersistentHashSet completion
- phm.janet: LazySeq (realize-once with caching, ls-first/ls-rest/ls-seq/ls-count)
  PersistentHashSet (backed by PHM, phs-conj/phs-disj/phs-contains?/phs-count/...)
  make-lazy-seq creates lazy thunk wrapper with :jolt/lazy-seq type tag
  make-phs creates hash set with :jolt/set type tag
- evaluator.janet: :jolt/set handler in eval-form, disj/set? special forms,
  special-symbol? entries, phm import for compile-time visibility
- core.janet: lazy-seq/iterate macros, set?/disj core fns, make-phs wired
  into hash-set, core-bindings entries for set?/disj/lazy-seq/make-lazy-seq/iterate
  Set support in core-conj/core-contains?/core-count/core-empty?/core-seq/core-get
  LazySeq support in core-first/core-rest/core-count/core-seq
- 9 tests (32-33): lazy-seq basic ops, realize-once caching
  PersistentHashSet construction, conj, disj, count, set? predicate
- 315 ok, 2 fail (pre-existing, unchanged)
2026-06-02 23:24:55 -04:00

18 lines
2.1 KiB
Markdown

Jolt Compiler Architecture (Phases 1-6, dfa9874→1de109f): Two-phase — analyze-form (Clojure form → annotated AST) → emit-ast (→ Janet source string) or emit-expr (→ Janet data structures for eval). analyze-form takes [form bindings &opt ctx]; ctx needed for macro expansion. Symbol classification: bindings first (:local), then core-renames (:core-symbol), then plain (:symbol). Two emitter paths: string (compile-form) and data structures (compile-ast). Core fn values resolved via core-fn-values table. compile-and-eval takes [form ctx]; pass nil for no macro ctx.
Key naming/facts:
- Clojure - → core-sub (NOT core--)
- core-nth did not exist — had to add both the function and core-bindings entry
- Missing from core-renames early: fn?, list, name, subs
- Bare tuples in Janet eval → treated as function calls. Always emit (tuple ...) or ['tuple ...]
- make-symbol: / at position 0 means unqualified symbol (was parsing empty ns)
- raw-form->janet converter for quote: don't re-analyze quoted forms, pass through verbatim
- emit-try-expr: Janet format is (try body ([err] handler)) not (try body (catch sym handler))
- Loop compilation: (do (var _loop_N nil) (set _loop_N (fn [params] body)) (_loop_N init-vals...))
- Recur compilation: rewrites to (loop-name arg1 arg2...) via :loop-name in AST
eval-string dispatch: When :compile? true, stateful forms (defmacro, ns, deftype, defmulti, defmethod, require, in-ns) use interpreter. All others (def, macros like defn) go through compile-and-eval. Macros expanded at analyze time via resolve-macro.
Remaining: syntax-quote, set! compiler support. deftype/defmulti/defmethod routed to interpreter.
§
Janet gotchas: (1) `parse` returns `[form, consumed-count]`, NOT `[form, error?]` — use parser/new→consume→eof→produce pipeline. (2) `:#inst` is invalid keyword literal — use `(keyword "#inst")` dynamically. (3) Janet `case` works for multi-arity simulation when `defn ([] body) ([x] body)` fails. (4) Bare tuples in eval are function calls — always use `['tuple ...]`. (5) Core `-` maps to `core-sub` NOT `core--`.