diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2017-11-18 14:14:08 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-11-18 14:18:00 +0100 |
commit | 908a25a2ca262b212ab1b9e4dc4da42ece46b6df (patch) | |
tree | e11d744bd14dfdcc0cc3ee8f986fb45cfe534dee | |
parent | 5b57abe3544261ba2df29648d48a997e8d1983da (diff) | |
download | Nim-908a25a2ca262b212ab1b9e4dc4da42ece46b6df.tar.gz |
replaced asArray with a much more powerful mapLiterals macro
-rw-r--r-- | changelog.md | 5 | ||||
-rw-r--r-- | lib/core/macros.nim | 8 | ||||
-rw-r--r-- | lib/pure/collections/sequtils.nim | 55 |
3 files changed, 49 insertions, 19 deletions
diff --git a/changelog.md b/changelog.md index 6244e4f09..2e0780220 100644 --- a/changelog.md +++ b/changelog.md @@ -78,10 +78,13 @@ This now needs to be written as: via the new ``nim doc0`` command. - Added ``system.getStackTraceEntries`` that allows you to access the stack trace in a structured manner without string parsing. +- Added ``sequtils.mapLiterals`` for easier construction of array and tuple + literals. +- Added ``macros.isAtomicLit`` predicate. - Moved from stdlib into Nimble packages: - [``basic2d``](https://github.com/nim-lang/basic2d) _deprecated: use ``glm``, ``arraymancer``, ``neo``, or another package instead_ - - [``basic3d``](https://github.com/nim-lang/basic3d) + - [``basic3d``](https://github.com/nim-lang/basic3d) _deprecated: use ``glm``, ``arraymancer``, ``neo``, or another package instead_ - [``gentabs``](https://github.com/lcrees/gentabs) - [``libuv``](https://github.com/lcrees/libuv) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 5d0cb0c0d..e51b79abd 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -237,7 +237,7 @@ proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.} proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.} proc newNimNode*(kind: NimNodeKind, - lineInfoFrom: NimNode=nil): NimNode + lineInfoFrom: NimNode = nil): NimNode {.magic: "NNewNimNode", noSideEffect.} ## Creates a new AST node of the specified kind. ## @@ -470,7 +470,6 @@ proc newLit*(c: char): NimNode {.compileTime.} = result = newNimNode(nnkCharLit) result.intVal = ord(c) - proc newLit*(i: int): NimNode {.compileTime.} = ## produces a new integer literal node. result = newNimNode(nnkIntLit) @@ -581,6 +580,11 @@ proc newLit*(s: string): NimNode {.compileTime.} = result = newNimNode(nnkStrLit) result.strVal = s +proc isAtomicLit*(n: NimNode): bool = + ## returns true if ``n`` is some kind literal like ``0.3`` (a ``float`` + ## literal) or ``"abc"`` (a ``string`` literal). + result = n.kind in {nnkCharLit..nnkNilLit} + proc nestList*(theProc: NimIdent, x: NimNode): NimNode {.compileTime.} = ## nests the list `x` into a tree of call expressions: diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 8bbfb5f55..0088e42d1 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -706,27 +706,50 @@ template newSeqWith*(len: int, init: untyped): untyped = result[i] = init result -macro asArray*(targetType: typedesc, values: typed): untyped = - ## applies a type conversion to each of the elements in the specified - ## array literal. Each element is converted to the ``targetType`` type.. +proc mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool): NimNode = + if isAtomicLit(constructor): + result = newNimNode(nnkCall, lineInfoFrom=constructor) + result.add op + result.add constructor + else: + result = newNimNode(constructor.kind, lineInfoFrom=constructor) + for v in constructor: + if nested or isAtomicLit(v): + result.add mapLitsImpl(v, op, nested) + else: + result.add v + +macro mapLiterals*(constructor, op: untyped; + nested = true): untyped = + ## applies ``op`` to each of the **atomic** literals like ``3`` + ## or ``"abc"`` in the specified ``constructor`` AST. This can + ## be used to map every array element to some target type: ## ## Example: ## ## .. code-block:: - ## let x = asArray(int, [0.1, 1.2, 2.3, 3.4]) + ## let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int) ## doAssert x is array[4, int] ## ## Short notation for: ## ## .. code-block:: - ## let x = [(0.1).int, (1.2).int, (2.3).int, (3.4).int] - values.expectKind(nnkBracket) - result = newNimNode(nnkBracket, lineInfoFrom=values) - for i in 0 ..< len(values): - var call = newNimNode(nnkCall, lineInfoFrom=values[i]) - call.add targetType - call.add values[i] - result.add call + ## let x = [int(0.1), int(1.2), int(2.3), int(3.4)] + ## + ## If ``nested`` is true, the literals are replaced everywhere + ## in the ``constructor`` AST, otherwise only the first level + ## is considered: + ## + ## .. code-block:: + ## mapLiterals((1, ("abc"), 2), float, nested=false) + ## + ## Produces:: + ## + ## (float(1), ("abc"), float(2)) + ## + ## There are no constraints for the ``constructor`` AST, it + ## works for nested tuples of arrays of sets etc. + result = mapLitsImpl(constructor, op, nested.boolVal) when isMainModule: import strutils @@ -1016,11 +1039,11 @@ when isMainModule: seq2D[0][1] = true doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]] - block: # asArray tests - let x = asArray(int, [1.2, 2.3, 3.4, 4.5]) + block: # mapLiterals tests + let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int) doAssert x is array[4, int] - let y = asArray(`$`, [1.2, 2.3, 3.4, 4.5]) - doAssert y is array[4, string] + doAssert mapLiterals((1, ("abc"), 2), float, nested=false) == (float(1), "abc", float(2)) + doAssert mapLiterals(([1], ("abc"), 2), `$`, nested=true) == (["1"], "abc", "2") when not defined(testing): echo "Finished doc tests" |