fix: 18 bugs across interpreter, reader, emitter, and runtime

- cljMinMax now handles float and mixed int/float arguments
- cljType* covers ckSet, ckTransient, ckAgent
- cljConj and cljVec return vectors instead of lists
- rem uses truncated division semantics (matches Clojure)
- range with negative step terminates correctly
- reduce of empty collection with no init errors instead of returning nil
- swap! extra args flatten correctly
- remove duplicate not definition (dead code)
- ratio literals (1/5) parse correctly
- scientific notation uses correct variable (numTok not tok)
- readSet returns proper set value instead of (set [...]) form
- TCP REPL catches specific exceptions instead of bare except
- initBuiltinMacros guards against duplicate registration
- doseq :while clause no longer generates dead code or infinite loop
- emitter resets all global state on each emitProgram call
- pushLeaf fills gaps with internal nodes instead of nil children

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 12:25:53 +03:00
parent 7cb8aa1ee0
commit 11fca52282
7 changed files with 91 additions and 42 deletions
+9 -7
View File
@@ -428,8 +428,7 @@ proc initMacros*() =
if whileExpr != nil:
let gs = cljSymbol(gensymName("dw_"))
b = @[cljList(@[cljSymbol("loop"), cljVector(@[gs, cljBool(true)]),
cljList(@[cljSymbol("when"), whileExpr] & b & @[cljList(@[cljSymbol("recur"), gs])]),
cljList(@[cljSymbol("when"), cljBool(false), cljNil()])])]
cljList(@[cljSymbol("when"), whileExpr] & b & @[cljList(@[cljSymbol("recur"), gs])])])]
return cljList(@[cljSymbol("do")] & b)
# Build nested doseq for multiple pairs, innermost gets the body with modifiers
@@ -438,11 +437,10 @@ proc initMacros*() =
inner = @[cljList(@[cljSymbol("let"), cljVector(letBinds)] & inner)]
if whenExpr != nil:
inner = @[cljList(@[cljSymbol("when"), whenExpr] & inner)]
if whileExpr != nil:
let gs = cljSymbol(gensymName("dw_"))
inner = @[cljList(@[cljSymbol("loop"), cljVector(@[gs, cljBool(true)]),
cljList(@[cljSymbol("when"), whileExpr] & inner & @[cljList(@[cljSymbol("recur"), gs])]),
cljList(@[cljSymbol("when"), cljBool(false), cljNil()])])]
if whileExpr != nil:
let gs = cljSymbol(gensymName("dw_"))
inner = @[cljList(@[cljSymbol("loop"), cljVector(@[gs, cljBool(true)]),
cljList(@[cljSymbol("when"), whileExpr] & inner & @[cljList(@[cljSymbol("recur"), gs])])])]
proc makeLoop(name: CljVal, coll: CljVal, innerBody: seq[CljVal]): CljVal =
if name.kind == ckVector:
@@ -606,5 +604,9 @@ proc initMacros*() =
return cljList(@[cljSymbol("do")] & body)
)
var macrosInitialized = false
proc initBuiltinMacros*() =
if macrosInitialized: return
initMacros()
macrosInitialized = true