macrocache.nim 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2018 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module provides an API for macros to collect compile-time information
  10. ## across module boundaries. It should be used instead of global `{.compileTime.}`
  11. ## variables as those break incremental compilation.
  12. ##
  13. ## The main feature of this module is that if you create `CacheTable`s or
  14. ## any other `Cache` types with the same name in different modules, their
  15. ## content will be shared, meaning that you can fill a `CacheTable` in
  16. ## one module, and iterate over its contents in another.
  17. runnableExamples:
  18. import std/macros
  19. const mcTable = CacheTable"myTable"
  20. const mcSeq = CacheSeq"mySeq"
  21. const mcCounter = CacheCounter"myCounter"
  22. static:
  23. # add new key "val" with the value `myval`
  24. let myval = newLit("hello ic")
  25. mcTable["val"] = myval
  26. assert mcTable["val"].kind == nnkStrLit
  27. # Can access the same cache from different static contexts
  28. # All the information is retained
  29. static:
  30. # get value from `mcTable` and add it to `mcSeq`
  31. mcSeq.add(mcTable["val"])
  32. assert mcSeq.len == 1
  33. static:
  34. assert mcSeq[0].strVal == "hello ic"
  35. # increase `mcCounter` by 3
  36. mcCounter.inc(3)
  37. assert mcCounter.value == 3
  38. when defined(nimPreviewSlimSystem):
  39. import std/assertions
  40. type
  41. CacheSeq* = distinct string
  42. ## Compile-time sequence of `NimNode`s.
  43. CacheTable* = distinct string
  44. ## Compile-time table of key-value pairs.
  45. ##
  46. ## Keys are `string`s and values are `NimNode`s.
  47. CacheCounter* = distinct string
  48. ## Compile-time counter, uses `int` for storing the count.
  49. proc value*(c: CacheCounter): int {.magic: "NccValue".} =
  50. ## Returns the value of a counter `c`.
  51. runnableExamples:
  52. static:
  53. let counter = CacheCounter"valTest"
  54. # default value is 0
  55. assert counter.value == 0
  56. inc counter
  57. assert counter.value == 1
  58. proc inc*(c: CacheCounter; by = 1) {.magic: "NccInc".} =
  59. ## Increments the counter `c` with the value `by`.
  60. runnableExamples:
  61. static:
  62. let counter = CacheCounter"incTest"
  63. inc counter
  64. inc counter, 5
  65. assert counter.value == 6
  66. proc add*(s: CacheSeq; value: NimNode) {.magic: "NcsAdd".} =
  67. ## Adds `value` to `s`.
  68. runnableExamples:
  69. import std/macros
  70. const mySeq = CacheSeq"addTest"
  71. static:
  72. mySeq.add(newLit(5))
  73. mySeq.add(newLit("hello ic"))
  74. assert mySeq.len == 2
  75. assert mySeq[1].strVal == "hello ic"
  76. proc incl*(s: CacheSeq; value: NimNode) {.magic: "NcsIncl".} =
  77. ## Adds `value` to `s`.
  78. ##
  79. ## .. hint:: This doesn't do anything if `value` is already in `s`.
  80. runnableExamples:
  81. import std/macros
  82. const mySeq = CacheSeq"inclTest"
  83. static:
  84. mySeq.incl(newLit(5))
  85. mySeq.incl(newLit(5))
  86. # still one element
  87. assert mySeq.len == 1
  88. proc len*(s: CacheSeq): int {.magic: "NcsLen".} =
  89. ## Returns the length of `s`.
  90. runnableExamples:
  91. import std/macros
  92. const mySeq = CacheSeq"lenTest"
  93. static:
  94. let val = newLit("helper")
  95. mySeq.add(val)
  96. assert mySeq.len == 1
  97. mySeq.add(val)
  98. assert mySeq.len == 2
  99. proc `[]`*(s: CacheSeq; i: int): NimNode {.magic: "NcsAt".} =
  100. ## Returns the `i`th value from `s`.
  101. runnableExamples:
  102. import std/macros
  103. const mySeq = CacheSeq"subTest"
  104. static:
  105. mySeq.add(newLit(42))
  106. assert mySeq[0].intVal == 42
  107. proc `[]`*(s: CacheSeq; i: BackwardsIndex): NimNode =
  108. ## Returns the `i`th last value from `s`.
  109. runnableExamples:
  110. import std/macros
  111. const mySeq = CacheSeq"backTest"
  112. static:
  113. mySeq &= newLit(42)
  114. mySeq &= newLit(7)
  115. assert mySeq[^1].intVal == 7 # Last item
  116. assert mySeq[^2].intVal == 42 # Second last item
  117. s[s.len - int(i)]
  118. iterator items*(s: CacheSeq): NimNode =
  119. ## Iterates over each item in `s`.
  120. runnableExamples:
  121. import std/macros
  122. const myseq = CacheSeq"itemsTest"
  123. static:
  124. myseq.add(newLit(5))
  125. myseq.add(newLit(42))
  126. for val in myseq:
  127. # check that all values in `myseq` are int literals
  128. assert val.kind == nnkIntLit
  129. for i in 0 ..< len(s): yield s[i]
  130. proc `[]=`*(t: CacheTable; key: string, value: NimNode) {.magic: "NctPut".} =
  131. ## Inserts a `(key, value)` pair into `t`.
  132. ##
  133. ## .. warning:: `key` has to be unique! Assigning `value` to a `key` that is already
  134. ## in the table will result in a compiler error.
  135. runnableExamples:
  136. import std/macros
  137. const mcTable = CacheTable"subTest"
  138. static:
  139. # assign newLit(5) to the key "value"
  140. mcTable["value"] = newLit(5)
  141. # check that we can get the value back
  142. assert mcTable["value"].kind == nnkIntLit
  143. proc len*(t: CacheTable): int {.magic: "NctLen".} =
  144. ## Returns the number of elements in `t`.
  145. runnableExamples:
  146. import std/macros
  147. const dataTable = CacheTable"lenTest"
  148. static:
  149. dataTable["key"] = newLit(5)
  150. assert dataTable.len == 1
  151. proc `[]`*(t: CacheTable; key: string): NimNode {.magic: "NctGet".} =
  152. ## Retrieves the `NimNode` value at `t[key]`.
  153. runnableExamples:
  154. import std/macros
  155. const mcTable = CacheTable"subTest"
  156. static:
  157. mcTable["toAdd"] = newStmtList()
  158. # get the NimNode back
  159. assert mcTable["toAdd"].kind == nnkStmtList
  160. proc hasKey*(t: CacheTable; key: string): bool =
  161. ## Returns true if `key` is in the table `t`.
  162. ##
  163. ## See also:
  164. ## * [contains proc][contains(CacheTable, string)] for use with the `in` operator
  165. runnableExamples:
  166. import std/macros
  167. const mcTable = CacheTable"hasKeyEx"
  168. static:
  169. assert not mcTable.hasKey("foo")
  170. mcTable["foo"] = newEmptyNode()
  171. # Will now be true since we inserted a value
  172. assert mcTable.hasKey("foo")
  173. raiseAssert "implemented in the vmops"
  174. proc contains*(t: CacheTable; key: string): bool {.inline.} =
  175. ## Alias of [hasKey][hasKey(CacheTable, string)] for use with the `in` operator.
  176. runnableExamples:
  177. import std/macros
  178. const mcTable = CacheTable"containsEx"
  179. static:
  180. mcTable["foo"] = newEmptyNode()
  181. # Will be true since we gave it a value before
  182. assert "foo" in mcTable
  183. t.hasKey(key)
  184. proc hasNext(t: CacheTable; iter: int): bool {.magic: "NctHasNext".}
  185. proc next(t: CacheTable; iter: int): (string, NimNode, int) {.magic: "NctNext".}
  186. iterator pairs*(t: CacheTable): (string, NimNode) =
  187. ## Iterates over all `(key, value)` pairs in `t`.
  188. runnableExamples:
  189. import std/macros
  190. const mytabl = CacheTable"values"
  191. static:
  192. mytabl["intVal"] = newLit(5)
  193. mytabl["otherVal"] = newLit(6)
  194. for key, val in mytabl:
  195. # make sure that we actually get the same keys
  196. assert key in ["intVal", "otherVal"]
  197. # all vals are int literals
  198. assert val.kind == nnkIntLit
  199. var h = 0
  200. while hasNext(t, h):
  201. let (a, b, h2) = next(t, h)
  202. yield (a, b)
  203. h = h2