- analyze-form: Clojure forms → annotated AST nodes (:op keys) - emit-ast: AST dispatch → Janet source via StringBuffer - compile-form: analyze → emit → Janet source string - Symbol classification: locals, core refs, qualified refs - Ops: const, do, if, def, fn, let, invoke, quote, vector, map - Local binding awareness in fn* and let* (shadowing works) - All 317 existing tests pass, 24 new compiler tests
2 KiB
Compiler implementation plan (6 phases): Phase 1 — compiler.janet skeleton + emit* for const/do/if/let/fn/def/invoke. Phase 2 — symbol classifier (resolve locals/vars/core at analyze time). Phase 3 — loader.janet + api.janet wiring (:compile? flag, load-ns, caching). Phase 4 — macro integration (expand at analyze time via interpreter). Phase 5 — remaining ops (loop/recur, try/throw, quote, syntax-quote, set!, deftype, .). Phase 6 — tests + benchmarks. New files: src/jolt/compiler.janet, src/jolt/loader.janet, test/compiler-test.janet. Modified files: evaluator.janet (compiler fast-path), types.janet (compiled-cache table), api.janet (compile-string, load-ns). Reader and core unchanged.
§
Compiler is in src/jolt/compiler.janet (352 lines). Two-phase architecture: analyze-form produces annotated AST with :op keys, emit-ast dispatches on :op to emit Janet source, compile-form ties them together returning a Janet source string. Source-to-source (not bytecode). core-renames table maps Clojure core names to Janet function names (e.g., "inc" → "core-inc"). Phase 1 covers: const, do, if, def, fn*, let*, invoke, symbol, core-symbol, qualified-symbol, quote, vector, map. Tests in test/compiler-test.janet (79 lines). Phase 2 (symbol classification — locals/vars/core at analyze time) is the next step.
§
After compiler Phase 1: 317 tests pass, 0 failures (was 253 before). Compiler tests add 8 test groups (literals, do, if, def, fn, let, invoke — 19 assertions). Run with jpm test.
§
Compiler development workflow: (1) add match arm in analyze-form → produces {:op :new-op ...} AST, (2) add emit-* helper + dispatch arm in emit-ast, (3) add test assertions in test/compiler-test.janet using compile-str helper, (4) run janet test/compiler-test.janet then jpm test. Tests compare source-to-source output strings, not execution results. Any fn added to core-bindings in core.janet must also be added to core-renames in compiler.janet.