Files
bara-lang/PLAN.md
T
dimgigov 281fd2e00b docs: update plan — 230/233 (98.7%), roadmap to 100%
- Documented 3 remaining failures with root causes
- Roadmap: Phase A (closure scoping), Phase B (multi-file), Phase C (symbol emit)
2026-05-11 03:47:05 +03:00

3.6 KiB

Clojure/Nim — Test Suite Compliance Plan

Current Status: 230/233 (98.7%)

Component Pass Total %
clojure.string 8 8 100%
clojure.core 222 225 98.7%
Total 230 233 98.7%

Unit Tests: 78/80 (97.5%)

Status Test Issue
78 tests All passing
emit symbol Returns cljSymbol("x") instead of raw "x"
emit mangled symbol Same — symbol emit returns data instead of name

3 Remaining Compliance Failures

1. not_eq — Cross-namespace dependency

  • Error: undeclared identifier: 'eq_SLASH_tests'
  • Cause: Test calls (eq/tests (complement not=)) where eq/tests is a function defined in clojure.core-test.eq namespace (separate file). Our compiler processes each test file independently — it doesn't load required namespaces.
  • Fix needed: Multi-file compilation — ns :require should inline/compile required files and make their functions available.

2. add_watch — Closure scoping with fn params

  • Error: undeclared identifier: 'ref1'
  • Cause: The test defines functions like (fn [key ref old new] ...) where ref gets mangled to ref1. These fn params are used inside deeply nested closures (try/catch inside fn inside testing block). The IIFE wrapping by emitBlock creates scope boundaries that prevent fn params from being visible in inner closures.
  • Fix needed: IIFE-wrapped closures must capture enclosing scope variables. Either stop wrapping non-last forms in IIFEs, or use Nim closures that properly capture outer variables.

3. remove_watch — Same closure scoping issue

  • Error: undeclared identifier: 'ref1'
  • Cause: Same as add_watch — fn params not visible across IIFE boundaries.
  • Fix needed: Same as add_watch.

Roadmap to 100%

Phase A: Closure Scoping Fix (fixes add_watch + remove_watch)

  • Approach: Instead of wrapping non-last forms in discard ((proc(): CljVal = ...)()), emit them as direct statements. The IIFE wrapping was added to handle multi-line expressions as non-last forms, but it breaks variable scoping.
  • Alternative: Use Nim's {.inline.} procs or block: labels instead of IIFEs for scope isolation.
  • Impact: +2 tests (232/233)

Phase B: Multi-file Compilation (fixes not_eq)

  • Approach: When ns :require encounters a namespace, find and compile the corresponding .cljc/.clj file, inline its top-level defs into the current compilation unit.
  • Key files: src/cljnim.nim (file resolution), src/emitter.nim (ns handler)
  • Impact: +1 test (233/233)

Phase C: Symbol Emit Fix (fixes 2 unit tests)

  • Approach: When emitting a bare symbol that's not a local var and not a runtime function, check if it was defined as a def/defn in the current compilation unit. If so, emit the mangled name directly instead of cljSymbol(...).
  • Impact: +2 unit tests (80/80)

Session Log

2026-05-11 (late session) — Bulk fixes

  • Reader: prefer :default over :clj in conditionals
  • Emitter: cond, definterface, new special forms
  • Emitter: ns alias registration, when discard, try/catch scope + type mapping
  • Emitter: emitBlock var hoisting out of IIFEs
  • Emitter: removed all DEBUG stderr output
  • Runtime: random-uuid, System/getProperty, vreset!, restart-agent, require/eval/resolve stubs
  • Runtime: Boolean/Object/Integer constructors
  • Runtime: seq overloads for cljAssoc, cljDissoc, cljGet, cljExInfo, cljTransduce
  • Result: 220/233 → 230/233 compliance, 77/80 → 78/80 unit tests