File: tunique_type.nim

package info (click to toggle)
nim 2.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,911,644 kB
  • sloc: sh: 24,603; ansic: 1,761; python: 1,492; makefile: 1,013; sql: 298; asm: 141; xml: 13
file content (67 lines) | stat: -rw-r--r-- 2,147 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# Bug #2022

discard """
  output: '''@[97, 45]
@[true, false]
@[false, false]'''
"""

## The goal of this snippet is to provide and test a construct for general-
## purpose, random-access mapping. I use an AST-manipulation-based approach
## because it's more efficient than using procedure pointers and less
## verbose than defining a new callable type for every invocation of `map`.

import sugar
import macros
import strutils

#===============================================================================
# Define a system for storing copies of ASTs as static strings.
# This serves the same purpose as D's `alias` parameters for types, used heavily
# in its popular `ranges` and `algorithm` modules.

var exprNodes {.compileTime.} = newSeq[NimNode]()

proc refExpr(exprNode: NimNode): string {.compileTime.} =
  exprNodes.add exprNode.copy
  "expr" & $(exprNodes.len - 1)

proc derefExpr(exprRef: string): NimNode {.compileTime.} =
  exprNodes[parseInt(exprRef[4 .. ^1])]

#===============================================================================
# Define a type that allows a callable expression to be mapped onto elements
# of an indexable collection.

type Mapped[Input; predicate: static[string]] = object
  input: Input

macro map(input, predicate: untyped): untyped =
  let predicate = callsite()[2]
  newNimNode(nnkObjConstr).add(
    newNimNode(nnkBracketExpr).add(
      ident"Mapped",
      newNimNode(nnkTypeOfExpr).add(input),
      newLit(refExpr(predicate))),
    newNimNode(nnkExprColonExpr).add(
      ident"input", input))

proc `[]`(m: Mapped, i: int): auto =
  macro buildResult: untyped =
    newCall(
      derefExpr(m.predicate),
      newNimNode(nnkBracketExpr).add(
        newDotExpr(ident"m", ident"input"),
        ident"i"))
  buildResult()

#===============================================================================
# Test out our generic mapping construct.

let a = "a-string".map(ord)
let b = @["a", "seq"].map((e: string) => e == "a")
let c = "another-string".map((e: char) => e == 'o')

echo(@[a[0], a[1]]) # @[97, 45]
echo(@[b[0], b[1]]) # @[true, false]
echo(@[c[0], c[1]]) # @[false, false]