tmacros_issues.nim 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. discard """
  2. nimout: '''
  3. IntLit 5
  4. proc (x: int): string => typeDesc[proc[string, int]]
  5. proc (x: int): void => typeDesc[proc[void, int]]
  6. proc (x: int) => typeDesc[proc[void, int]]
  7. x => seq[int]
  8. a
  9. s
  10. d
  11. f
  12. TTaa
  13. TTaa
  14. TTaa
  15. TTaa
  16. true
  17. true
  18. nil
  19. 42
  20. false
  21. true
  22. @[i0, i1, i2, i3, i4]
  23. @[tmp, tmp, tmp, tmp, tmp]
  24. '''
  25. output: '''
  26. range[0 .. 100]
  27. array[0 .. 100, int]
  28. 10
  29. test
  30. 0o377'i8
  31. 0o000000000755'i32
  32. 1
  33. 2
  34. 3
  35. foo1
  36. foo2
  37. foo3
  38. true
  39. false
  40. true
  41. false
  42. 1.0
  43. '''
  44. """
  45. import macros, parseutils
  46. block t7723:
  47. macro foo1(): untyped =
  48. result = newStmtList()
  49. result.add quote do:
  50. proc init(foo: int, bar: typedesc[int]): int =
  51. foo
  52. #expandMacros:
  53. foo1()
  54. doAssert init(1, int) == 1
  55. block t8706:
  56. macro varargsLen(args:varargs[untyped]): untyped =
  57. doAssert args.kind == nnkArgList
  58. doAssert args.len == 0
  59. result = newLit(args.len)
  60. template bar(a0:varargs[untyped]): untyped =
  61. varargsLen(a0)
  62. template foo(x: int, a0:varargs[untyped]): untyped =
  63. bar(a0)
  64. doAssert foo(42) == 0
  65. doAssert bar() == 0
  66. block t9194:
  67. type
  68. Foo1 = range[0 .. 100]
  69. Foo2 = array[0 .. 100, int]
  70. macro get(T: typedesc): untyped =
  71. # Get the X out of typedesc[X]
  72. let tmp = getTypeImpl(T)
  73. result = newStrLitNode(getTypeImpl(tmp[1]).repr)
  74. echo Foo1.get
  75. echo Foo2.get
  76. block t1944:
  77. template t(e: untyped): untyped =
  78. macro m(eNode: untyped): untyped =
  79. echo eNode.treeRepr
  80. m e
  81. t 5
  82. block t926:
  83. proc test(f: var NimNode) {.compileTime.} =
  84. f = newNimNode(nnkStmtList)
  85. f.add newCall(newIdentNode("echo"), newLit(10))
  86. macro blah(prc: untyped): untyped =
  87. result = prc
  88. test(result)
  89. proc test() {.blah.} =
  90. echo 5
  91. block t2211:
  92. macro showType(t:typed): untyped =
  93. let ty = t.getType
  94. echo t.repr, " => ", ty.repr
  95. showType(proc(x:int): string)
  96. showType(proc(x:int): void)
  97. showType(proc(x:int))
  98. var x: seq[int]
  99. showType(x)
  100. block t1140:
  101. proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =
  102. var splitValue: string
  103. var read = value.parseUntil(splitValue, '$', index)
  104. # when false:
  105. if false:
  106. var identifier: string
  107. read = value.parseWhile(identifier, {}, index)
  108. node.add newCall("add", ident("result"), newCall("$", ident(identifier)))
  109. if splitValue.len > 0:
  110. node.insert node.len, newCall("add", ident("result"), newStrLitNode(splitValue))
  111. proc parse_template(node: NimNode, value: string) {.compiletime.} =
  112. var index = 0
  113. while index < value.len and
  114. parse_until_symbol(node, value, index): discard
  115. macro tmpli(body: untyped): typed =
  116. result = newStmtList()
  117. result.add parseExpr("result = \"\"")
  118. result.parse_template body[1].strVal
  119. proc actual: string {.used.} = tmpli html"""
  120. <p>Test!</p>
  121. """
  122. proc another: string {.used.} = tmpli html"""
  123. <p>what</p>
  124. """
  125. block tbugs:
  126. type
  127. Foo = object
  128. s: char
  129. iterator test2(f: string): Foo =
  130. for i in f:
  131. yield Foo(s: i)
  132. macro test(): untyped =
  133. for i in test2("asdf"):
  134. echo i.s
  135. test()
  136. # bug 1297
  137. type TType = tuple[s: string]
  138. macro echotest(): untyped =
  139. var t: TType
  140. t.s = ""
  141. t.s.add("test")
  142. result = newCall(newIdentNode("echo"), newStrLitNode(t.s))
  143. echotest()
  144. # bug #1103
  145. type
  146. Td = tuple
  147. a:string
  148. b:int
  149. proc get_data(d: Td) : string {.compileTime.} =
  150. result = d.a # Works if a literal string is used here.
  151. # Bugs if line A or B is active. Works with C
  152. result &= "aa" # A
  153. #result.add("aa") # B
  154. #result = result & "aa" # C
  155. macro m(s:static[Td]) : untyped =
  156. echo get_data(s)
  157. echo get_data(s)
  158. result = newEmptyNode()
  159. const s = ("TT", 3)
  160. m(s)
  161. m(s)
  162. # bug #933
  163. proc nilcheck(): NimNode {.compileTime.} =
  164. echo(result == nil) # true
  165. echo(result.isNil) # true
  166. echo(repr(result)) # nil
  167. macro testnilcheck(): untyped =
  168. result = newNimNode(nnkStmtList)
  169. discard nilcheck()
  170. testnilcheck()
  171. # bug #1323
  172. proc calc(): array[1, int] =
  173. result[0].inc()
  174. result[0].inc()
  175. const c = calc()
  176. doAssert c[0] == 2
  177. # bug #3046
  178. macro sampleMacroInt(i: int): untyped =
  179. echo i.intVal
  180. macro sampleMacroBool(b: bool): untyped =
  181. echo b.boolVal
  182. sampleMacroInt(42)
  183. sampleMacroBool(false)
  184. sampleMacroBool(system.true)
  185. # bug #11131
  186. macro toRendererBug(n): untyped =
  187. result = newLit repr(n)
  188. echo toRendererBug(0o377'i8)
  189. echo toRendererBug(0o755'i32)
  190. # bug #12129
  191. macro foobar() =
  192. var loopVars = newSeq[NimNode](5)
  193. for i, sym in loopVars.mpairs():
  194. sym = ident("i" & $i)
  195. echo loopVars
  196. for sym in loopVars.mitems():
  197. sym = ident("tmp")
  198. echo loopVars
  199. foobar()
  200. # bug #13253
  201. import macros
  202. type
  203. FooBar = object
  204. a: seq[int]
  205. macro genFoobar(a: static FooBar): untyped =
  206. result = newStmtList()
  207. for b in a.a:
  208. result.add(newCall(bindSym"echo", newLit b))
  209. proc foobar(a: static FooBar) =
  210. genFoobar(a) # removing this make it work
  211. for b in a.a:
  212. echo "foo" & $b
  213. proc main() =
  214. const a: seq[int] = @[1, 2,3]
  215. # Error: type mismatch: got <array[0..2, int]> but expected 'seq[int]'
  216. const fb = Foobar(a: a)
  217. foobar(fb)
  218. main()
  219. # bug #13484
  220. proc defForward(id, nid: NimNode): NimNode =
  221. result = newProc(id, @[newIdentNode("bool"), newIdentDefs(nid, newIdentNode("int"))], body=newEmptyNode())
  222. proc defEven(evenid, oddid, nid: NimNode): NimNode =
  223. result = quote do:
  224. proc `evenid`(`nid`: int): bool =
  225. if `nid` == 0:
  226. return true
  227. else:
  228. return `oddid`(`nid` - 1)
  229. proc defOdd(evenid, oddid, nid: NimNode): NimNode =
  230. result = quote do:
  231. proc `oddid`(`nid`: int): bool =
  232. if `nid` == 0:
  233. return false
  234. else:
  235. return `evenid`(`nid` - 1)
  236. proc callNode(funid, param: NimNode): NimNode =
  237. result = quote do:
  238. `funid`(`param`)
  239. macro testEvenOdd3(): untyped =
  240. let
  241. evenid = newIdentNode("even3")
  242. oddid = newIdentNode("odd3")
  243. nid = newIdentNode("n")
  244. oddForward = defForward(oddid, nid)
  245. even = defEven(evenid, oddid, nid)
  246. odd = defOdd(evenid, oddid, nid)
  247. callEven = callNode(evenid, newLit(42))
  248. callOdd = callNode(oddid, newLit(42))
  249. result = quote do:
  250. `oddForward`
  251. `even`
  252. `odd`
  253. echo `callEven`
  254. echo `callOdd`
  255. macro testEvenOdd4(): untyped =
  256. let
  257. evenid = newIdentNode("even4")
  258. oddid = newIdentNode("odd4")
  259. nid = newIdentNode("n")
  260. oddForward = defForward(oddid, nid)
  261. even = defEven(evenid, oddid, nid)
  262. odd = defOdd(evenid, oddid, nid)
  263. callEven = callNode(evenid, newLit(42))
  264. callOdd = callNode(oddid, newLit(42))
  265. # rewrite the body of proc node.
  266. oddForward[6] = newStmtList()
  267. result = quote do:
  268. `oddForward`
  269. `even`
  270. `odd`
  271. echo `callEven`
  272. echo `callOdd`
  273. macro testEvenOdd5(): untyped =
  274. let
  275. evenid = genSym(nskProc, "even5")
  276. oddid = genSym(nskProc, "odd5")
  277. nid = newIdentNode("n")
  278. oddForward = defForward(oddid, nid)
  279. even = defEven(evenid, oddid, nid)
  280. odd = defOdd(evenid, oddid, nid)
  281. callEven = callNode(evenid, newLit(42))
  282. callOdd = callNode(oddid, newLit(42))
  283. result = quote do:
  284. `oddForward`
  285. `even`
  286. `odd`
  287. echo `callEven`
  288. echo `callOdd`
  289. macro testEvenOdd6(): untyped =
  290. let
  291. evenid = genSym(nskProc, "even6")
  292. oddid = genSym(nskProc, "odd6")
  293. nid = newIdentNode("n")
  294. oddForward = defForward(oddid, nid)
  295. even = defEven(evenid, oddid, nid)
  296. odd = defOdd(evenid, oddid, nid)
  297. callEven = callNode(evenid, newLit(42))
  298. callOdd = callNode(oddid, newLit(42))
  299. # rewrite the body of proc node.
  300. oddForward[6] = newStmtList()
  301. result = quote do:
  302. `oddForward`
  303. `even`
  304. `odd`
  305. echo `callEven`
  306. echo `callOdd`
  307. # it works
  308. testEvenOdd3()
  309. # it causes an error (redefinition of odd4), which is correct
  310. assert not compiles testEvenOdd4()
  311. # it caused an error (still forwarded: odd5)
  312. testEvenOdd5()
  313. # it works, because the forward decl and definition share the symbol and the compiler is forgiving here
  314. #testEvenOdd6() #Don't test it though, the compiler may become more strict in the future
  315. # bug #15385
  316. var captured_funcs {.compileTime.}: seq[NimNode] = @[]
  317. macro aad*(fns: varargs[typed]): typed =
  318. result = newStmtList()
  319. for fn in fns:
  320. captured_funcs.add fn[0]
  321. result.add fn
  322. func exp*(x: float): float ## get different error if you remove forward declaration
  323. func exp*(x: float): float {.aad.} =
  324. var x1 = min(max(x, -708.4), 709.8)
  325. var result: float ## looks weird because it is taken from template expansion
  326. result = x1 + 1.0
  327. result
  328. template check_accuracy(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
  329. proc check_accuracy: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
  330. let k = (rng.b - rng.a) / (float) n
  331. var
  332. res, x: float
  333. i, max_ulp = 0
  334. avg_ulp = 0.0
  335. x = rng.a
  336. while (i < n):
  337. res = f(x)
  338. i.inc
  339. x = x + 0.001
  340. (avg_ulp, max_ulp)
  341. check_accuracy()
  342. discard check_accuracy(exp, -730.0..709.4, 4)
  343. # And without forward decl
  344. macro aad2*(fns: varargs[typed]): typed =
  345. result = newStmtList()
  346. for fn in fns:
  347. captured_funcs.add fn[0]
  348. result.add fn
  349. func exp2*(x: float): float {.aad2.} =
  350. var x1 = min(max(x, -708.4), 709.8)
  351. var result: float ## looks weird because it is taken from template expansion
  352. result = x1 + 1.0
  353. result
  354. template check_accuracy2(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
  355. proc check_accuracy2: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
  356. let k = (rng.b - rng.a) / (float) n
  357. var
  358. res, x: float
  359. i, max_ulp = 0
  360. avg_ulp = 0.0
  361. x = rng.a
  362. while (i < n):
  363. res = f(x)
  364. i.inc
  365. x = x + 0.001
  366. (avg_ulp, max_ulp)
  367. check_accuracy2()
  368. discard check_accuracy2(exp2, -730.0..709.4, 4)
  369. # And minimized:
  370. macro aadMin(fn: typed): typed = fn
  371. func expMin: float
  372. func expMin: float {.aadMin.} = 1
  373. echo expMin()
  374. # doubly-typed forward decls
  375. macro noop(x: typed) = x
  376. noop:
  377. proc cally() = discard
  378. cally()
  379. noop:
  380. proc barry()
  381. proc barry() = discard
  382. # some more:
  383. proc barry2() {.noop.}
  384. proc barry2() = discard
  385. proc barry3() {.noop.}
  386. proc barry3() {.noop.} = discard
  387. # issue #15389
  388. block double_sem_for_procs:
  389. macro aad(fns: varargs[typed]): typed =
  390. result = newStmtList()
  391. for fn in fns:
  392. result.add fn
  393. func exp(x: float): float {.aad.} =
  394. var x1 = min(max(x, -708.4), 709.8)
  395. if x1 > 0.0:
  396. return x1 + 1.0
  397. result = 10.0
  398. discard exp(5.0)