From 713f9d00d369e6fc4e92af67385fbb2b1b30ac03 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 9 Jul 2021 16:54:13 +0200 Subject: [PATCH] Add `%` operator Reuse the `%` operator from json module for consistency. --- src/preserves.nim | 79 ++++++++++++++++++++++++++++++++++++-- tests/test_conversions.nim | 7 ++++ 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/preserves.nim b/src/preserves.nim index a06f765..117b56f 100644 --- a/src/preserves.nim +++ b/src/preserves.nim @@ -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) diff --git a/tests/test_conversions.nim b/tests/test_conversions.nim index 70400dd..3bbfda2 100644 --- a/tests/test_conversions.nim +++ b/tests/test_conversions.nim @@ -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 }"""