tparams_gensymed.nim 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. discard """
  2. output: '''
  3. 0
  4. 1
  5. 2
  6. 3
  7. 0
  8. 1
  9. 2
  10. 3
  11. wth
  12. 3
  13. 2
  14. 1
  15. 0
  16. (total: 6)
  17. S1
  18. 5
  19. abc
  20. '''
  21. """
  22. # bug #1915
  23. import macros
  24. # Test that parameters are properly gensym'ed finally:
  25. template genNodeKind(kind, name: untyped) =
  26. proc name*(children: varargs[NimNode]): NimNode {.compiletime.}=
  27. result = newNimNode(kind)
  28. for c in children:
  29. result.add(c)
  30. genNodeKind(nnkNone, None)
  31. # Test that generics in templates still work (regression to fix #1915)
  32. # bug #2004
  33. type Something = object
  34. proc testA(x: Something) = discard
  35. template def(name: untyped) =
  36. proc testB[T](reallyUniqueName: T) =
  37. `test name`(reallyUniqueName)
  38. def A
  39. var x: Something
  40. testB(x)
  41. # bug #2215
  42. # Test that templates in generics still work (regression to fix the
  43. # regression...)
  44. template forStatic(index, slice, predicate: untyped) =
  45. const a = slice.a
  46. const b = slice.b
  47. when a <= b:
  48. template iteration(i: int) =
  49. block:
  50. const index = i
  51. predicate
  52. template iterateStartingFrom(i: int) =
  53. when i <= b:
  54. iteration i
  55. iterateStartingFrom i + 1
  56. iterateStartingFrom a
  57. proc concreteProc(x: int) =
  58. forStatic i, 0..3:
  59. echo i
  60. proc genericProc(x: auto) =
  61. forStatic i, 0..3:
  62. echo i
  63. concreteProc(7) # This works
  64. genericProc(7) # This doesn't compile
  65. import tables
  66. # bug #9476
  67. proc getTypeInfo*(T: typedesc): pointer =
  68. var dummy: T
  69. getTypeInfo(dummy)
  70. macro implementUnary(op: untyped): untyped =
  71. result = newStmtList()
  72. template defineTable(tableSymbol) =
  73. var tableSymbol = initTable[pointer, pointer]()
  74. let tableSymbol = genSym(nskVar, "registeredProcs")
  75. result.add(getAst(defineTable(tableSymbol)))
  76. template defineRegisterInstantiation(tableSym, regTemplSym, instSym, op) =
  77. template regTemplSym*(T: typedesc) =
  78. let ti = getTypeInfo(T)
  79. proc instSym(xOrig: int): int {.gensym, cdecl.} =
  80. let x {.inject.} = xOrig
  81. op
  82. tableSym[ti] = cast[pointer](instSym)
  83. let regTemplSymbol = ident("registerInstantiation")
  84. let instSymbol = ident("instantiation")
  85. result.add(getAst(defineRegisterInstantiation(
  86. tableSymbol, regTemplSymbol, instSymbol, op
  87. )))
  88. echo result.repr
  89. implementUnary(): x*x
  90. registerInstantiation(int)
  91. registerInstantiation(float)
  92. # bug #10192
  93. template nest(body) {.dirty.} =
  94. template p1(b1: untyped) {.dirty, used.} =
  95. template implp1: untyped {.dirty.} = b1
  96. template p2(b2: untyped) {.dirty, used.} =
  97. template implp2: untyped {.dirty.} = b2
  98. body
  99. implp1
  100. implp2
  101. template test() =
  102. nest:
  103. p1:
  104. var foo = "bar"
  105. p2:
  106. doAssert(foo.len == 3)
  107. test()
  108. # regression found in PMunch's parser generator
  109. proc namedcall(arg: string) =
  110. discard
  111. macro m(): untyped =
  112. result = quote do:
  113. (proc (arg: string) =
  114. namedcall(arg = arg)
  115. echo arg)
  116. let meh = m()
  117. meh("wth")
  118. macro foo(body: untyped): untyped =
  119. result = body
  120. template baz(): untyped =
  121. foo:
  122. proc bar2(b: int): int =
  123. echo b
  124. if b > 0: b + bar2(b = b - 1)
  125. else: 0
  126. echo (total: bar2(3))
  127. baz()
  128. # bug #12121
  129. macro state_machine_enum(states: varargs[untyped]) =
  130. result = nnkTypeSection.newTree(
  131. nnkTypeDef.newTree(
  132. nnkPragmaExpr.newTree(ident("State"), nnkPragma.newTree(ident("pure"))),
  133. newEmptyNode(),
  134. nnkEnumTy.newTree(newEmptyNode())
  135. )
  136. )
  137. for s in states:
  138. expectKind(s, nnkIdent)
  139. result[0][2].add s
  140. template mystate_machine(body: untyped) =
  141. state_machine_enum(S1, S2, S3)
  142. var state_stack: seq[State]
  143. template state_current(): State {.inject, used.} =
  144. state_stack[^1]
  145. template state_push(state_name) {.inject, used.} =
  146. state_stack.add State.state_name
  147. template state_pop(n = 1) {.inject, used.} =
  148. state_stack.setLen(state_stack.len - n)
  149. body
  150. mystate_machine:
  151. state_push(S1)
  152. echo state_current()
  153. state_pop()
  154. # bug #15075
  155. block: #Doesn't work
  156. template genGenTempl: untyped =
  157. proc loop(locals: int)
  158. proc loop(locals: int) = discard
  159. genGenTempl()
  160. let pool = loop
  161. block: #Doesn't work
  162. macro genGenMacro: untyped =
  163. quote do:
  164. proc loop(locals: int)
  165. proc loop(locals: int) = discard
  166. genGenMacro()
  167. let pool = loop
  168. block: #This works
  169. proc loop(locals: int)
  170. proc loop(locals: int) = discard
  171. let pool = loop
  172. #Now somewhat recursive:
  173. type Cont = ref object of RootObj
  174. fn*: proc(c: Cont): Cont {.nimcall.}
  175. block: #Doesn't work
  176. template genGenTempl(): untyped =
  177. proc loop(locals: Cont): Cont
  178. proc loop(locals: Cont): Cont =
  179. return Cont(fn: loop)
  180. proc doServer(): Cont =
  181. return Cont(fn: loop)
  182. genGenTempl()
  183. discard doServer()
  184. block: #Doesn't work
  185. macro genGenMacro(): untyped =
  186. quote:
  187. proc loop(locals: Cont): Cont
  188. proc loop(locals: Cont): Cont =
  189. return Cont(fn: loop)
  190. proc doServer(): Cont =
  191. return Cont(fn: loop)
  192. genGenMacro()
  193. discard doServer()
  194. block: #This works
  195. proc loop(locals: Cont): Cont
  196. proc loop(locals: Cont): Cont =
  197. return Cont(fn: loop)
  198. proc doServer(): Cont =
  199. return Cont(fn: loop)
  200. discard doServer()
  201. #And fully recursive:
  202. block: #Doesn't work
  203. template genGenTempl: untyped =
  204. proc loop(locals: int)
  205. proc loop(locals: int) = loop(locals)
  206. genGenTempl()
  207. let pool = loop
  208. block: #Doesn't work
  209. macro genGenMacro: untyped =
  210. quote do:
  211. proc loop(locals: int)
  212. proc loop(locals: int) = loop(locals)
  213. genGenMacro()
  214. let pool = loop
  215. block: #This works
  216. proc loop(locals: int)
  217. proc loop(locals: int) = loop(locals)
  218. let pool = loop
  219. block:
  220. template genAndCallLoop: untyped =
  221. proc loop() {.gensym.}
  222. proc loop() {.gensym.} =
  223. discard
  224. loop()
  225. genAndCallLoop
  226. block: #Fully recursive and gensymmed:
  227. template genGenTempl: untyped =
  228. proc loop(locals: int) {.gensym.}
  229. proc loop(locals: int) {.gensym.} = loop(locals)
  230. let pool = loop
  231. genGenTempl()
  232. block: #Make sure gensymmed symbol doesn't overwrite the forward decl
  233. proc loop()
  234. proc loop() = discard
  235. template genAndCallLoop: untyped =
  236. proc loop() {.gensym.} =
  237. discard
  238. loop()
  239. genAndCallLoop()
  240. template genLoopDecl: untyped =
  241. proc loop()
  242. template genLoopDef: untyped =
  243. proc loop() = discard
  244. block:
  245. genLoopDecl
  246. genLoopDef
  247. loop()
  248. block:
  249. proc loop()
  250. genLoopDef
  251. loop()
  252. block:
  253. genLoopDecl
  254. proc loop() = discard
  255. loop()
  256. block: #Gensymmed sym sharing forward decl
  257. macro genGenMacro: untyped =
  258. let sym = genSym(nskProc, "loop")
  259. nnkStmtList.newTree(
  260. newProc(sym, body = newEmptyNode()),
  261. newCall(sym),
  262. newProc(sym, body = newStmtList()),
  263. )
  264. genGenMacro
  265. # inject pragma on params
  266. template test(procname, body: untyped): untyped =
  267. proc procname(data {.inject.}: var int = 0) =
  268. body
  269. test(hello):
  270. echo data
  271. data = 3
  272. var data = 5
  273. hello(data)
  274. # bug #5691
  275. template bar(x: typed) = discard
  276. macro barry(x: typed) = discard
  277. var a = 0
  278. bar:
  279. var a = 10
  280. barry:
  281. var a = 20
  282. bar:
  283. var b = 10
  284. barry:
  285. var b = 20
  286. var b = 30
  287. # template bar(x: static int) = discard
  288. #You may think that this should work:
  289. # bar((var c = 1; echo "hey"; c))
  290. # echo c
  291. #But it must not! Since this would be incorrect:
  292. # bar((var b = 3; const c = 1; echo "hey"; c))
  293. # echo b # <- b wouldn't exist
  294. discard not (let xx = 1; true)
  295. discard xx
  296. template barrel(a: typed): untyped = a
  297. barrel:
  298. var aa* = 1
  299. var bb = 3
  300. export bb
  301. # Test declaredInScope within params
  302. template test1: untyped =
  303. when not declaredInScope(thing):
  304. var thing {.inject.}: int
  305. proc chunkedReadLoop =
  306. test1
  307. test1
  308. template test2: untyped =
  309. when not not not declaredInScope(thing):
  310. var thing {.inject.}: int
  311. proc chunkedReadLoop2 =
  312. test2
  313. test2
  314. test1(); test2()
  315. block: # bug #22846
  316. template foo2(x: proc (y: string)) =
  317. let f = x
  318. f("abc")
  319. foo2(proc (y: string) = echo y)