Add `%` operator

Reuse the `%` operator from json module for consistency.
This commit is contained in:
Emery Hemingway 2021-07-09 16:54:13 +02:00
parent f0c1ebe85e
commit 713f9d00d3
2 changed files with 82 additions and 4 deletions

View File

@ -1,8 +1,9 @@
# SPDX-License-Identifier: ISC
import bigints
import std/[base64, endians, json, hashes, macros, sets, streams, tables, typetraits]
import std/[base64, endians, hashes, macros, sets, streams, tables, typetraits]
import json except `%`
type
PreserveKind* = enum
@ -53,7 +54,7 @@ proc assertValid*(prs: Preserve) =
for v in prs.set: assertValid(v)
of pkDictionary:
for key, val in prs.dict.pairs:
assert(key.kind < pkRecord)
# assert(key.kind < pkRecord)
assertValid(key)
assertValid(val)
else:
@ -212,7 +213,7 @@ proc `$`*(prs: Preserve): string =
for val in prs.set.items:
result.add($val)
result.add(' ')
if result.len > 1:
if result.len > 2:
result.setLen(result.high)
result.add('}')
of pkDictionary:
@ -502,7 +503,7 @@ proc toPreserve*[T](x: T): Preserve =
elif T is float64:
result = Preserve(kind: pkDouble, double: x)
elif T is object | tuple:
when T.hasCustomPragma(unpreservable): {.error.}
when T.hasCustomPragma(unpreservable): {.fatal: "unpreservable type".}
elif T.hasCustomPragma(record):
result = Preserve(kind: pkRecord)
for _, f in x.fieldPairs: result.record.add(toPreserve(f))
@ -662,3 +663,73 @@ proc `[]`*(prs: Preserve; i: int): Preserve =
of pkSequence: prs.sequence[i]
else:
raise newException(ValueError, "`[]` is not valid for " & $prs.kind)
template `%`*(p: Preserve): Preserve = p
proc `%`*(b: bool): Preserve =
Preserve(kind: pkBoolean, bool: b)
proc `%`*(f: float32): Preserve =
Preserve(kind: pkFloat, float: f)
proc `%`*(d: float64): Preserve =
Preserve(kind: pkDouble, double: d)
proc `%`*(n: SomeInteger): Preserve =
Preserve(kind: pkSignedInteger, int: n)
proc `%`*(b: Bigint): Preserve =
Preserve(kind: pkBigInteger, bigint: b)
proc `%`*(s: string): Preserve =
Preserve(kind: pkString, string: s)
proc `%`*(buf: seq[byte]): Preserve =
Preserve(kind: pkByteString, bytes: buf)
proc `%`*(e: enum): Preserve =
## Initialize a preserves symbol from the string
## representation of ``e``.
Preserve(kind: pkSymbol, symbol: $e)
proc `%`*[T](elems: openArray[T]): Preserve =
result = Preserve(kind: pkSequence,
sequence: newSeqOfCap[Preserve](elems.len))
for e in elems: result.sequence.add(%e)
proc `%`*[T](set: HashSet[T]): Preserve =
result = Preserve(kind: pkSet #[, set: set.map(`%`)]#)
for e in set:
result.set.incl %e
proc `%`*[A,B](table: Table[A,B]|TableRef[A,B]): Preserve =
result = Preserve(kind: pkDictionary, dict: initTable[Preserve, Preserve](table.len))
for k, v in table.pairs: result.dict[%k] = %v
proc toPreserveImpl(x: NimNode): NimNode {.compileTime.} =
case x.kind
of nnkBracket: # sequence
result = newNimNode(nnkBracket)
for i in 0 ..< x.len:
result.add(toPreserveImpl(x[i]))
result = newCall(bindSym("%", brOpen), result)
of nnkTableConstr: # dictionary
if x.len == 0: return newCall(bindSym"newJObject")
result = newNimNode(nnkTableConstr)
for i in 0 ..< x.len:
x[i].expectKind nnkExprColonExpr
result.add newTree(nnkExprColonExpr, x[i][0], toPreserveImpl(x[i][1]))
result = newCall(bindSym("%", brOpen), result)
of nnkCurly: # set
result = newNimNode(nnkCurly)
for i in 0 ..< x.len:
result.add(toPreserveImpl(x[i]))
result = newCall(bindSym("%", brOpen), result)
of nnkPar:
if x.len == 1: result = toPreserveImpl(x[0])
else: result = newCall(bindSym("%", brOpen), x)
else:
result = newCall(bindSym("%", brOpen), x)
macro `%*`*(x: untyped): untyped =
result = toPreserveImpl(x)

View File

@ -29,3 +29,10 @@ suite "conversions":
check(prs.kind == pkRecord)
check(preserveTo(prs, Foobar) == tup)
check(classOf(tup) == classOf(prs))
suite "%":
template check(p: Preserve; s: string) =
test s: check($p == s)
check %false, "#f"
check %[0, 1, 2, 3], "[0 1 2 3]"
#check %*{0, 1, 2, 3}, """#{ #t #f }"""