fix: clojure test suite compatibility — 145/225 passing (64%)

Reader: #? reader conditionals with :default, #?@ splicing, char literals,
N/M suffix and ratio parsing, comma as whitespace, number parsing fix
for negative BigInt/Decimal/Ratio literals

Emitter: mangleName trailing/double underscore fixes, scope stack for
local var tracking, symbol-as-value emits cljSymbol() not bare identifier,
macro-expanded do-unwrap in processForm, emitBlock multiline wrap,
indentCode helper, when-var-exists emitter form, variadic apply fix,
fn proc spacing fix, def indent fix

Macros: deftest, is, testing, thrown?, are, when-var-exists builtins;
rewritten and/or using gensym; improved for/doseq/dotimes; cond->
and cond->> threading fixes; threading macro insert fixes

Runtime: sorted-map, sorted-set, sorted?, array-map, object-array,
hash-map, hash-set, inf, nan; assoc extended to vectors

Test runner: #?@ splice unwrapping, removed conflicting defmacro stubs
This commit is contained in:
2026-05-09 16:14:44 +03:00
parent a9ad83c509
commit e6859568b3
5 changed files with 615 additions and 265 deletions
+58 -3
View File
@@ -1,6 +1,6 @@
import cljnim_pvec
import cljnim_pmap
import strutils, sequtils, hashes, algorithm, os, osproc, locks
import strutils, sequtils, hashes, algorithm, os, osproc, locks, math
type
CljKind* = enum
@@ -79,6 +79,8 @@ proc cljBool*(v: bool): CljVal = CljVal(kind: ckBool, boolVal: v)
proc cljInt*(v: int64): CljVal = CljVal(kind: ckInt, intVal: v)
proc cljInt*(v: int): CljVal = CljVal(kind: ckInt, intVal: v.int64)
proc cljFloat*(v: float64): CljVal = CljVal(kind: ckFloat, floatVal: v)
proc cljInf*(args: seq[CljVal]): CljVal = CljVal(kind: ckFloat, floatVal: Inf)
proc cljNaN*(args: seq[CljVal]): CljVal = CljVal(kind: ckFloat, floatVal: NaN)
proc cljString*(v: string): CljVal = CljVal(kind: ckString, strVal: v)
proc cljKeyword*(v: string): CljVal = CljVal(kind: ckKeyword, kwName: v)
proc cljSymbol*(v: string): CljVal = CljVal(kind: ckSymbol, symName: v)
@@ -104,6 +106,20 @@ proc cljSet*(items: seq[CljVal]): CljVal =
s = pmapAssoc(s, item, true, hash(item), cljEq)
CljVal(kind: ckSet, setData: s)
proc cljHashMap*(args: seq[CljVal]): CljVal =
if args.len mod 2 != 0:
raise newException(CatchableError, "hash-map requires even number of arguments")
var m = newPersistentMap[CljVal, CljVal]()
for i in countup(0, args.len - 1, 2):
m = pmapAssoc(m, args[i], args[i+1], hash(args[i]), cljEq)
CljVal(kind: ckMap, mapData: m)
proc cljHashSet*(args: seq[CljVal]): CljVal =
var s = newPersistentMap[CljVal, bool]()
for item in args:
s = pmapAssoc(s, item, true, hash(item), cljEq)
CljVal(kind: ckSet, setData: s)
# ---- Display ----
proc cljRepr*(v: CljVal): string =
@@ -686,6 +702,30 @@ proc cljVec*(v: CljVal): CljVal =
of ckVector: v
else: cljVector(@[v])
proc cljObjectArray*(n: CljVal): CljVal =
var size = 0
if not n.isNil and n.kind == ckInt:
size = n.intVal.int
var items: seq[CljVal] = @[]
for i in 0..<size:
items.add(cljNil())
return cljList(items)
proc cljSortedMap*(args: seq[CljVal]): CljVal =
# Fallback to regular hash-map
cljHashMap(args)
proc cljSortedSet*(args: seq[CljVal]): CljVal =
# Fallback to regular hash-set
cljHashSet(args)
proc cljArrayMap*(args: seq[CljVal]): CljVal =
# Fallback to regular hash-map
cljHashMap(args)
proc cljSortedQ*(v: CljVal): CljVal =
cljBool(false)
proc cljEmpty*(v: CljVal): CljVal =
cljBool(cljCount(v).intVal == 0)
@@ -852,9 +892,24 @@ proc cljGetDefault*(m: CljVal, key: CljVal, default: CljVal): CljVal =
else: default
proc cljAssoc*(m: CljVal, key: CljVal, val: CljVal): CljVal =
if m.isNil or m.kind != ckMap:
if m.isNil or m.kind == ckNil:
return CljVal(kind: ckMap, mapData: pmapAssoc(newPersistentMap[CljVal, CljVal](), key, val, hash(key), cljEq))
CljVal(kind: ckMap, mapData: pmapAssoc(m.mapData, key, val, hash(key), cljEq))
case m.kind
of ckMap:
CljVal(kind: ckMap, mapData: pmapAssoc(m.mapData, key, val, hash(key), cljEq))
of ckVector:
if key.kind != ckInt:
raise newException(CatchableError, "assoc on vector requires integer index")
let idx = key.intVal
let cnt = m.vecData.count
if idx < 0 or idx > cnt:
raise newException(CatchableError, "Index out of bounds: " & $idx)
if idx == cnt:
CljVal(kind: ckVector, vecData: pvecConj(m.vecData, val))
else:
CljVal(kind: ckVector, vecData: pvecAssoc(m.vecData, idx, val))
else:
raise newException(CatchableError, "assoc expects a map or vector")
proc cljDissoc*(m: CljVal, key: CljVal): CljVal =
if m.isNil or m.kind != ckMap: return cljMap(@[], @[])