tmacros_various.nim 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. discard """
  2. nimout: '''
  3. Infix
  4. Ident "=>"
  5. Call
  6. Ident "name"
  7. Ident "a"
  8. ExprColonExpr
  9. Ident "b"
  10. Ident "cint"
  11. NilLit
  12. macrocache ok
  13. '''
  14. output: '''
  15. x = 10
  16. x + y = 30
  17. proc foo[T, N: static[int]]()
  18. proc foo[T; N: static[int]]()
  19. a[0]: 42
  20. a[1]: 45
  21. x: some string
  22. ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")])
  23. ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")])
  24. 0
  25. 0
  26. 0
  27. '''
  28. """
  29. import macros, sugar, macrocache
  30. block tdump:
  31. let
  32. x = 10
  33. y = 20
  34. dump x
  35. dump(x + y)
  36. block texprcolonexpr:
  37. macro def(x): untyped =
  38. echo treeRepr(x)
  39. def name(a, b:cint) => nil
  40. block tgenericparams:
  41. macro test():string =
  42. let expr0 = "proc foo[T, N: static[int]]()"
  43. let expr1 = "proc foo[T; N: static[int]]()"
  44. newLit($toStrLit(parseExpr(expr0)) & "\n" & $toStrLit(parseExpr(expr1)))
  45. echo test()
  46. block tidgen:
  47. # Test compile-time state in same module
  48. var gid {.compileTime.} = 3
  49. macro genId(): int =
  50. result = newIntLitNode(gid)
  51. inc gid
  52. proc Id1(): int {.compileTime.} = return genId()
  53. proc Id2(): int {.compileTime.} = return genId()
  54. doAssert Id1() == 3
  55. doAssert Id2() == 4
  56. block tlexerex:
  57. macro match(s: cstring|string; pos: int; sections: varargs[untyped]): untyped =
  58. for sec in sections:
  59. expectKind sec, nnkOfBranch
  60. expectLen sec, 2
  61. result = newStmtList()
  62. var input = "the input"
  63. var pos = 0
  64. match input, pos:
  65. of r"[a-zA-Z_]\w+": echo "an identifier"
  66. of r"\d+": echo "an integer"
  67. of r".": echo "something else"
  68. block tcopylineinfo:
  69. # issue #5617, feature request
  70. type Test = object
  71. macro mixer(n: typed): untyped =
  72. let x = newIdentNode("echo")
  73. x.copyLineInfo(n)
  74. result = newLit(x.lineInfo == n.lineInfo)
  75. var z = mixer(Test)
  76. doAssert z
  77. block tsetgetlineinfo:
  78. # issue #21098, feature request
  79. type Test = object
  80. macro mixer1(n: typed): untyped =
  81. let x = newIdentNode("echo")
  82. var lineInfo = n.lineInfoObj
  83. x.setLineInfo lineInfo
  84. result = newLit(x.lineInfo == n.lineInfo)
  85. macro mixer2(n: typed): untyped =
  86. let x = newIdentNode("echo")
  87. var lineInfo = n.lineInfoObj
  88. lineInfo.line += 1
  89. x.setLineInfo lineInfo
  90. result = newLit(x.lineInfo != n.lineInfo)
  91. doAssert mixer1(Test)
  92. doAssert mixer2(Test)
  93. block tdebugstmt:
  94. macro debug(n: varargs[untyped]): untyped =
  95. result = newNimNode(nnkStmtList, n)
  96. for i in 0..n.len-1:
  97. add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
  98. add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
  99. add(result, newCall("writeLine", newIdentNode("stdout"), n[i]))
  100. var
  101. a: array[0..10, int]
  102. x = "some string"
  103. a[0] = 42
  104. a[1] = 45
  105. debug(a[0], a[1], x)
  106. const
  107. pairs = {"key": "val", "keyB": "2"}
  108. macro bilookups(arg: static[openArray[(string, string)]]): untyped =
  109. var a = newTree(nnkBracket)
  110. var b = newTree(nnkBracket)
  111. for (k, v) in items(arg):
  112. a.add(newTree(nnkTupleConstr, newLit k, newLit v))
  113. b.add(newTree(nnkTupleConstr, newLit v, newLit k))
  114. result = newTree(nnkTupleConstr, a, b)
  115. macro bilookups2(arg: untyped): untyped =
  116. var a = newTree(nnkBracket)
  117. var b = newTree(nnkBracket)
  118. arg.expectKind(nnkTableConstr)
  119. for x in items(arg):
  120. x.expectKind(nnkExprColonExpr)
  121. a.add(newTree(nnkTupleConstr, x[0], x[1]))
  122. b.add(newTree(nnkTupleConstr, x[1], x[0]))
  123. result = newTree(nnkTupleConstr, a, b)
  124. const cnst1 = bilookups(pairs)
  125. echo cnst1
  126. const cnst2 = bilookups2({"key": "val", "keyB": "2"})
  127. echo cnst2
  128. # macrocache #11404
  129. const
  130. mcTable = CacheTable"nimTest"
  131. mcSeq = CacheSeq"nimTest"
  132. mcCounter = CacheCounter"nimTest"
  133. static:
  134. doAssert(mcCounter.value == 0) # CacheCounter.value
  135. mcCounter.inc # CacheCounter.inc
  136. doAssert(mcCounter.value == 1) # CacheCounter.value
  137. let a = newLit(1)
  138. let b = newLit(2)
  139. let c = newLit(3)
  140. let d = newLit(4)
  141. mcSeq.add a # CacheSeq.add
  142. mcSeq.add b # CacheSeq.add
  143. mcSeq.add c # CacheSeq.add
  144. doAssert(mcSeq.len == 3) # CacheSeq.len
  145. #doAssert(c in mcSeq) # CacheSeq.contains
  146. #doAssert(d notin mcSeq) # CacheSeq.contains
  147. mcSeq.incl d # CacheSeq.incl
  148. doAssert(mcSeq.len == 4) # CacheSeq.len
  149. mcSeq.incl c # CacheSeq.incl
  150. doAssert(mcSeq.len == 4) # CacheSeq.len
  151. doAssert(mcSeq[3] == d) # CacheSeq.[]
  152. #doAssert(mcSeq.pop() == d)# CacheSeq.pop
  153. #doAssert(mcSeq.len == 3) # CacheSeq.len
  154. doAssert(mcTable.len == 0) # CacheTable.len
  155. mcTable["a"] = a # CacheTable.[]=
  156. doAssert(mcTable.len == 1) # CacheTable.len
  157. doAssert(mcTable["a"] == a) # CacheTable.[]
  158. #doAssert("a" in mcTable) # CacheTable.contains
  159. #doAssert(mcTable.hasKey("a"))# CacheTable.hasKey
  160. for k, v in mcTable: # CacheTable.items
  161. doAssert(k == "a")
  162. doAssert(v == a)
  163. echo "macrocache ok"
  164. block tupleNewLitTests:
  165. macro t(): untyped =
  166. result = newLit (1, "foo", (), (1,), (a1: 'x', a2: @["ba"]))
  167. doAssert $t() == """(1, "foo", (), (1,), (a1: 'x', a2: @["ba"]))"""
  168. # this `$` test is needed because tuple equality doesn't distinguish
  169. # between named vs unnamed tuples
  170. doAssert t() == (1, "foo", (), (1, ), (a1: 'x', a2: @["ba"]))
  171. from strutils import contains
  172. block getImplTransformed:
  173. macro bar(a: typed): string =
  174. # newLit a.getImpl.repr # this would be before code transformation
  175. let b = a.getImplTransformed
  176. newLit b.repr
  177. template toExpand() =
  178. for ai in 0..2: echo ai
  179. proc baz(a=1): int =
  180. defer: discard
  181. toExpand()
  182. 12
  183. const code = bar(baz)
  184. # sanity check:
  185. doAssert "finally" in code # `defer` is lowered to try/finally
  186. doAssert "while" in code # `for` is lowered to `while`
  187. doAssert "toExpand" notin code
  188. # template is expanded (but that would already be the case with
  189. # `a.getImpl.repr`, unlike the other transformations mentioned above
  190. # test macro resemming
  191. macro makeVar(): untyped =
  192. quote:
  193. var tensorY {.inject.}: int
  194. macro noop(a: typed): untyped =
  195. a
  196. noop:
  197. makeVar
  198. echo tensorY
  199. macro xbenchmark(body: typed): untyped =
  200. result = body
  201. xbenchmark:
  202. proc fastSHA(inputtest: string) =
  203. discard inputtest
  204. fastSHA("hey")
  205. block: # issue #4547
  206. macro lazy(stmtList : typed) : untyped =
  207. let decl = stmtList[0]
  208. decl.expectKind nnkLetSection
  209. let name = decl[0][0].strVal
  210. let call = decl[0][2].copy
  211. call.expectKind nnkCall
  212. let ident = newIdentNode("get" & name)
  213. result = quote do:
  214. var value : type(`call`)
  215. proc `ident`() : type(`call`) =
  216. if value.isNil:
  217. value = `call`
  218. value
  219. type MyObject = object
  220. a,b: int
  221. # this part, the macro call and it's result (written in the comment below) is important
  222. lazy:
  223. let y = new(MyObject)
  224. #[
  225. var value: type(new(MyObject))
  226. proc gety(): type(new(MyObject)) =
  227. if value.isNil:
  228. value = new(MyObject)
  229. value
  230. ]#
  231. doAssert gety().a == 0 # works and should work
  232. doAssert gety().b == 0 # works and should work
  233. doAssert not declared(y)
  234. doAssert not compiles(y.a) # identifier y should not exist anymore
  235. doAssert not compiles(y.b) # identifier y should not exist anymore
  236. block: # bug #13511
  237. type
  238. Builder = ref object
  239. components: seq[Component]
  240. Component = object
  241. proc add(builder: var Builder, component: Component) {.compileTime.} =
  242. builder.components.add(component)
  243. macro debugAst(arg: typed): untyped =
  244. ## just for debugging purpose.
  245. discard arg.treeRepr
  246. return arg
  247. static:
  248. var component = Component()
  249. var builder = Builder()
  250. template foo(): untyped =
  251. ## WAS: this doc comment causes compilation failure.
  252. builder
  253. debugAst:
  254. add(foo(), component)
  255. block: # bug #15118
  256. macro flop(name: static string) =
  257. let id = genSym(nskType, "env")
  258. let r =
  259. nnkStmtList.newTree(
  260. nnkTypeSection.newTree(
  261. nnkTypeDef.newTree(
  262. id,
  263. newEmptyNode(),
  264. nnkRefTy.newTree(
  265. nnkObjectTy.newTree(
  266. newEmptyNode(),
  267. newEmptyNode(),
  268. nnkRecList.newTree(
  269. nnkIdentDefs.newTree(
  270. newIdentNode(name),
  271. newIdentNode("int"),
  272. newEmptyNode()
  273. )
  274. )
  275. )
  276. )
  277. )
  278. ),
  279. # var f: T
  280. nnkVarSection.newTree(
  281. nnkIdentDefs.newTree(
  282. newIdentNode("f"),
  283. id,
  284. newEmptyNode()
  285. )
  286. ),
  287. # echo f.a
  288. nnkCommand.newTree(
  289. newIdentNode("new"),
  290. newIdentNode("f")
  291. ),
  292. nnkCommand.newTree(
  293. newIdentNode("echo"),
  294. nnkDotExpr.newTree(
  295. newIdentNode("f"),
  296. newIdentNode(name)
  297. )
  298. )
  299. )
  300. r
  301. block:
  302. flop("a")
  303. block:
  304. flop("b")
  305. static:
  306. block:
  307. const containsTable = CacheTable"containsTable"
  308. doAssert "foo" notin containsTable
  309. containsTable["foo"] = newLit 42
  310. doAssert "foo" in containsTable