forked from Kaynato/klein
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.nim
71 lines (65 loc) · 2.26 KB
/
utils.nim
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
68
69
70
71
import macros
proc rec_replace(node, src, dst: NimNode): NimNode {.compileTime.} =
## Replace all occurrences of arbitrary src node (possibly complex) with dst node (can be complex)
if node.kind == src.kind and node == src:
return dst
result = copyNimNode(node)
for n in node:
result.add(n.rec_replace(src, dst))
proc rec_match_replace(node: NimNode, pairs: openArray[(NimNode, NimNode)]): NimNode {.compileTime.} =
## Replace nodes according to the pair mapping
for (src, dst) in pairs:
if node.kind == src.kind and node == src:
return dst
result = copyNimNode(node)
for n in node:
result.add(n.rec_match_replace(pairs))
macro autoConvert*(typ, def: untyped) =
## Converts func/proc to a routine that automatically
## converts its input to the requested type `typ`
## Note: typ can also be some arbitrary symbol that will be
var generic: NimNode
var args: seq[NimNode]
result = nnkFuncDef.newNimNode()
# Find the generic ident and the argnames
for node in def:
if node.kind == nnkGenericParams:
node[0].expectKind nnkIdentDefs
node[0][0].expectKind nnkIdent
generic = node[0][0]
if node.kind == nnkFormalParams:
## Argnames go up to the type, which is T
if node[0].kind == nnkEmpty:
# Het type args
for identDef in node[1..^1]:
identDef.expectKind nnkIdentDefs
let varDef = identDef[0]
varDef.expectKind nnkIdent
if varDef != generic:
args.add varDef
else:
# Flat args
node[0].expectKind nnkIdent
let varDefs = node[1]
varDefs.expectKind nnkIdentDefs
for varDef in varDefs:
if varDef.kind == nnkIdent and varDef != generic:
args.add varDef
result.add node
# Construct the body
var pairs = newSeq[(NimNode, NimNode)]()
for arg in args:
pairs.add (arg, newDotExpr(arg, typ))
var body = copyNimTree(def.body)
var castBody = body.rec_match_replace(pairs)
# Construct the result
result.body = quote do:
when T is `typ`:
`body`
else:
`castBody`
when isMainModule:
type Plane* = distinct array[4, float32]
expandMacros:
func newPlane*[T: SomeNumber](e0, e1, e2, e3: T): Plane {.autoConvert: float32.} =
[e0, e1, e2, e3].Plane