tclosure.nim 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. discard """
  2. target: "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 foldr(n: openarray[int], fn: proc (x, y: int): int {.closure}): int =
  42. for i in 0..n.len-1:
  43. result = fn(result, n[i])
  44. proc each(n: openarray[int], fn: proc(x: int) {.closure.}) =
  45. for i in 0..n.len-1:
  46. fn(n[i])
  47. var myData: array[0..4, int] = [0, 1, 2, 3, 4]
  48. proc testA() =
  49. var p = 0
  50. map(myData, proc (x: int): int =
  51. result = x + 1 shl (proc (y: int): int =
  52. return y + p
  53. )(0)
  54. inc(p))
  55. testA()
  56. myData.each do (x: int):
  57. write(stdout, x)
  58. write(stdout, " ")
  59. #OUT 2 4 6 8 10
  60. type
  61. ITest = tuple[
  62. setter: proc(v: int),
  63. getter: proc(): int]
  64. proc getInterf(): ITest =
  65. var shared: int
  66. return (setter: proc (x: int) = shared = x,
  67. getter: proc (): int = return shared)
  68. # bug #5015
  69. type Mutator = proc(matched: string): string {.noSideEffect, gcsafe, locks: 0.}
  70. proc putMutated(
  71. MutatorCount: static[int],
  72. mTable: static[array[MutatorCount, Mutator]], input: string) =
  73. for i in 0..<MutatorCount: echo mTable[i](input)
  74. proc mutator0(matched: string): string =
  75. "foo"
  76. const
  77. mTable = [Mutator(mutator0)]
  78. putMutated(1, mTable, "foo")
  79. block tclosure0:
  80. when true:
  81. # test simple closure within dummy 'main':
  82. proc dummy =
  83. proc main2(param: int) =
  84. var fooB = 23
  85. proc outer(outerParam: string) =
  86. var outerVar = 88
  87. echo outerParam, outerVar
  88. proc inner() =
  89. block Test:
  90. echo fooB, " ", param, outerParam, " ", outerVar
  91. inner()
  92. outer("foo")
  93. main2(24)
  94. dummy()
  95. when true:
  96. proc outer2(x:int) : proc(y:int):int = # curry-ed application
  97. return proc(y:int):int = x*y
  98. var fn = outer2(6) # the closure
  99. echo fn(3) # it works
  100. var rawP = fn.rawProc()
  101. var rawE = fn.rawEnv()
  102. # A type to cast the function pointer into a nimcall
  103. type TimesClosure = proc(a: int, x: pointer): int {.nimcall.}
  104. # Call the function with its closure
  105. echo cast[TimesClosure](rawP)(3, rawE)
  106. when true:
  107. proc outer =
  108. var x, y: int = 99
  109. proc innerA = echo x
  110. proc innerB =
  111. echo y
  112. innerA()
  113. innerA()
  114. innerB()
  115. outer()
  116. when true:
  117. proc indirectDep =
  118. var x, y: int = 99
  119. proc innerA = echo x, " ", y
  120. proc innerB =
  121. innerA()
  122. innerA()
  123. innerB()
  124. indirectDep()
  125. when true:
  126. proc needlessIndirection =
  127. var x, y: int = 99
  128. proc indirection =
  129. var z = 12
  130. proc innerA = echo z, " ", x, " ", y
  131. proc innerB =
  132. innerA()
  133. innerA()
  134. innerB()
  135. indirection()
  136. needlessIndirection()
  137. block tclosure3:
  138. proc main =
  139. const n = 30
  140. for iterations in 0..50_000:
  141. var s: seq[proc(): string {.closure.}] = @[]
  142. for i in 0 .. n-1:
  143. (proc () =
  144. let ii = i
  145. s.add(proc(): string = return $(ii*ii)))()
  146. for i in 0 .. n-1:
  147. let val = s[i]()
  148. if val != $(i*i): echo "bug ", val
  149. if getOccupiedMem() > 5000_000: quit("still a leak!")
  150. echo "success"
  151. main()
  152. import json, tables, sequtils
  153. block tclosure4:
  154. proc run(json_params: OrderedTable) =
  155. let json_elems = json_params["files"].elems
  156. # These fail compilation.
  157. var files = map(json_elems, proc (x: JsonNode): string = x.str)
  158. #var files = json_elems.map do (x: JsonNode) -> string: x.str
  159. let text = """{"files": ["a", "b", "c"]}"""
  160. run((text.parseJson).fields)
  161. import hashes, math
  162. block tclosurebug2:
  163. type
  164. TSlotEnum = enum seEmpty, seFilled, seDeleted
  165. TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
  166. TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
  167. TOrderedKeyValuePair[A, B] = tuple[
  168. slot: TSlotEnum, next: int, key: A, val: B]
  169. TOrderedKeyValuePairSeq[A, B] = seq[TOrderedKeyValuePair[A, B]]
  170. OrderedTable[A, B] = object ## table that remembers insertion order
  171. data: TOrderedKeyValuePairSeq[A, B]
  172. counter, first, last: int
  173. const
  174. growthFactor = 2
  175. proc mustRehash(length, counter: int): bool {.inline.} =
  176. assert(length > counter)
  177. result = (length * 2 < counter * 3) or (length - counter < 4)
  178. proc nextTry(h, maxHash: Hash): Hash {.inline.} =
  179. result = ((5 * h) + 1) and maxHash
  180. template rawGetImpl() {.dirty.} =
  181. var h: Hash = hash(key) and high(t.data) # start with real hash value
  182. while t.data[h].slot != seEmpty:
  183. if t.data[h].key == key and t.data[h].slot == seFilled:
  184. return h
  185. h = nextTry(h, high(t.data))
  186. result = -1
  187. template rawInsertImpl() {.dirty.} =
  188. var h: Hash = hash(key) and high(data)
  189. while data[h].slot == seFilled:
  190. h = nextTry(h, high(data))
  191. data[h].key = key
  192. data[h].val = val
  193. data[h].slot = seFilled
  194. template addImpl() {.dirty.} =
  195. if mustRehash(len(t.data), t.counter): enlarge(t)
  196. rawInsert(t, t.data, key, val)
  197. inc(t.counter)
  198. template putImpl() {.dirty.} =
  199. var index = rawGet(t, key)
  200. if index >= 0:
  201. t.data[index].val = val
  202. else:
  203. addImpl()
  204. proc len[A, B](t: OrderedTable[A, B]): int {.inline.} =
  205. ## returns the number of keys in `t`.
  206. result = t.counter
  207. template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} =
  208. var h = t.first
  209. while h >= 0:
  210. var nxt = t.data[h].next
  211. if t.data[h].slot == seFilled: yieldStmt
  212. h = nxt
  213. iterator pairs[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] =
  214. ## iterates over any (key, value) pair in the table `t` in insertion
  215. ## order.
  216. forAllOrderedPairs:
  217. yield (t.data[h].key, t.data[h].val)
  218. iterator mpairs[A, B](t: var OrderedTable[A, B]): tuple[key: A, val: var B] =
  219. ## iterates over any (key, value) pair in the table `t` in insertion
  220. ## order. The values can be modified.
  221. forAllOrderedPairs:
  222. yield (t.data[h].key, t.data[h].val)
  223. iterator keys[A, B](t: OrderedTable[A, B]): A =
  224. ## iterates over any key in the table `t` in insertion order.
  225. forAllOrderedPairs:
  226. yield t.data[h].key
  227. iterator values[A, B](t: OrderedTable[A, B]): B =
  228. ## iterates over any value in the table `t` in insertion order.
  229. forAllOrderedPairs:
  230. yield t.data[h].val
  231. iterator mvalues[A, B](t: var OrderedTable[A, B]): var B =
  232. ## iterates over any value in the table `t` in insertion order. The values
  233. ## can be modified.
  234. forAllOrderedPairs:
  235. yield t.data[h].val
  236. proc rawGet[A, B](t: OrderedTable[A, B], key: A): int =
  237. rawGetImpl()
  238. proc `[]`[A, B](t: OrderedTable[A, B], key: A): B =
  239. ## retrieves the value at ``t[key]``. If `key` is not in `t`,
  240. ## default empty value for the type `B` is returned
  241. ## and no exception is raised. One can check with ``hasKey`` whether the key
  242. ## exists.
  243. var index = rawGet(t, key)
  244. if index >= 0: result = t.data[index].val
  245. proc mget[A, B](t: var OrderedTable[A, B], key: A): var B =
  246. ## retrieves the value at ``t[key]``. The value can be modified.
  247. ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
  248. var index = rawGet(t, key)
  249. if index >= 0: result = t.data[index].val
  250. else: raise newException(KeyError, "key not found: " & $key)
  251. proc hasKey[A, B](t: OrderedTable[A, B], key: A): bool =
  252. ## returns true iff `key` is in the table `t`.
  253. result = rawGet(t, key) >= 0
  254. proc rawInsert[A, B](t: var OrderedTable[A, B],
  255. data: var TOrderedKeyValuePairSeq[A, B],
  256. key: A, val: B) =
  257. rawInsertImpl()
  258. data[h].next = -1
  259. if t.first < 0: t.first = h
  260. if t.last >= 0: data[t.last].next = h
  261. t.last = h
  262. proc enlarge[A, B](t: var OrderedTable[A, B]) =
  263. var n: TOrderedKeyValuePairSeq[A, B]
  264. newSeq(n, len(t.data) * growthFactor)
  265. var h = t.first
  266. t.first = -1
  267. t.last = -1
  268. while h >= 0:
  269. var nxt = t.data[h].next
  270. if t.data[h].slot == seFilled:
  271. rawInsert(t, n, t.data[h].key, t.data[h].val)
  272. h = nxt
  273. swap(t.data, n)
  274. proc `[]=`[A, B](t: var OrderedTable[A, B], key: A, val: B) =
  275. ## puts a (key, value)-pair into `t`.
  276. putImpl()
  277. proc add[A, B](t: var OrderedTable[A, B], key: A, val: B) =
  278. ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
  279. addImpl()
  280. proc iniOrderedTable[A, B](initialSize=64): OrderedTable[A, B] =
  281. ## creates a new ordered hash table that is empty. `initialSize` needs to be
  282. ## a power of two.
  283. assert isPowerOfTwo(initialSize)
  284. result.counter = 0
  285. result.first = -1
  286. result.last = -1
  287. newSeq(result.data, initialSize)
  288. proc toOrderedTable[A, B](pairs: openarray[tuple[key: A,
  289. val: B]]): OrderedTable[A, B] =
  290. ## creates a new ordered hash table that contains the given `pairs`.
  291. result = iniOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
  292. for key, val in items(pairs): result[key] = val
  293. proc sort[A, B](t: var OrderedTable[A,B],
  294. cmp: proc (x, y: tuple[key: A, val: B]): int {.closure.}) =
  295. ## sorts the ordered table so that the entry with the highest counter comes
  296. ## first. This is destructive (with the advantage of being efficient)!
  297. ## You must not modify `t` afterwards!
  298. ## You can use the iterators `pairs`, `keys`, and `values` to iterate over
  299. ## `t` in the sorted order.
  300. # we use shellsort here; fast enough and simple
  301. var h = 1
  302. while true:
  303. h = 3 * h + 1
  304. if h >= high(t.data): break
  305. while true:
  306. h = h div 3
  307. for i in countup(h, high(t.data)):
  308. var j = i
  309. #echo(t.data.len, " ", j, " - ", h)
  310. #echo(repr(t.data[j-h]))
  311. proc rawCmp(x, y: TOrderedKeyValuePair[A, B]): int =
  312. if x.slot in {seEmpty, seDeleted} and y.slot in {seEmpty, seDeleted}:
  313. return 0
  314. elif x.slot in {seEmpty, seDeleted}:
  315. return -1
  316. elif y.slot in {seEmpty, seDeleted}:
  317. return 1
  318. else:
  319. let item1 = (x.key, x.val)
  320. let item2 = (y.key, y.val)
  321. return cmp(item1, item2)
  322. while rawCmp(t.data[j-h], t.data[j]) <= 0:
  323. swap(t.data[j], t.data[j-h])
  324. j = j-h
  325. if j < h: break
  326. if h == 1: break
  327. import sugar
  328. block inference3304:
  329. type
  330. List[T] = ref object
  331. val: T
  332. proc foo[T](l: List[T]): seq[int] =
  333. @[1,2,3,5].filter(x => x != l.val)
  334. echo(foo(List[int](val: 3)))
  335. block tcodegenerr1923:
  336. type
  337. Foo[M] = proc() : M
  338. proc bar[M](f : Foo[M]) =
  339. discard f()
  340. proc baz() : int = 42
  341. bar(baz)
  342. block doNotation:
  343. type
  344. Button = object
  345. Event = object
  346. x, y: int
  347. proc onClick(x: Button, handler: proc(x: Event)) =
  348. handler(Event(x: 10, y: 20))
  349. proc onFocusLost(x: Button, handler: proc()) =
  350. handler()
  351. proc onUserEvent(x: Button, eventName: string, handler: proc) =
  352. echo "registered handler for ", eventName
  353. var b = Button()
  354. b.onClick do (e: Event):
  355. echo "click at ", e.x, ",", e.y
  356. b.onFocusLost:
  357. echo "lost focus 1"
  358. b.onFocusLost do:
  359. echo "lost focus 2"
  360. b.onUserEvent("UserEvent 1") do:
  361. discard
  362. b.onUserEvent "UserEvent 2":
  363. discard
  364. b.onUserEvent("UserEvent 3"):
  365. discard
  366. b.onUserEvent("UserEvent 4", () => echo "event 4")
  367. import tables
  368. block fib50:
  369. proc memoize(f: proc (a: int64): int64): proc (a: int64): int64 =
  370. var previous = initTable[int64, int64]()
  371. return proc(i: int64): int64 =
  372. if not previous.hasKey i:
  373. previous[i] = f(i)
  374. return previous[i]
  375. var fib: proc(a: int64): int64
  376. fib = memoize(proc (i: int64): int64 =
  377. if i == 0 or i == 1:
  378. return 1
  379. return fib(i-1) + fib(i-2)
  380. )
  381. doAssert fib(50) == 20365011074
  382. block tflatmap:
  383. # bug #3995
  384. type
  385. RNG = tuple[]
  386. Rand[A] = (RNG) -> (A, RNG)
  387. proc nextInt(r: RNG): (int, RNG) =
  388. (1, ())
  389. proc flatMap[A,B](f: Rand[A], g: A -> Rand[B]): Rand[B] =
  390. (rng: RNG) => (
  391. let (a, rng2) = f(rng);
  392. let g1 = g(a);
  393. g1(rng2)
  394. )
  395. proc map[A,B](s: Rand[A], f: A -> B): Rand[B] =
  396. let g: A -> Rand[B] = (a: A) => ((rng: RNG) => (f(a), rng))
  397. flatMap(s, g)
  398. let f = nextInt.map(i => i - i mod 2)
  399. block tforum:
  400. type
  401. PAsyncHttpServer = ref object
  402. value: string
  403. PFutureBase = ref object
  404. callback: proc () {.closure.}
  405. value: string
  406. failed: bool
  407. proc accept(server: PAsyncHttpServer): PFutureBase =
  408. new(result)
  409. result.callback = proc () =
  410. discard
  411. server.value = "hahaha"
  412. proc processClient(): PFutureBase =
  413. new(result)
  414. proc serve(server: PAsyncHttpServer): PFutureBase =
  415. iterator serveIter(): PFutureBase {.closure.} =
  416. echo server.value
  417. while true:
  418. var acceptAddrFut = server.accept()
  419. yield acceptAddrFut
  420. var fut = acceptAddrFut.value
  421. var f = processClient()
  422. f.callback =
  423. proc () =
  424. echo("processClient end")
  425. echo(f.failed)
  426. yield f
  427. var x = serveIter
  428. for i in 0 .. 1:
  429. result = x()
  430. result.callback()
  431. discard serve(PAsyncHttpServer(value: "asdas"))
  432. block futclosure2138:
  433. proc any[T](list: varargs[T], pred: (T) -> bool): bool =
  434. for item in list:
  435. if pred(item):
  436. result = true
  437. break
  438. proc contains(s: string, words: varargs[string]): bool =
  439. any(words, (word) => s.contains(word))
  440. block tinterf:
  441. type
  442. ITest = tuple[
  443. setter: proc(v: int) {.closure.},
  444. getter1: proc(): int {.closure.},
  445. getter2: proc(): int {.closure.}]
  446. proc getInterf(): ITest =
  447. var shared1, shared2: int
  448. return (setter: proc (x: int) =
  449. shared1 = x
  450. shared2 = x + 10,
  451. getter1: proc (): int = result = shared1,
  452. getter2: proc (): int = return shared2)
  453. var i = getInterf()
  454. i.setter(56)
  455. doAssert i.getter1() == 56
  456. doAssert i.getter2() == 66
  457. block tjester:
  458. type
  459. Future[T] = ref object
  460. data: T
  461. callback: proc () {.closure.}
  462. proc cbOuter(response: string) {.discardable.} =
  463. iterator cbIter(): Future[int] {.closure.} =
  464. for i in 0..7:
  465. proc foo(): int =
  466. iterator fooIter(): Future[int] {.closure.} =
  467. echo response, i
  468. yield Future[int](data: 17)
  469. var iterVar = fooIter
  470. iterVar().data
  471. yield Future[int](data: foo())
  472. var iterVar2 = cbIter
  473. proc cb2() {.closure.} =
  474. try:
  475. if not finished(iterVar2):
  476. let next = iterVar2()
  477. if next != nil:
  478. next.callback = cb2
  479. except:
  480. echo "WTF"
  481. cb2()
  482. cbOuter "baro"
  483. block tnamedparamanonproc:
  484. type
  485. PButton = ref object
  486. TButtonClicked = proc(button: PButton) {.nimcall.}
  487. proc newButton(onClick: TButtonClicked) =
  488. discard
  489. proc main() =
  490. newButton(onClick = proc(b: PButton) =
  491. var requestomat = 12
  492. )
  493. main()
  494. block tnestedclosure:
  495. proc main(param: int) =
  496. var foo = 23
  497. proc outer(outerParam: string) =
  498. var outerVar = 88
  499. echo outerParam, outerVar
  500. proc inner() =
  501. block Test:
  502. echo foo, " ", param, outerParam, " ", outerVar
  503. inner()
  504. outer("foo")
  505. # test simple closure within dummy 'main':
  506. proc dummy =
  507. proc main2(param: int) =
  508. var fooB = 23
  509. proc outer(outerParam: string) =
  510. var outerVar = 88
  511. echo outerParam, outerVar
  512. proc inner() =
  513. block Test:
  514. echo fooB, " ", param, outerParam, " ", outerVar
  515. inner()
  516. outer("foo")
  517. main2(24)
  518. dummy()
  519. main(24)
  520. # Jester + async triggered this bug:
  521. proc cbOuter() =
  522. var response = "hohoho"
  523. block:
  524. proc cbIter() =
  525. block:
  526. proc fooIter() =
  527. doAssert response == "hohoho"
  528. fooIter()
  529. cbIter()
  530. cbOuter()
  531. block tnestedproc:
  532. proc p(x, y: int): int =
  533. result = x + y
  534. echo p((proc (): int =
  535. var x = 7
  536. return x)(),
  537. (proc (): int = return 4)())
  538. block tnoclosure:
  539. proc pascal(n: int) =
  540. var row = @[1]
  541. for r in 1..n:
  542. row = zip(row & @[0], @[0] & row).mapIt(it[0] + it[1])
  543. echo row
  544. pascal(10)