Guest User

Untitled

a guest
Jan 23rd, 2018
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.38 KB | None | 0 0
  1. {.experimental.}
  2. import macros
  3. import tables
  4.  
  5. macro ctor*(none: untyped): auto =
  6. let args = callsite()
  7. if args[1].kind != nnkProcDef:
  8. error("`ctor` pragma is used only with procedures.")
  9. var procTemplate = args[1]
  10. var paramsTemplate = procTemplate[3]
  11.  
  12. if paramsTemplate.len < 2:
  13. error("Constructor must have at least one parameter.")
  14. if paramsTemplate[1][1].kind != nnkVarTy:
  15. error("First parameter of constructor must be a `var Type`.")
  16. if paramsTemplate[0].kind != nnkEmpty:
  17. error("Constructor must not return a value.")
  18.  
  19. # Original proc is preserved.
  20. var prc = procTemplate.copy()
  21. result = newStmtList(prc)
  22.  
  23. # Construct parameter `_: typedesc[T]`
  24. var resultType = paramsTemplate[1][1][0] # Type identifier
  25. var typeParam = newNimNode(nnkIdentDefs).add(
  26. newIdentNode("_"),
  27. newNimNode(nnkBracketExpr).add(
  28. newIdentNode("typedesc"),
  29. resultType.copy()
  30. ),
  31. newNimNode(nnkEmpty)
  32. )
  33.  
  34. # Generate value constructor
  35. # proc init*[T](_: typedesc[MyObj], n: T): MyObj =
  36. # init(result, n)
  37. prc = procTemplate.copy()
  38. var params = prc[3]
  39. # Insert return type
  40. params[0] = resultType.copy()
  41. # Replace `self` parameter with `_: typedesc[T]`
  42. params[1] = typeParam.copy()
  43. # Replace body of generated constructor with call to original constructor init(result, ...)
  44. prc[6] = newStmtList(
  45. newNimNode(nnkCall).add(
  46. newIdentNode("init"),
  47. newIdentNode("result")
  48. )
  49. )
  50. for i in 2..<params.len:
  51. prc[6][0].add(params[i][0].copy())
  52.  
  53. result.add(prc)
  54.  
  55. # Generate reference constructor
  56. # proc new*[T](_: typedesc[MyObj], n: T): ref MyObj =
  57. # result.new()
  58. # init(result, n)
  59. prc = procTemplate.copy()
  60. if prc[0].kind == nnkPostfix:
  61. prc[0][1] = newIdentNode("new")
  62. else:
  63. prc[0] = newIdentNode("new")
  64. params = prc[3]
  65. # Insert ref return type
  66. params[0] = newNimNode(nnkRefTy).add(resultType.copy())
  67. # Replace `self` parameter with `_: typedesc[T]`
  68. params[1] = typeParam.copy()
  69. # Replace body of generated constructor with call to original constructor new(result); init(result, ...)
  70. prc[6] = newStmtList(
  71. newNimNode(nnkCall).add(
  72. newIdentNode("new"),
  73. newIdentNode("result")
  74. ),
  75. newNimNode(nnkCall).add(
  76. newIdentNode("init"),
  77. newIdentNode("result")
  78. )
  79. )
  80. for i in 2..<params.len:
  81. prc[6][1].add(params[i][0].copy())
  82.  
  83. result.add(prc)
  84.  
  85. if isMainModule:
  86. type
  87. MyObj[T] = object
  88. n: T
  89.  
  90. proc init[T](self: var MyObj[T]; n: T) {.ctor.} =
  91. self.n = n
  92.  
  93. proc init[A, B](self: var Table[A, B], initial_size=64) {.ctor.} =
  94. self = init_table[A, B](initial_size)
  95. self[123] = 321
  96.  
  97. proc main =
  98. var a = MyObj.init(1) # Generated value type constructor
  99. doAssert(a.n == 1)
  100.  
  101. var b = MyObj.new(2) # Generated ref type constructor
  102. doAssert(b.n == 2)
  103. var c = MyObj[byte]() # Initialize object without constructing it
  104. doAssert(c.n == 0)
  105. c.init(3) # Call original constructor which had `ctor` pragma applied to it
  106. doAssert(c.n == 3)
  107.  
  108. var d = MyObj[byte].new() # Initialize ref object without constructing it
  109. doAssert(d.n == 0)
  110. d.init(4) # Call original constructor which had `ctor` pragma applied to it
  111. doAssert(d.n == 4)
  112.  
  113. var e = Table[int, int].new()
  114. doAssert(e[123] == 321)
  115.  
  116. var f = Table[int, int].init()
  117. doAssert(f[123] == 321)
  118.  
  119. main()
Add Comment
Please, Sign In to add comment