mapEmbeds for Preserve[void] to Preserve[E]
This commit is contained in:
parent
b6275a241b
commit
cca512c9df
|
@ -282,34 +282,15 @@ proc initSet*[E](): Preserve[E] = Preserve[E](kind: pkSet)
|
|||
proc initDictionary*[E](): Preserve[E] = Preserve[E](kind: pkDictionary)
|
||||
## Create a Preserves dictionary value.
|
||||
|
||||
proc embed*[E](e: E): Preserve[E] =
|
||||
proc embed*[E](pr: sink Preserve[E]): Preserve[E] =
|
||||
## Create a Preserves value that embeds ``e``.
|
||||
result = pr
|
||||
result.embedded = true
|
||||
|
||||
proc embed*[E](e: sink E): Preserve[E] =
|
||||
## Create a Preserves value that embeds ``e``.
|
||||
Preserve[E](kind: pkEmbedded, embed: e)
|
||||
|
||||
proc mapEmbeds*[A, B](pr: Preserve[A]; op: proc (v: A): B): Preserve[B] =
|
||||
## Convert `Preserve[A]` to `Preserve[B]` using an `A -> B` procedure.
|
||||
case pr.kind
|
||||
of pkBoolean, pkFloat, pkDouble, pkSignedInteger, pkBigInteger, pkString, pkByteString, pkSymbol:
|
||||
result = cast[Preserve[B]](pr)
|
||||
of pkRecord:
|
||||
result = Preserve[B](kind: pr.kind)
|
||||
result.record = map(pr.record) do (x: Preserve[A]) -> Preserve[B]:
|
||||
mapEmbeds(x, op)
|
||||
of pkSequence:
|
||||
result = Preserve[B](kind: pr.kind)
|
||||
result.sequence = map(pr.sequence) do (x: Preserve[A]) -> Preserve[B]:
|
||||
mapEmbeds(x, op)
|
||||
of pkSet:
|
||||
result = Preserve[B](kind: pr.kind)
|
||||
result.set = map(pr.set) do (x: Preserve[A]) -> Preserve[B]:
|
||||
mapEmbeds(x, op)
|
||||
of pkDictionary:
|
||||
result = Preserve[B](kind: pr.kind)
|
||||
result.dict = map(pr.dict) do (e: DictEntry[A]) -> DictEntry[B]:
|
||||
(mapEmbeds(e.key, op), mapEmbeds(e.val, op))
|
||||
of pkEmbedded:
|
||||
result = embed op(pr.embed)
|
||||
|
||||
proc len*(pr: Preserve): int =
|
||||
## Return the shallow count of values in ``pr``, that is the number of
|
||||
## fields in a record, items in a sequence, items in a set, or key-value pairs
|
||||
|
@ -699,7 +680,10 @@ proc toPreserve*[T](x: T; E = void): Preserve[E] =
|
|||
when x.dot(key).hasCustomPragma(preservesSymbol):
|
||||
toSymbol(val, E)
|
||||
elif x.dot(key).hasCustomPragma(preservesLiteral):
|
||||
const lit = parsePreserves x.dot(key).getCustomPragmaVal(preservesLiteral)
|
||||
when E is void:
|
||||
const lit = parsePreserves(x.dot(key).getCustomPragmaVal(preservesLiteral))
|
||||
else:
|
||||
let lit = parsePreserves(x.dot(key).getCustomPragmaVal(preservesLiteral), E)
|
||||
lit
|
||||
else:
|
||||
toPreserve(val, E)
|
||||
|
@ -883,7 +867,10 @@ proc fromPreserve*[T, E](v: var T; pr: Preserve[E]): bool =
|
|||
else:
|
||||
false
|
||||
elif v.dot(key).hasCustomPragma(preservesLiteral):
|
||||
const lit = parsePreserves v.dot(key).getCustomPragmaVal(preservesLiteral)
|
||||
when E is void:
|
||||
const lit = parsePreserves(v.dot(key).getCustomPragmaVal(preservesLiteral))
|
||||
else:
|
||||
let lit = parsePreserves(v.dot(key).getCustomPragmaVal(preservesLiteral), E)
|
||||
pr == lit
|
||||
else:
|
||||
fromPreserve(val, pr)
|
||||
|
@ -988,6 +975,61 @@ when isMainModule:
|
|||
var pr = t.toPreserveHook(void)
|
||||
assert fromPreserveHook(t, pr)
|
||||
|
||||
proc mapEmbeds*(pr: sink Preserve[void]; E: typedesc): Preserve[E] =
|
||||
## Convert `Preserve[void]` to `Preserve[E]` using `fromPreserve` for `E`.
|
||||
when E is void: {.error: "E cannot be void".}
|
||||
if pr.embedded:
|
||||
pr.embedded = false
|
||||
result = Preserve[E](kind: pkEmbedded)
|
||||
if not fromPreserve(result.embed, pr):
|
||||
raise newException(ValueError, "failed to convert " & $E & " from " & $pr)
|
||||
else:
|
||||
case pr.kind
|
||||
of pkBoolean, pkFloat, pkDouble, pkSignedInteger, pkBigInteger, pkString, pkByteString, pkSymbol:
|
||||
result = cast[Preserve[E]](pr)
|
||||
of pkRecord:
|
||||
result = Preserve[E](kind: pr.kind)
|
||||
result.record = map(pr.record) do (x: Preserve[void]) -> Preserve[E]:
|
||||
mapEmbeds(x, E)
|
||||
of pkSequence:
|
||||
result = Preserve[E](kind: pr.kind)
|
||||
result.sequence = map(pr.sequence) do (x: Preserve[void]) -> Preserve[E]:
|
||||
mapEmbeds(x, E)
|
||||
of pkSet:
|
||||
result = Preserve[E](kind: pr.kind)
|
||||
result.set = map(pr.set) do (x: Preserve[void]) -> Preserve[E]:
|
||||
mapEmbeds(x, E)
|
||||
of pkDictionary:
|
||||
result = Preserve[E](kind: pr.kind)
|
||||
result.dict = map(pr.dict) do (e: DictEntry[void]) -> DictEntry[E]:
|
||||
(mapEmbeds(e.key, E), mapEmbeds(e.val, E))
|
||||
of pkEmbedded:
|
||||
assert false
|
||||
|
||||
proc mapEmbeds*[A, B](pr: sink Preserve[A]; op: proc (v: A): B): Preserve[B] =
|
||||
## Convert `Preserve[A]` to `Preserve[B]` using an `A → B` procedure.
|
||||
case pr.kind
|
||||
of pkBoolean, pkFloat, pkDouble, pkSignedInteger, pkBigInteger, pkString, pkByteString, pkSymbol:
|
||||
result = cast[Preserve[B]](pr)
|
||||
of pkRecord:
|
||||
result = Preserve[B](kind: pr.kind)
|
||||
result.record = map(pr.record) do (x: Preserve[A]) -> Preserve[B]:
|
||||
mapEmbeds(x, op)
|
||||
of pkSequence:
|
||||
result = Preserve[B](kind: pr.kind)
|
||||
result.sequence = map(pr.sequence) do (x: Preserve[A]) -> Preserve[B]:
|
||||
mapEmbeds(x, op)
|
||||
of pkSet:
|
||||
result = Preserve[B](kind: pr.kind)
|
||||
result.set = map(pr.set) do (x: Preserve[A]) -> Preserve[B]:
|
||||
mapEmbeds(x, op)
|
||||
of pkDictionary:
|
||||
result = Preserve[B](kind: pr.kind)
|
||||
result.dict = map(pr.dict) do (e: DictEntry[A]) -> DictEntry[B]:
|
||||
(mapEmbeds(e.key, op), mapEmbeds(e.val, op))
|
||||
of pkEmbedded:
|
||||
result = embed op(pr.embed)
|
||||
|
||||
proc concat[E](result: var string; pr: Preserve[E]) =
|
||||
if pr.embedded: result.add("#!")
|
||||
case pr.kind:
|
||||
|
|
|
@ -104,5 +104,9 @@ proc parsePreserves*(text: string): Preserve[void] {.gcsafe.} =
|
|||
assert(stack.len == 1)
|
||||
stack.pop.value
|
||||
|
||||
proc parsePreserves*(text: string; E: typedesc): Preserve[E] {.gcsafe.} =
|
||||
when E is void: parsePreserves(text)
|
||||
else: mapEmbeds(parsePreserves(text), E)
|
||||
|
||||
when isMainModule:
|
||||
assert(parsePreserves("#f") == Preserve())
|
||||
|
|
|
@ -26,12 +26,12 @@ suite "parse":
|
|||
for (txt, bin) in examples:
|
||||
test txt:
|
||||
checkpoint(txt)
|
||||
let test = parsePreserves(txt)
|
||||
let test = parsePreserves(txt, int)
|
||||
checkpoint($test)
|
||||
block:
|
||||
let
|
||||
a = test
|
||||
b = decodePreserves(bin)
|
||||
b = decodePreserves(bin, int)
|
||||
check(a == b)
|
||||
block:
|
||||
let
|
||||
|
|
Loading…
Reference in New Issue