Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import macros
- import tables
- import typetraits
- import sequtils
- {. pragma: printMe .}
- {. pragma: ignoreMe .}
- type
- Pragma = object
- name: string
- args: seq[NimNode]
- Field = object
- name: string
- typeNode: NimNode
- pragmas: seq[Pragma]
- iterator subs[T](indexable: T, a: int, b: int): untyped =
- let a = if a < 0: indexable.len + a else: a
- let b = if b < 0: indexable.len - 1 + b else: b - 1
- for i in a..b:
- yield indexable[i]
- proc buildPragma(node: NimNode): Pragma {. compileTime .} =
- case node.kind:
- of nnkIdent:
- return Pragma(name: $node, args: @[])
- of nnkExprColonExpr:
- if node[1].kind == nnkBracket:
- return Pragma(name: $node[0], args: toSeq(node[1]))
- else:
- return Pragma(name: $node[0], args: @[node[1]])
- else:
- error("Unexpected " & $node.kind)
- proc processPragmaNode(node: NimNode): seq[Pragma] {. compileTime .} =
- node.expectKind(nnkPragma)
- toSeq(node.children).map do (x: NimNode) -> Pragma:
- case x.kind:
- of nnkIdent:
- return Pragma(name: $x, args: @[])
- of nnkExprColonExpr:
- if x[1].kind == nnkBracket:
- return Pragma(name: $x[0], args: toSeq(x[1]))
- else:
- return Pragma(name: $x[0], args: @[x[1]])
- else:
- error("Unexpected " & $x.kind)
- proc processIdentDefsNode(node: NimNode): seq[Field] {. compileTime .} =
- node.expectKind(nnkIdentDefs)
- let typeNode = node[^2]
- return toSeq(node.subs(0, -2)).map do (x: NimNode) -> Field:
- case x.kind:
- of nnkIdent:
- return Field(
- name: $x,
- typeNode: typeNode,
- pragmas: @[]
- )
- of nnkPragmaExpr:
- return Field(
- name: $x[0],
- typeNode: typeNode,
- pragmas: processPragmaNode(x[1])
- )
- else:
- error("Unexpected " & $x.kind)
- #IdentDefs = (PragmaExpr | Ident{fieldName})* Ident{type}
- #PragmaExpr = Ident{fieldName} Pragma
- #Pragma = (Ident{pragmaName} | ColonExpr)*
- static:
- var procs = initTable[string, proc(name: NimNode, fields: seq[Field]): NimNode]()
- macro dotype(stmt: untyped): untyped =
- expectKind(stmt[0], nnkTypeSection)
- for typedef in stmt[0].children:
- let objdef = typedef[2]
- expectKind(objdef, nnkObjectTy)
- if objdef[0].kind == nnkPragma:
- for pragma in objdef[0].children:
- if procs.hasKey($pragma):
- let t: seq[Field] = @[]
- let fields = toSeq(objdef[2]).foldl(a.concat(processIdentDefsNode(b)), t)
- stmt.add(procs[$pragma](typedef[0], fields))
- return stmt
- proc newsl(nodes: seq[NimNode]): NimNode {. compileTime .} =
- var s = newStmtList()
- for n in nodes.items:
- s.add(n)
- return s
- proc hasPragma(field: Field, name: string): bool =
- field.pragmas.any do (p: Pragma) -> bool:
- p.name == name
- proc printMeGen(name: NimNode, fields: seq[Field]): NimNode {. compileTime .} =
- let sym = genSym(nskParam, "y")
- let f = proc(field: Field): bool =
- not hasPragma(field, "ignoreMe")
- let pr = fields.filter(f).map do (field: Field) -> NimNode:
- newCall(newIdentNode("echo"), newDotExpr(sym, newIdentNode(field.name)))
- let body = newsl(pr)
- let x = quote do:
- proc printMe(`sym`: `name`) =
- `body`
- x
- static:
- procs["printMe"] = printMeGen
- dotype:
- type
- Foo = object {. printMe .}
- a: int
- b: float
- c: string
- Bar = object {. printMe .}
- a: int
- b: float
- c {. ignoreMe .}: string
- let bar = Bar(a: 1, b: 2.2, c: "ignored")
- echo bar
- let foo = Foo(a: 5, b: 6.6, c: "foo")
- echo foo
- printMe foo
- printMe bar
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement