Phase 5: HAMT Persistent Vector + CI fixes
- Add lib/cljnim_pvec.nim: 32-way HAMT Persistent Vector with structural sharing - Migrate ckVector from seq[CljVal] to PersistentVector[CljVal] in runtime - Fix recursive pushLeaf bug (nil nodes at depth > 2) - Fix defn/if return value bug: replace discard with result = in proc bodies - Fix cljNth to accept CljVal index - Add len and [] overloads for PersistentVector seq compatibility - Add tests/test_pvec.nim (14 tests) - Update .gitlab-ci.yml to nim:2.2.10 and add test_pvec - Update docs/ROADMAP.md and add PHASE5_HAMT.md
This commit is contained in:
+56
-54
@@ -1,3 +1,4 @@
|
||||
import cljnim_pvec
|
||||
import strutils, sequtils, hashes, algorithm, os, osproc
|
||||
|
||||
type
|
||||
@@ -16,7 +17,7 @@ type
|
||||
of ckKeyword: kwName*: string
|
||||
of ckSymbol: symName*: string
|
||||
of ckList: listItems*: seq[CljVal]
|
||||
of ckVector: vecData*: seq[CljVal]
|
||||
of ckVector: vecData*: PersistentVector[CljVal]
|
||||
of ckMap:
|
||||
mapKeys*: seq[CljVal]
|
||||
mapVals*: seq[CljVal]
|
||||
@@ -34,7 +35,7 @@ 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)
|
||||
proc cljList*(items: seq[CljVal]): CljVal = CljVal(kind: ckList, listItems: items)
|
||||
proc cljVector*(items: seq[CljVal]): CljVal = CljVal(kind: ckVector, vecData: items)
|
||||
proc cljVector*(items: seq[CljVal]): CljVal = CljVal(kind: ckVector, vecData: newPersistentVector(items))
|
||||
proc cljFn*(p: proc(args: seq[CljVal]): CljVal): CljVal = CljVal(kind: ckFn, fnProc: p)
|
||||
|
||||
proc cljMap*(keys, vals: seq[CljVal]): CljVal =
|
||||
@@ -77,7 +78,7 @@ proc cljRepr*(v: CljVal): string =
|
||||
of ckKeyword: ":" & v.kwName
|
||||
of ckSymbol: v.symName
|
||||
of ckList: "(" & v.listItems.mapIt(cljRepr(it)).join(" ") & ")"
|
||||
of ckVector: "[" & v.vecData.mapIt(cljRepr(it)).join(" ") & "]"
|
||||
of ckVector: "[" & toSeq(v.vecData).mapIt(cljRepr(it)).join(" ") & "]"
|
||||
of ckMap:
|
||||
var parts: seq[string] = @[]
|
||||
for i in 0..<v.mapKeys.len:
|
||||
@@ -334,7 +335,7 @@ proc cljCount*(v: CljVal): int =
|
||||
if v.isNil: return 0
|
||||
case v.kind
|
||||
of ckList: v.listItems.len
|
||||
of ckVector: v.vecData.len
|
||||
of ckVector: v.vecData.count
|
||||
of ckMap: v.mapKeys.len
|
||||
of ckString: v.strVal.len
|
||||
else: 0
|
||||
@@ -346,8 +347,8 @@ proc cljFirst*(v: CljVal): CljVal =
|
||||
if v.listItems.len == 0: cljNil()
|
||||
else: v.listItems[0]
|
||||
of ckVector:
|
||||
if v.vecData.len == 0: cljNil()
|
||||
else: v.vecData[0]
|
||||
if v.vecData.count == 0: cljNil()
|
||||
else: pvecNth(v.vecData, 0)
|
||||
else: cljNil()
|
||||
|
||||
proc cljRest*(v: CljVal): CljVal =
|
||||
@@ -357,8 +358,8 @@ proc cljRest*(v: CljVal): CljVal =
|
||||
if v.listItems.len <= 1: cljList(@[])
|
||||
else: cljList(v.listItems[1..^1])
|
||||
of ckVector:
|
||||
if v.vecData.len <= 1: cljList(@[])
|
||||
else: cljList(v.vecData[1..^1])
|
||||
if v.vecData.count <= 1: cljList(@[])
|
||||
else: cljList(toSeq(v.vecData)[1..^1])
|
||||
else: cljList(@[])
|
||||
|
||||
proc cljNext*(v: CljVal): CljVal =
|
||||
@@ -374,20 +375,21 @@ proc cljLast*(v: CljVal): CljVal =
|
||||
if v.listItems.len == 0: cljNil()
|
||||
else: v.listItems[^1]
|
||||
of ckVector:
|
||||
if v.vecData.len == 0: cljNil()
|
||||
else: v.vecData[^1]
|
||||
if v.vecData.count == 0: cljNil()
|
||||
else: pvecNth(v.vecData, v.vecData.count - 1)
|
||||
else: cljNil()
|
||||
|
||||
proc cljNth*(v: CljVal, n: int): CljVal =
|
||||
proc cljNth*(v: CljVal, n: CljVal): CljVal =
|
||||
let idx = n.intVal
|
||||
case v.kind
|
||||
of ckList:
|
||||
if n < 0 or n >= v.listItems.len:
|
||||
if idx < 0 or idx >= v.listItems.len:
|
||||
raise newException(IndexDefect, "nth: index out of range")
|
||||
v.listItems[n]
|
||||
v.listItems[idx]
|
||||
of ckVector:
|
||||
if n < 0 or n >= v.vecData.len:
|
||||
if idx < 0 or idx >= v.vecData.count:
|
||||
raise newException(IndexDefect, "nth: index out of range")
|
||||
v.vecData[n]
|
||||
pvecNth(v.vecData, idx)
|
||||
else:
|
||||
raise newException(CatchableError, "nth requires a collection")
|
||||
|
||||
@@ -400,7 +402,7 @@ proc cljConj*(coll: CljVal, item: CljVal): CljVal =
|
||||
newItems.add(coll.listItems)
|
||||
cljList(newItems)
|
||||
of ckVector:
|
||||
var newItems = coll.vecData
|
||||
var newItems = toSeq(coll.vecData)
|
||||
newItems.add(item)
|
||||
cljVector(newItems)
|
||||
else:
|
||||
@@ -416,7 +418,7 @@ proc cljCons*(item: CljVal, coll: CljVal): CljVal =
|
||||
cljList(newItems)
|
||||
of ckVector:
|
||||
var newItems = @[item]
|
||||
newItems.add(coll.vecData)
|
||||
newItems.add(toSeq(coll.vecData))
|
||||
cljList(newItems)
|
||||
else:
|
||||
cljList(@[item])
|
||||
@@ -428,8 +430,8 @@ proc cljSeq*(v: CljVal): CljVal =
|
||||
if v.listItems.len == 0: cljNil()
|
||||
else: v
|
||||
of ckVector:
|
||||
if v.vecData.len == 0: cljNil()
|
||||
else: cljList(v.vecData)
|
||||
if v.vecData.count == 0: cljNil()
|
||||
else: cljList(toSeq(v.vecData))
|
||||
of ckString:
|
||||
if v.strVal.len == 0: cljNil()
|
||||
else:
|
||||
@@ -455,7 +457,7 @@ proc cljConcat*(args: seq[CljVal]): CljVal =
|
||||
if not a.isNil:
|
||||
case a.kind
|
||||
of ckList: items.add(a.listItems)
|
||||
of ckVector: items.add(a.vecData)
|
||||
of ckVector: items.add(toSeq(a.vecData))
|
||||
else: discard
|
||||
cljList(items)
|
||||
|
||||
@@ -463,14 +465,14 @@ proc cljTake*(n: int, coll: CljVal): CljVal =
|
||||
if coll.isNil: return cljList(@[])
|
||||
case coll.kind
|
||||
of ckList: cljList(coll.listItems[0..<min(n, coll.listItems.len)])
|
||||
of ckVector: cljList(coll.vecData[0..<min(n, coll.vecData.len)])
|
||||
of ckVector: cljList(toSeq(coll.vecData)[0..<min(n, coll.vecData.count)])
|
||||
else: cljList(@[])
|
||||
|
||||
proc cljDrop*(n: int, coll: CljVal): CljVal =
|
||||
if coll.isNil: return cljList(@[])
|
||||
case coll.kind
|
||||
of ckList: cljList(coll.listItems[min(n, coll.listItems.len)..^1])
|
||||
of ckVector: cljList(coll.vecData[min(n, coll.vecData.len)..^1])
|
||||
of ckVector: cljList(toSeq(coll.vecData)[min(n, coll.vecData.count)..^1])
|
||||
else: cljList(@[])
|
||||
|
||||
proc cljReverse*(coll: CljVal): CljVal =
|
||||
@@ -481,7 +483,7 @@ proc cljReverse*(coll: CljVal): CljVal =
|
||||
items.reverse()
|
||||
cljList(items)
|
||||
of ckVector:
|
||||
var items = coll.vecData
|
||||
var items = toSeq(coll.vecData)
|
||||
items.reverse()
|
||||
cljList(items)
|
||||
else: cljList(@[])
|
||||
@@ -497,7 +499,7 @@ proc cljSort*(coll: CljVal): CljVal =
|
||||
return 0)
|
||||
cljList(items)
|
||||
of ckVector:
|
||||
var items = coll.vecData
|
||||
var items = toSeq(coll.vecData)
|
||||
items.sort(proc(a, b: CljVal): int =
|
||||
if a.kind == ckInt and b.kind == ckInt:
|
||||
return cmp(a.intVal, b.intVal)
|
||||
@@ -515,7 +517,7 @@ proc cljDistinct*(coll: CljVal): CljVal =
|
||||
seen.add(item)
|
||||
cljList(seen)
|
||||
of ckVector:
|
||||
for item in coll.vecData:
|
||||
for item in coll.vecData.items:
|
||||
if item notin seen:
|
||||
seen.add(item)
|
||||
cljList(seen)
|
||||
@@ -531,7 +533,7 @@ proc cljFlatten*(coll: CljVal): CljVal =
|
||||
for item in v.listItems:
|
||||
flattenHelper(item)
|
||||
of ckVector:
|
||||
for item in v.vecData:
|
||||
for item in v.vecData.items:
|
||||
flattenHelper(item)
|
||||
else:
|
||||
result.add(v)
|
||||
@@ -543,7 +545,7 @@ proc cljPartition*(n: int, coll: CljVal): CljVal =
|
||||
var items: seq[CljVal]
|
||||
case coll.kind
|
||||
of ckList: items = coll.listItems
|
||||
of ckVector: items = coll.vecData
|
||||
of ckVector: items = toSeq(coll.vecData)
|
||||
else: return cljList(@[])
|
||||
var parts: seq[CljVal] = @[]
|
||||
var i = 0
|
||||
@@ -559,7 +561,7 @@ proc cljFrequencies*(coll: CljVal): CljVal =
|
||||
var items: seq[CljVal]
|
||||
case coll.kind
|
||||
of ckList: items = coll.listItems
|
||||
of ckVector: items = coll.vecData
|
||||
of ckVector: items = toSeq(coll.vecData)
|
||||
else: return cljMap(@[], @[])
|
||||
for item in items:
|
||||
var found = false
|
||||
@@ -580,7 +582,7 @@ proc cljGroupBy*(f: proc(args: seq[CljVal]): CljVal, coll: CljVal): CljVal =
|
||||
var items: seq[CljVal]
|
||||
case coll.kind
|
||||
of ckList: items = coll.listItems
|
||||
of ckVector: items = coll.vecData
|
||||
of ckVector: items = toSeq(coll.vecData)
|
||||
else: return cljMap(@[], @[])
|
||||
for item in items:
|
||||
let key = f(@[item])
|
||||
@@ -708,7 +710,7 @@ proc cljMap*(f: proc(args: seq[CljVal]): CljVal, coll: CljVal): CljVal =
|
||||
if coll.isNil: return cljList(@[])
|
||||
case coll.kind
|
||||
of ckList: cljList(cljMapSeq(f, coll.listItems))
|
||||
of ckVector: cljList(cljMapSeq(f, coll.vecData))
|
||||
of ckVector: cljList(cljMapSeq(f, toSeq(coll.vecData)))
|
||||
else: cljList(@[])
|
||||
|
||||
proc cljMap*(f: CljVal, coll: CljVal): CljVal =
|
||||
@@ -719,7 +721,7 @@ proc cljFilter*(f: proc(args: seq[CljVal]): CljVal, coll: CljVal): CljVal =
|
||||
if coll.isNil: return cljList(@[])
|
||||
case coll.kind
|
||||
of ckList: cljList(cljFilterSeq(f, coll.listItems))
|
||||
of ckVector: cljList(cljFilterSeq(f, coll.vecData))
|
||||
of ckVector: cljList(cljFilterSeq(f, toSeq(coll.vecData)))
|
||||
else: cljList(@[])
|
||||
|
||||
proc cljFilter*(f: CljVal, coll: CljVal): CljVal =
|
||||
@@ -730,7 +732,7 @@ proc cljReduce*(f: proc(args: seq[CljVal]): CljVal, init: CljVal, coll: CljVal):
|
||||
if coll.isNil: return init
|
||||
case coll.kind
|
||||
of ckList: cljReduceSeq(f, init, coll.listItems)
|
||||
of ckVector: cljReduceSeq(f, init, coll.vecData)
|
||||
of ckVector: cljReduceSeq(f, init, toSeq(coll.vecData))
|
||||
else: init
|
||||
|
||||
proc cljReduce*(f: CljVal, init: CljVal, coll: CljVal): CljVal =
|
||||
@@ -741,7 +743,7 @@ proc cljMapv*(f: proc(args: seq[CljVal]): CljVal, coll: CljVal): CljVal =
|
||||
if coll.isNil: return cljVector(@[])
|
||||
case coll.kind
|
||||
of ckList: cljVector(cljMapSeq(f, coll.listItems))
|
||||
of ckVector: cljVector(cljMapSeq(f, coll.vecData))
|
||||
of ckVector: cljVector(cljMapSeq(f, toSeq(coll.vecData)))
|
||||
else: cljVector(@[])
|
||||
|
||||
proc cljMapv*(f: CljVal, coll: CljVal): CljVal =
|
||||
@@ -754,7 +756,7 @@ proc cljSome*(f: CljVal, coll: CljVal): CljVal =
|
||||
var items: seq[CljVal]
|
||||
case coll.kind
|
||||
of ckList: items = coll.listItems
|
||||
of ckVector: items = coll.vecData
|
||||
of ckVector: items = toSeq(coll.vecData)
|
||||
else: return cljNil()
|
||||
for item in items:
|
||||
let r = fn(@[item])
|
||||
@@ -768,7 +770,7 @@ proc cljEvery*(f: CljVal, coll: CljVal): CljVal =
|
||||
var items: seq[CljVal]
|
||||
case coll.kind
|
||||
of ckList: items = coll.listItems
|
||||
of ckVector: items = coll.vecData
|
||||
of ckVector: items = toSeq(coll.vecData)
|
||||
else: return cljBool(true)
|
||||
for item in items:
|
||||
let r = fn(@[item])
|
||||
@@ -782,7 +784,7 @@ proc cljApply*(f: CljVal, args: CljVal): CljVal =
|
||||
if not args.isNil:
|
||||
case args.kind
|
||||
of ckList: argSeq = args.listItems
|
||||
of ckVector: argSeq = args.vecData
|
||||
of ckVector: argSeq = toSeq(args.vecData)
|
||||
else: argSeq = @[args]
|
||||
f.fnProc(argSeq)
|
||||
|
||||
@@ -844,12 +846,12 @@ proc cljStrJoin*(args: seq[CljVal]): CljVal =
|
||||
if args.len == 1:
|
||||
case args[0].kind
|
||||
of ckList: return cljString(args[0].listItems.mapIt(cljStr(it)).join(""))
|
||||
of ckVector: return cljString(args[0].vecData.mapIt(cljStr(it)).join(""))
|
||||
of ckVector: return cljString(toSeq(args[0].vecData).mapIt(cljStr(it)).join(""))
|
||||
else: return cljString(cljStr(args[0]))
|
||||
let sep = cljStr(args[0])
|
||||
case args[1].kind
|
||||
of ckList: cljString(args[1].listItems.mapIt(cljStr(it)).join(sep))
|
||||
of ckVector: cljString(args[1].vecData.mapIt(cljStr(it)).join(sep))
|
||||
of ckVector: cljString(toSeq(args[1].vecData).mapIt(cljStr(it)).join(sep))
|
||||
else: cljString(cljStr(args[1]))
|
||||
|
||||
proc cljStrSplit*(s: CljVal, sep: CljVal): CljVal =
|
||||
@@ -966,12 +968,12 @@ proc cljInto*(to: CljVal, src: CljVal): CljVal =
|
||||
of ckVector:
|
||||
case src.kind
|
||||
of ckList:
|
||||
var items = to.vecData
|
||||
var items = toSeq(to.vecData)
|
||||
items.add(src.listItems)
|
||||
cljVector(items)
|
||||
of ckVector:
|
||||
var items = to.vecData
|
||||
items.add(src.vecData)
|
||||
var items = toSeq(to.vecData)
|
||||
items.add(toSeq(src.vecData))
|
||||
cljVector(items)
|
||||
else: to
|
||||
of ckList:
|
||||
@@ -982,7 +984,7 @@ proc cljInto*(to: CljVal, src: CljVal): CljVal =
|
||||
cljList(items)
|
||||
of ckVector:
|
||||
var items = to.listItems
|
||||
items.add(src.vecData)
|
||||
items.add(toSeq(src.vecData))
|
||||
cljList(items)
|
||||
else: to
|
||||
of ckMap:
|
||||
@@ -1003,32 +1005,32 @@ proc cljInto*(to: CljVal, src: CljVal): CljVal =
|
||||
elif src.kind == ckVector:
|
||||
var keys = to.mapKeys
|
||||
var vals = to.mapVals
|
||||
for pair in src.vecData:
|
||||
if pair.kind == ckVector and pair.vecData.len == 2:
|
||||
for pair in src.vecData.items:
|
||||
if pair.kind == ckVector and pair.vecData.count == 2:
|
||||
var found = false
|
||||
for j in 0..<keys.len:
|
||||
if keys[j] == pair.vecData[0]:
|
||||
vals[j] = pair.vecData[1]
|
||||
if keys[j] == pvecNth(pair.vecData, 0):
|
||||
vals[j] = pvecNth(pair.vecData, 1)
|
||||
found = true
|
||||
break
|
||||
if not found:
|
||||
keys.add(pair.vecData[0])
|
||||
vals.add(pair.vecData[1])
|
||||
keys.add(pvecNth(pair.vecData, 0))
|
||||
vals.add(pvecNth(pair.vecData, 1))
|
||||
cljMap(keys, vals)
|
||||
elif src.kind == ckVector:
|
||||
var keys = to.mapKeys
|
||||
var vals = to.mapVals
|
||||
for pair in src.vecData:
|
||||
if pair.kind == ckVector and pair.vecData.len == 2:
|
||||
for pair in src.vecData.items:
|
||||
if pair.kind == ckVector and pair.vecData.count == 2:
|
||||
var found = false
|
||||
for j in 0..<keys.len:
|
||||
if keys[j] == pair.vecData[0]:
|
||||
vals[j] = pair.vecData[1]
|
||||
if keys[j] == pvecNth(pair.vecData, 0):
|
||||
vals[j] = pvecNth(pair.vecData, 1)
|
||||
found = true
|
||||
break
|
||||
if not found:
|
||||
keys.add(pair.vecData[0])
|
||||
vals.add(pair.vecData[1])
|
||||
keys.add(pvecNth(pair.vecData, 0))
|
||||
vals.add(pvecNth(pair.vecData, 1))
|
||||
cljMap(keys, vals)
|
||||
else: to
|
||||
else: to
|
||||
|
||||
Reference in New Issue
Block a user