tparams_gensymed.nim 7.5 KB

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