tsugar.nim 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. discard """
  2. targets: "c js"
  3. matrix: "--mm:refc; --mm:orc"
  4. output: '''
  5. x + y = 30
  6. '''
  7. """
  8. import std/[sugar, algorithm, random, sets, tables, strutils, sequtils]
  9. import std/[syncio, assertions]
  10. type # for capture test, ref #20679
  11. FooCapture = ref object
  12. x: int
  13. proc mainProc() =
  14. block: # bug #16967
  15. var s = newSeq[proc (): int](5)
  16. {.push exportc.}
  17. proc bar() =
  18. for i in 0 ..< s.len:
  19. let foo = i + 1
  20. capture foo:
  21. s[i] = proc(): int = foo
  22. {.pop.}
  23. bar()
  24. for i, p in s.pairs:
  25. let foo = i + 1
  26. doAssert p() == foo
  27. template main() =
  28. block: # `=>`
  29. block:
  30. let f1 = () => 42
  31. doAssert f1() == 42
  32. let f2 = (x: int) => x + 1
  33. doAssert f2(42) == 43
  34. let f3 = (x, y: int) => x + y
  35. doAssert f3(1, 2) == 3
  36. var x = 0
  37. let f4 = () => (x = 12)
  38. f4()
  39. doAssert x == 12
  40. let f5 = () => (discard) # simplest proc that returns void
  41. f5()
  42. block:
  43. proc call1(f: () -> int): int = f()
  44. doAssert call1(() => 12) == 12
  45. proc call2(f: int -> int): int = f(42)
  46. doAssert call2(x => x) == 42
  47. doAssert call2((x) => x) == 42
  48. doAssert call2((x: int) => x) == 42
  49. proc call3(f: (int, int) -> int): int = f(1, 2)
  50. doAssert call3((x, y) => x + y) == 3
  51. doAssert call3((x, y: int) => x + y) == 3
  52. doAssert call3((x: int, y: int) => x + y) == 3
  53. var a = 0
  54. proc call4(f: int -> void) = f(42)
  55. call4((x: int) => (a = x))
  56. doAssert a == 42
  57. proc call5(f: (int {.noSideEffect.} -> int)): int = f(42)
  58. doAssert call5(x {.noSideEffect.} => x + 1) == 43
  59. block: # `->`
  60. doAssert $(() -> int) == "proc (): int{.closure.}"
  61. doAssert $(float -> int) == "proc (i0: float): int{.closure.}"
  62. doAssert $((float) -> int) == "proc (i0: float): int{.closure.}"
  63. doAssert $((float, bool) -> int) == "proc (i0: float, i1: bool): int{.closure.}"
  64. doAssert $(() -> void) == "proc (){.closure.}"
  65. doAssert $(float -> void) == "proc (i0: float){.closure.}"
  66. doAssert $((float) -> void) == "proc (i0: float){.closure.}"
  67. doAssert $((float, bool) -> void) == "proc (i0: float, i1: bool){.closure.}"
  68. doAssert $(() {.inline.} -> int) == "proc (): int{.inline.}"
  69. doAssert $(float {.inline.} -> int) == "proc (i0: float): int{.inline.}"
  70. doAssert $((float) {.inline.} -> int) == "proc (i0: float): int{.inline.}"
  71. doAssert $((float, bool) {.inline.} -> int) == "proc (i0: float, i1: bool): int{.inline.}"
  72. block: # capture
  73. var closure1: () -> int
  74. for i in 0 .. 10:
  75. if i == 5:
  76. capture i:
  77. closure1 = () => i
  78. doAssert closure1() == 5
  79. var closure2: () -> (int, int)
  80. for i in 0 .. 10:
  81. for j in 0 .. 10:
  82. if i == 5 and j == 3:
  83. capture i, j:
  84. closure2 = () => (i, j)
  85. doAssert closure2() == (5, 3)
  86. block: # issue #20679
  87. # this should compile. Previously was broken as `var int` is an `nnkHiddenDeref`
  88. # which was not handled correctly
  89. block:
  90. var x = 5
  91. var s1 = newSeq[proc (): int](2)
  92. proc function(data: var int) =
  93. for i in 0 ..< 2:
  94. data = (i+1) * data
  95. capture data:
  96. s1[i] = proc(): int = data
  97. function(x)
  98. doAssert s1[0]() == 5
  99. doAssert s1[1]() == 10
  100. block:
  101. var y = @[5, 10]
  102. var s2 = newSeq[proc (): seq[int]](2)
  103. proc functionS(data: var seq[int]) =
  104. for i in 0 ..< 2:
  105. data.add (i+1) * 5
  106. capture data:
  107. s2[i] = proc(): seq[int] = data
  108. functionS(y)
  109. doAssert s2[0]() == @[5, 10, 5]
  110. doAssert s2[1]() == @[5, 10, 5, 10]
  111. template typeT(typ, val: untyped): untyped =
  112. var x = val
  113. var s = newSeq[proc (): typ](2)
  114. proc functionT[T](data: var T) =
  115. for i in 0 ..< 2:
  116. if i == 1:
  117. data = default(T)
  118. capture data:
  119. s[i] = proc (): T = data
  120. functionT(x)
  121. doAssert s[0]() == val
  122. doAssert s[1]() == x # == default
  123. doAssert s[1]() == default(typ)
  124. block:
  125. var x = 1.1
  126. typeT(float, x)
  127. block:
  128. var x = "hello"
  129. typeT(string, x)
  130. block:
  131. var f = FooCapture(x: 5)
  132. typeT(FooCapture, f)
  133. block: # dup
  134. block dup_with_field:
  135. type
  136. Foo = object
  137. col, pos: int
  138. name: string
  139. proc inc_col(foo: var Foo) = inc(foo.col)
  140. proc inc_pos(foo: var Foo) = inc(foo.pos)
  141. proc name_append(foo: var Foo, s: string) = foo.name &= s
  142. let a = Foo(col: 1, pos: 2, name: "foo")
  143. block:
  144. let b = a.dup(inc_col, inc_pos):
  145. _.pos = 3
  146. name_append("bar")
  147. inc_pos
  148. doAssert(b == Foo(col: 2, pos: 4, name: "foobar"))
  149. block:
  150. let b = a.dup(inc_col, pos = 3, name = "bar"):
  151. name_append("bar")
  152. inc_pos
  153. doAssert(b == Foo(col: 2, pos: 4, name: "barbar"))
  154. block:
  155. var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
  156. doAssert dup(a, sort(_)) == sorted(a)
  157. doAssert a.dup(sort) == sorted(a)
  158. # Chaining:
  159. var aCopy = a
  160. aCopy.insert(10)
  161. doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy)
  162. block:
  163. when nimvm: discard
  164. else:
  165. const b = @[0, 1, 2]
  166. discard b.dup shuffle()
  167. doAssert b[0] == 0
  168. doAssert b[1] == 1
  169. block: # collect
  170. let data = @["bird", "word"] # if this gets stuck in your head, its not my fault
  171. doAssert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"]
  172. doAssert collect(initTable(2), for (i, d) in data.pairs: {i: d}) ==
  173. {0: "bird", 1: "word"}.toTable
  174. doAssert collect(initHashSet(), for d in data.items: {d}) == data.toHashSet
  175. block:
  176. let x = collect(newSeqOfCap(4)):
  177. for (i, d) in data.pairs:
  178. if i mod 2 == 0: d
  179. doAssert x == @["bird"]
  180. block: # bug #12874
  181. let bug = collect(
  182. newSeq,
  183. for (i, d) in data.pairs:(
  184. block:
  185. if i mod 2 == 0:
  186. d
  187. else:
  188. d & d
  189. )
  190. )
  191. doAssert bug == @["bird", "wordword"]
  192. block:
  193. let y = collect(newSeq):
  194. for (i, d) in data.pairs:
  195. try: parseInt(d) except: 0
  196. doAssert y == @[0, 0]
  197. block:
  198. let z = collect(newSeq):
  199. for (i, d) in data.pairs:
  200. case d
  201. of "bird": "word"
  202. else: d
  203. doAssert z == @["word", "word"]
  204. block:
  205. proc tforum(): seq[int] =
  206. collect(newSeq):
  207. for y in 0..10:
  208. if y mod 5 == 2:
  209. for x in 0..y:
  210. x
  211. doAssert tforum() == @[0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7]
  212. block:
  213. let x = collect:
  214. for d in data.items:
  215. when d is int: "word"
  216. else: d
  217. doAssert x == @["bird", "word"]
  218. block:
  219. doAssert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")]
  220. doAssert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0]
  221. doAssert collect(for (i, d) in pairs(data): {i: d}) ==
  222. {1: "word", 0: "bird"}.toTable
  223. doAssert collect(for d in data.items: {d}) == data.toHashSet
  224. block: # bug #14332
  225. template foo =
  226. discard collect(newSeq, for i in 1..3: i)
  227. foo()
  228. block: # dump
  229. # symbols in templates are gensym'd
  230. let
  231. x {.inject.} = 10
  232. y {.inject.} = 20
  233. dump(x + y) # x + y = 30
  234. block: # dumpToString
  235. template square(x): untyped = x * x
  236. let x {.inject.} = 10
  237. doAssert dumpToString(square(x)) == "square(x): x * x = 100"
  238. let s = dumpToString(doAssert 1+1 == 2)
  239. doAssert "failedAssertImpl" in s
  240. let s2 = dumpToString:
  241. doAssertRaises(AssertionDefect): doAssert false
  242. doAssert "except AssertionDefect" in s2
  243. block: # bug #20704
  244. proc test() =
  245. var xs, ys: seq[int]
  246. for i in 0..5:
  247. xs.add(i)
  248. xs.apply(proc (d: auto) = ys.add(d))
  249. # ^ can be turned into d => ys.add(d) when we can infer void return type, #16906
  250. doAssert ys == @[0, 1, 2, 3, 4, 5]
  251. test()
  252. mainProc()
  253. when not defined(js): # TODO fixme JS VM
  254. static:
  255. main()
  256. main()