fix: threading macros, REPL stability, and CI coverage

- fix(emitter): emitFnWrapper now uses runtimeName for builtin operators
- fix(emitter): map/reduce handlers support variadic runtime functions (+, -, etc.)
- fix(emitter): variadic runtime functions list extracted to variadicRuntimeFns constant
- fix(macros): restore correct thread-first behavior (->) and fix result shadowing
- fix(macros): and/or/as->/some->/some->> macro result variable fixes
- fix(repl): add macroexpand step before interpreter eval
- fix(runtime): cljReduceSeq handles nil init (uses first coll element)
- fix(eval): add macroexpand/macroexpand-1 special forms to interpreter
- fix(eval): add macros module import for macroexpand access
- fix(warnings): eliminate ResultShadowed and UnusedImport warnings
- chore(.gitignore): remove artifact entries (-o, =0.4.0), unignore lib/bring_http.nim
- chore(ci): run all examples + threading macro + macroexpand REPL smoke tests
This commit is contained in:
2026-05-12 20:02:58 +03:00
parent 014a192c5d
commit 4b208dbe55
8 changed files with 136 additions and 83 deletions
+28 -28
View File
@@ -149,20 +149,20 @@ proc initMacros*() =
defineMacro("and", proc(args: seq[CljVal]): CljVal =
if args.len == 0: return cljBool(true)
if args.len == 1: return args[0]
var result = args[^1]
var acc = args[^1]
for i in countdown(args.len - 2, 0):
result = cljList(@[cljSymbol("if"), args[i], result, cljBool(false)])
return result
acc = cljList(@[cljSymbol("if"), args[i], acc, cljBool(false)])
return acc
)
# or
defineMacro("or", proc(args: seq[CljVal]): CljVal =
if args.len == 0: return cljNil()
if args.len == 1: return args[0]
var result = args[^1]
var acc = args[^1]
for i in countdown(args.len - 2, 0):
result = cljList(@[cljSymbol("if"), args[i], args[i], result])
return result
acc = cljList(@[cljSymbol("if"), args[i], args[i], acc])
return acc
)
# when-let
@@ -242,22 +242,22 @@ proc initMacros*() =
let clauses = args[1..^1]
if clauses.len mod 2 != 0:
raise newException(CatchableError, "cond-> requires pairs of test/expr")
var result = init
var acc = init
for i in 0..<(clauses.len div 2):
let test = clauses[i * 2]
let expr = clauses[i * 2 + 1]
let gs = cljSymbol(gensymName("ct_"))
if expr.kind == ckList and expr.items.len > 0:
result = cljList(@[cljSymbol("let"), cljVector(@[gs, result]),
acc = cljList(@[cljSymbol("let"), cljVector(@[gs, acc]),
cljList(@[cljSymbol("if"), test,
cljList(@[expr.items[0], gs] & expr.items[1..^1]),
gs])])
else:
result = cljList(@[cljSymbol("let"), cljVector(@[gs, result]),
acc = cljList(@[cljSymbol("let"), cljVector(@[gs, acc]),
cljList(@[cljSymbol("if"), test,
cljList(@[expr, gs]),
gs])])
return result
return acc
)
# cond->>
@@ -268,22 +268,22 @@ proc initMacros*() =
let clauses = args[1..^1]
if clauses.len mod 2 != 0:
raise newException(CatchableError, "cond->> requires pairs of test/expr")
var result = init
var acc = init
for i in 0..<(clauses.len div 2):
let test = clauses[i * 2]
let expr = clauses[i * 2 + 1]
let gs = cljSymbol(gensymName("ct_"))
if expr.kind == ckList and expr.items.len > 0:
result = cljList(@[cljSymbol("let"), cljVector(@[gs, result]),
acc = cljList(@[cljSymbol("let"), cljVector(@[gs, acc]),
cljList(@[cljSymbol("if"), test,
cljList(expr.items & @[gs]),
gs])])
else:
result = cljList(@[cljSymbol("let"), cljVector(@[gs, result]),
acc = cljList(@[cljSymbol("let"), cljVector(@[gs, acc]),
cljList(@[cljSymbol("if"), test,
cljList(@[expr, gs]),
gs])])
return result
return acc
)
# doto
@@ -312,10 +312,10 @@ proc initMacros*() =
let init = args[0]
let name = args[1]
let body = args[2..^1]
var result = init
var acc = init
for form in body:
result = cljList(@[cljSymbol("let"), cljVector(@[name, result]), form])
return result
acc = cljList(@[cljSymbol("let"), cljVector(@[name, acc]), form])
return acc
)
# some->
@@ -324,21 +324,21 @@ proc initMacros*() =
raise newException(CatchableError, "some-> requires initial value and body")
let init = args[0]
let body = args[1..^1]
var result = init
var acc = init
for form in body:
let gs = cljSymbol(gensymName("st_"))
let nilCheck = cljList(@[cljSymbol("nil?"), gs])
if form.kind == ckList and form.items.len > 0:
result = cljList(@[cljSymbol("let"), cljVector(@[gs, result]),
acc = cljList(@[cljSymbol("let"), cljVector(@[gs, acc]),
cljList(@[cljSymbol("if"), nilCheck,
cljNil(),
cljList(@[form.items[0], gs] & form.items[1..^1])])])
else:
result = cljList(@[cljSymbol("let"), cljVector(@[gs, result]),
acc = cljList(@[cljSymbol("let"), cljVector(@[gs, acc]),
cljList(@[cljSymbol("if"), nilCheck,
cljNil(),
cljList(@[form, gs])])])
return result
return acc
)
# some->>
@@ -347,20 +347,20 @@ proc initMacros*() =
raise newException(CatchableError, "some->> requires initial value and body")
let init = args[0]
let body = args[1..^1]
var result = init
var acc = init
for form in body:
let gs = cljSymbol(gensymName("st_"))
if form.kind == ckList and form.items.len > 0:
result = cljList(@[cljSymbol("let"), cljVector(@[gs, result]),
acc = cljList(@[cljSymbol("let"), cljVector(@[gs, acc]),
cljList(@[cljSymbol("if"), gs,
cljList(form.items & @[gs]),
cljNil()])])
else:
result = cljList(@[cljSymbol("let"), cljVector(@[gs, result]),
acc = cljList(@[cljSymbol("let"), cljVector(@[gs, acc]),
cljList(@[cljSymbol("if"), gs,
cljList(@[form, gs]),
cljNil()])])
return result
return acc
)
# for
@@ -465,11 +465,11 @@ proc initMacros*() =
let loopBody = cljList(@[cljSymbol("when"), name] & innerBody & @[recurForm])
return cljList(@[cljSymbol("loop"), cljVector(@[name, cljList(@[cljSymbol("first"), seqColl]), gs, cljList(@[cljSymbol("next"), seqColl])]), loopBody])
var result = makeLoop(pairs[^1][0], pairs[^1][1], inner)
var acc = makeLoop(pairs[^1][0], pairs[^1][1], inner)
for j in countdown(pairs.len - 2, 0):
let innerSeq = @[result]
result = makeLoop(pairs[j][0], pairs[j][1], innerSeq)
return result
acc = makeLoop(pairs[j][0], pairs[j][1], innerSeq)
return acc
)
# dotimes