Advertisement
Guest User

Untitled

a guest
Feb 13th, 2018
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Nim 4.16 KB | None | 0 0
  1. import macros
  2. import tables
  3. import typetraits
  4. import sequtils
  5.  
  6. {. pragma: printMe .}
  7. {. pragma: ignoreMe .}
  8.  
  9. type
  10.     Pragma = object
  11.         name: string
  12.         args: seq[NimNode]
  13.        
  14.     Field = object
  15.         name: string
  16.         typeNode: NimNode
  17.         pragmas: seq[Pragma]
  18.  
  19. iterator subs[T](indexable: T, a: int, b: int): untyped =
  20.     let a = if a < 0: indexable.len + a else: a
  21.     let b = if b < 0: indexable.len - 1 + b else: b - 1
  22.     for i in a..b:
  23.         yield indexable[i]
  24.  
  25. proc buildPragma(node: NimNode): Pragma {. compileTime .} =
  26.     case node.kind:
  27.         of nnkIdent:
  28.             return Pragma(name: $node, args: @[])
  29.         of nnkExprColonExpr:
  30.             if node[1].kind == nnkBracket:
  31.                 return Pragma(name: $node[0], args: toSeq(node[1]))
  32.             else:
  33.                 return Pragma(name: $node[0], args: @[node[1]])
  34.         else:
  35.             error("Unexpected " & $node.kind)
  36.  
  37. proc processPragmaNode(node: NimNode): seq[Pragma] {. compileTime .} =
  38.     node.expectKind(nnkPragma)
  39.     toSeq(node.children).map do (x: NimNode) -> Pragma:
  40.         case x.kind:
  41.             of nnkIdent:
  42.                 return Pragma(name: $x, args: @[])
  43.             of nnkExprColonExpr:
  44.                 if x[1].kind == nnkBracket:
  45.                     return Pragma(name: $x[0], args: toSeq(x[1]))
  46.                 else:
  47.                     return Pragma(name: $x[0], args: @[x[1]])
  48.             else:
  49.                 error("Unexpected " & $x.kind)
  50.  
  51. proc processIdentDefsNode(node: NimNode): seq[Field] {. compileTime .} =
  52.     node.expectKind(nnkIdentDefs)
  53.     let typeNode = node[^2]
  54.    
  55.     return toSeq(node.subs(0, -2)).map do (x: NimNode) -> Field:
  56.         case x.kind:
  57.             of nnkIdent:
  58.                 return Field(
  59.                     name: $x,
  60.                     typeNode: typeNode,
  61.                     pragmas: @[]
  62.                 )
  63.             of nnkPragmaExpr:
  64.                 return Field(
  65.                     name: $x[0],
  66.                     typeNode: typeNode,
  67.                     pragmas: processPragmaNode(x[1])
  68.                 )
  69.             else:
  70.                 error("Unexpected " & $x.kind)
  71.            
  72. #IdentDefs = (PragmaExpr | Ident{fieldName})*  Ident{type}
  73. #PragmaExpr = Ident{fieldName} Pragma
  74. #Pragma = (Ident{pragmaName} | ColonExpr)*
  75.            
  76. static:
  77.     var procs = initTable[string, proc(name: NimNode, fields: seq[Field]): NimNode]()
  78.  
  79. macro dotype(stmt: untyped): untyped =
  80.     expectKind(stmt[0], nnkTypeSection)
  81.     for typedef in stmt[0].children:
  82.         let objdef = typedef[2]
  83.         expectKind(objdef, nnkObjectTy)
  84.        
  85.         if objdef[0].kind == nnkPragma:
  86.             for pragma in objdef[0].children:
  87.                 if procs.hasKey($pragma):
  88.                     let t: seq[Field] = @[]
  89.                     let fields = toSeq(objdef[2]).foldl(a.concat(processIdentDefsNode(b)), t)
  90.                     stmt.add(procs[$pragma](typedef[0], fields))
  91.     return stmt
  92.  
  93. proc newsl(nodes: seq[NimNode]): NimNode {. compileTime .} =
  94.     var s = newStmtList()
  95.     for n in nodes.items:
  96.         s.add(n)
  97.     return s
  98.  
  99. proc hasPragma(field: Field, name: string): bool =
  100.     field.pragmas.any do (p: Pragma) -> bool:
  101.         p.name == name
  102.    
  103. proc printMeGen(name: NimNode, fields: seq[Field]): NimNode {. compileTime .} =
  104.     let sym = genSym(nskParam, "y")
  105.    
  106.     let f = proc(field: Field): bool =
  107.         not hasPragma(field, "ignoreMe")
  108.    
  109.     let pr = fields.filter(f).map do (field: Field) -> NimNode:
  110.         newCall(newIdentNode("echo"), newDotExpr(sym, newIdentNode(field.name)))
  111.    
  112.     let body = newsl(pr)
  113.    
  114.     let x = quote do:
  115.         proc printMe(`sym`: `name`) =
  116.             `body`
  117.     x
  118.  
  119. static:
  120.     procs["printMe"] = printMeGen
  121.  
  122. dotype:
  123.     type
  124.         Foo = object {. printMe .}
  125.                 a: int
  126.                 b: float
  127.                 c: string
  128.    
  129.         Bar = object {. printMe .}
  130.                 a: int
  131.                 b: float
  132.                 c {. ignoreMe .}: string
  133.  
  134. let bar = Bar(a: 1, b: 2.2, c: "ignored")
  135. echo bar
  136. let foo = Foo(a: 5, b: 6.6, c: "foo")
  137. echo foo
  138.  
  139. printMe foo
  140. printMe bar
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement