- resolve-macro: resolve symbols to macro vars via ctx - Macro expansion in analyze-form: detects macro heads, expands, re-analyzes - compile-ast: emits Janet data structures with resolved core fn values - compile-and-eval uses compile-ast (no source parse roundtrip) - eval-string routes macros through compiler (expanded at analyze time) - Fix - mapping: core-sub (core-- doesn't exist) - All 317 tests pass + 6 new Phase 4 macro tests
1.4 KiB
Janet eval scope & source-to-source failure: (eval '(core-inc 1)) fails with "unknown symbol core-inc" even when the file does (use ./core). Janet's eval runs in the default environment and doesn't see use-imported symbols. NEVER emit Janet source strings for eval. Instead emit Janet data structures where function VALUES are embedded directly: [core-inc 1] not "(core-inc 1)". Use a core-fn-values table to resolve names at compile time. The (parse s) function returns [symbol, error-position] — must use parser pipeline for proper eval: parser/new→consume→eof→produce→eval. Without parser/eof, numbers/literals return nil from produce. Janet's eval also doesn't support special forms natively in data structures — (eval [if true 1 2]) fails with "unknown symbol if". Must parse strings, not eval tuples.
§
When you need to mutate a local with set, use (var x nil) not (def x nil). def creates constants — (set ns-name ...) on a def fails with "cannot set constant". This hit us in loader.janet ns-name extraction loop.
§
core-renames MUST match actual function names defined in core.janet. "-" maps to core-sub NOT core--. "not" maps to core-not (defined as (defn core-not ...)). Missing entries cause silent nil returns. When adding to core-renames, grep core.janet for the actual (defn core-XXX ...) or (def core-XXX ...) name. Then add matching entry to core-fn-values.