tclosure.nim 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. discard """
  2. targets: "c"
  3. output: '''
  4. 1 3 6 11 20 foo
  5. foo88
  6. 23 24foo 88
  7. 18
  8. 18
  9. 99
  10. 99
  11. 99
  12. 99 99
  13. 99 99
  14. 12 99 99
  15. 12 99 99
  16. success
  17. @[1, 2, 5]
  18. click at 10,20
  19. lost focus 1
  20. lost focus 2
  21. registered handler for UserEvent 1
  22. registered handler for UserEvent 2
  23. registered handler for UserEvent 3
  24. registered handler for UserEvent 4
  25. asdas
  26. processClient end
  27. false
  28. baro0
  29. foo88
  30. 23 24foo 88
  31. foo88
  32. 23 24foo 88
  33. 11
  34. @[1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]
  35. '''
  36. joinable: false
  37. """
  38. block tclosure:
  39. proc map(n: var openArray[int], fn: proc (x: int): int {.closure}) =
  40. for i in 0..n.len-1: n[i] = fn(n[i])
  41. proc each(n: openArray[int], fn: proc(x: int) {.closure.}) =
  42. for i in 0..n.len-1:
  43. fn(n[i])
  44. var myData: array[0..4, int] = [0, 1, 2, 3, 4]
  45. proc testA() =
  46. var p = 0
  47. map(myData, proc (x: int): int =
  48. result = x + 1 shl (proc (y: int): int =
  49. return y + p
  50. )(0)
  51. inc(p))
  52. testA()
  53. myData.each do (x: int):
  54. write(stdout, x)
  55. write(stdout, " ")
  56. #OUT 2 4 6 8 10
  57. # bug #5015
  58. type Mutator = proc(matched: string): string {.noSideEffect, gcsafe.}
  59. proc putMutated(
  60. MutatorCount: static[int],
  61. mTable: static[array[MutatorCount, Mutator]], input: string) =
  62. for i in 0..<MutatorCount: echo mTable[i](input)
  63. proc mutator0(matched: string): string =
  64. "foo"
  65. const
  66. mTable = [Mutator(mutator0)]
  67. putMutated(1, mTable, "foo")
  68. block tclosure0:
  69. when true:
  70. # test simple closure within dummy 'main':
  71. proc dummy =
  72. proc main2(param: int) =
  73. var fooB = 23
  74. proc outer(outerParam: string) =
  75. var outerVar = 88
  76. echo outerParam, outerVar
  77. proc inner() =
  78. block Test:
  79. echo fooB, " ", param, outerParam, " ", outerVar
  80. inner()
  81. outer("foo")
  82. main2(24)
  83. dummy()
  84. when true:
  85. proc outer2(x:int) : proc(y:int):int = # curry-ed application
  86. return proc(y:int):int = x*y
  87. var fn = outer2(6) # the closure
  88. echo fn(3) # it works
  89. var rawP = fn.rawProc()
  90. var rawE = fn.rawEnv()
  91. # A type to cast the function pointer into a nimcall
  92. type TimesClosure = proc(a: int, x: pointer): int {.nimcall.}
  93. # Call the function with its closure
  94. echo cast[TimesClosure](rawP)(3, rawE)
  95. when true:
  96. proc outer =
  97. var x, y: int = 99
  98. proc innerA = echo x
  99. proc innerB =
  100. echo y
  101. innerA()
  102. innerA()
  103. innerB()
  104. outer()
  105. when true:
  106. proc indirectDep =
  107. var x, y: int = 99
  108. proc innerA = echo x, " ", y
  109. proc innerB =
  110. innerA()
  111. innerA()
  112. innerB()
  113. indirectDep()
  114. when true:
  115. proc needlessIndirection =
  116. var x, y: int = 99
  117. proc indirection =
  118. var z = 12
  119. proc innerA = echo z, " ", x, " ", y
  120. proc innerB =
  121. innerA()
  122. innerA()
  123. innerB()
  124. indirection()
  125. needlessIndirection()
  126. block tclosure3:
  127. proc main =
  128. const n = 30
  129. for iterations in 0..10_000:
  130. var s: seq[proc(): string {.closure.}] = @[]
  131. for i in 0 .. n-1:
  132. (proc () =
  133. let ii = i
  134. s.add(proc(): string = return $(ii*ii)))()
  135. for i in 0 .. n-1:
  136. let val = s[i]()
  137. if val != $(i*i): echo "bug ", val
  138. if getOccupiedMem() > 5000_000: quit("still a leak!")
  139. echo "success"
  140. main()
  141. import json, tables, sequtils
  142. block tclosure4:
  143. proc run(json_params: OrderedTable) =
  144. let json_elems = json_params["files"].elems
  145. # These fail compilation.
  146. var files = map(json_elems, proc (x: JsonNode): string = x.str)
  147. let text = """{"files": ["a", "b", "c"]}"""
  148. run((text.parseJson).fields)
  149. import sugar
  150. block inference3304:
  151. type
  152. List[T] = ref object
  153. val: T
  154. proc foo[T](l: List[T]): seq[int] =
  155. @[1,2,3,5].filter(x => x != l.val)
  156. echo(foo(List[int](val: 3)))
  157. block tcodegenerr1923:
  158. type
  159. Foo[M] = proc() : M
  160. proc bar[M](f : Foo[M]) =
  161. discard f()
  162. proc baz() : int = 42
  163. bar(baz)
  164. block doNotation:
  165. type
  166. Button = object
  167. Event = object
  168. x, y: int
  169. proc onClick(x: Button, handler: proc(x: Event)) =
  170. handler(Event(x: 10, y: 20))
  171. proc onFocusLost(x: Button, handler: proc()) =
  172. handler()
  173. proc onUserEvent(x: Button, eventName: string, handler: proc) =
  174. echo "registered handler for ", eventName
  175. var b = Button()
  176. b.onClick do (e: Event):
  177. echo "click at ", e.x, ",", e.y
  178. b.onFocusLost do ():
  179. echo "lost focus 1"
  180. b.onFocusLost do ():
  181. echo "lost focus 2"
  182. b.onUserEvent("UserEvent 1") do ():
  183. discard
  184. onUserEvent(b, "UserEvent 2") do ():
  185. discard
  186. b.onUserEvent("UserEvent 3") do ():
  187. discard
  188. b.onUserEvent("UserEvent 4", () => echo "event 4")
  189. import tables
  190. block fib50:
  191. proc memoize(f: proc (a: int64): int64): proc (a: int64): int64 =
  192. var previous = initTable[int64, int64]()
  193. return proc(i: int64): int64 =
  194. if not previous.hasKey i:
  195. previous[i] = f(i)
  196. return previous[i]
  197. var fib: proc(a: int64): int64
  198. fib = memoize(proc (i: int64): int64 =
  199. if i == 0 or i == 1:
  200. return 1
  201. return fib(i-1) + fib(i-2)
  202. )
  203. doAssert fib(50) == 20365011074
  204. block tflatmap:
  205. # bug #3995
  206. type
  207. RNG = tuple[]
  208. Rand[A] = (RNG) -> (A, RNG)
  209. proc nextInt(r: RNG): (int, RNG) =
  210. (1, ())
  211. proc flatMap[A,B](f: Rand[A], g: A -> Rand[B]): Rand[B] =
  212. (rng: RNG) => (
  213. let (a, rng2) = f(rng);
  214. let g1 = g(a);
  215. g1(rng2)
  216. )
  217. proc map[A,B](s: Rand[A], f: A -> B): Rand[B] =
  218. let g: A -> Rand[B] = (a: A) => ((rng: RNG) => (f(a), rng))
  219. flatMap(s, g)
  220. discard nextInt.map(i => i - i mod 2)
  221. block tforum:
  222. type
  223. PAsyncHttpServer = ref object
  224. value: string
  225. PFutureBase = ref object
  226. callback: proc () {.closure.}
  227. value: string
  228. failed: bool
  229. proc accept(server: PAsyncHttpServer): PFutureBase =
  230. new(result)
  231. result.callback = proc () =
  232. discard
  233. server.value = "hahaha"
  234. proc processClient(): PFutureBase =
  235. new(result)
  236. proc serve(server: PAsyncHttpServer): PFutureBase =
  237. iterator serveIter(): PFutureBase {.closure.} =
  238. echo server.value
  239. while true:
  240. var acceptAddrFut = server.accept()
  241. yield acceptAddrFut
  242. var fut = acceptAddrFut.value
  243. var f = processClient()
  244. f.callback =
  245. proc () =
  246. echo("processClient end")
  247. echo(f.failed)
  248. yield f
  249. var x = serveIter
  250. for i in 0 .. 1:
  251. result = x()
  252. result.callback()
  253. discard serve(PAsyncHttpServer(value: "asdas"))
  254. block futclosure2138:
  255. proc any[T](list: varargs[T], pred: (T) -> bool): bool =
  256. for item in list:
  257. if pred(item):
  258. result = true
  259. break
  260. proc contains(s: string, words: varargs[string]): bool =
  261. any(words, (word) => s.contains(word))
  262. block tinterf:
  263. type
  264. ITest = tuple[
  265. setter: proc(v: int) {.closure.},
  266. getter1: proc(): int {.closure.},
  267. getter2: proc(): int {.closure.}]
  268. proc getInterf(): ITest =
  269. var shared1, shared2: int
  270. return (setter: proc (x: int) =
  271. shared1 = x
  272. shared2 = x + 10,
  273. getter1: proc (): int = result = shared1,
  274. getter2: proc (): int = return shared2)
  275. var i = getInterf()
  276. i.setter(56)
  277. doAssert i.getter1() == 56
  278. doAssert i.getter2() == 66
  279. block tjester:
  280. type
  281. Future[T] = ref object
  282. data: T
  283. callback: proc () {.closure.}
  284. proc cbOuter(response: string) {.discardable.} =
  285. iterator cbIter(): Future[int] {.closure.} =
  286. for i in 0..7:
  287. proc foo(): int =
  288. iterator fooIter(): Future[int] {.closure.} =
  289. echo response, i
  290. yield Future[int](data: 17)
  291. var iterVar = fooIter
  292. iterVar().data
  293. yield Future[int](data: foo())
  294. var iterVar2 = cbIter
  295. proc cb2() {.closure.} =
  296. try:
  297. if not finished(iterVar2):
  298. let next = iterVar2()
  299. if next != nil:
  300. next.callback = cb2
  301. except:
  302. echo "WTF"
  303. cb2()
  304. cbOuter "baro"
  305. block tnamedparamanonproc:
  306. type
  307. PButton = ref object
  308. TButtonClicked = proc(button: PButton) {.nimcall.}
  309. proc newButton(onClick: TButtonClicked) =
  310. discard
  311. proc main() =
  312. newButton(onClick = proc(b: PButton) =
  313. var requestomat = 12
  314. )
  315. main()
  316. block tnestedclosure:
  317. proc main(param: int) =
  318. var foo = 23
  319. proc outer(outerParam: string) =
  320. var outerVar = 88
  321. echo outerParam, outerVar
  322. proc inner() =
  323. block Test:
  324. echo foo, " ", param, outerParam, " ", outerVar
  325. inner()
  326. outer("foo")
  327. # test simple closure within dummy 'main':
  328. proc dummy =
  329. proc main2(param: int) =
  330. var fooB = 23
  331. proc outer(outerParam: string) =
  332. var outerVar = 88
  333. echo outerParam, outerVar
  334. proc inner() =
  335. block Test:
  336. echo fooB, " ", param, outerParam, " ", outerVar
  337. inner()
  338. outer("foo")
  339. main2(24)
  340. dummy()
  341. main(24)
  342. # Jester + async triggered this bug:
  343. proc cbOuter() =
  344. var response = "hohoho"
  345. block:
  346. proc cbIter() =
  347. block:
  348. proc fooIter() =
  349. doAssert response == "hohoho"
  350. fooIter()
  351. cbIter()
  352. cbOuter()
  353. block tnestedproc:
  354. proc p(x, y: int): int =
  355. result = x + y
  356. echo p((proc (): int =
  357. var x = 7
  358. return x)(),
  359. (proc (): int = return 4)())
  360. block tnoclosure:
  361. proc pascal(n: int) =
  362. var row = @[1]
  363. for r in 1..n:
  364. row = zip(row & @[0], @[0] & row).mapIt(it[0] + it[1])
  365. echo row
  366. pascal(10)