tcustom_pragma.nim 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. {.experimental: "notnil".}
  2. import macros, asyncmacro, asyncfutures
  3. block:
  4. template myAttr() {.pragma.}
  5. proc myProc():int {.myAttr.} = 2
  6. const hasMyAttr = myProc.hasCustomPragma(myAttr)
  7. static:
  8. assert(hasMyAttr)
  9. block:
  10. template myAttr(a: string) {.pragma.}
  11. type
  12. MyObj = object
  13. myField1, myField2 {.myAttr: "hi".}: int
  14. var o: MyObj
  15. static:
  16. assert o.myField2.hasCustomPragma(myAttr)
  17. assert(not o.myField1.hasCustomPragma(myAttr))
  18. import custom_pragma
  19. block: # A bit more advanced case
  20. type
  21. Subfield {.defaultValue: "catman".} = object
  22. `c`* {.serializationKey: "cc".}: float
  23. MySerializable = object
  24. a {.serializationKey"asdf", defaultValue: 5.} : int
  25. b {.custom_pragma.defaultValue"hello".} : int
  26. field: Subfield
  27. d {.alternativeKey("df", 5).}: float
  28. e {.alternativeKey(V = 5).}: seq[bool]
  29. proc myproc(x: int, s: string) {.alternativeKey(V = 5), serializationKey"myprocSS".} =
  30. echo x, s
  31. var s: MySerializable
  32. const aDefVal = s.a.getCustomPragmaVal(defaultValue)
  33. static: assert(aDefVal == 5)
  34. const aSerKey = s.a.getCustomPragmaVal(serializationKey)
  35. static: assert(aSerKey == "asdf")
  36. const cSerKey = getCustomPragmaVal(s.field.c, serializationKey)
  37. static: assert(cSerKey == "cc")
  38. const procSerKey = getCustomPragmaVal(myproc, serializationKey)
  39. static: assert(procSerKey == "myprocSS")
  40. static: assert(hasCustomPragma(myproc, alternativeKey))
  41. const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue)
  42. static: assert(hasFieldCustomPragma == false)
  43. # pragma on an object
  44. static:
  45. assert Subfield.hasCustomPragma(defaultValue)
  46. assert(Subfield.getCustomPragmaVal(defaultValue) == "catman")
  47. assert hasCustomPragma(type(s.field), defaultValue)
  48. proc foo(s: var MySerializable) =
  49. static: assert(s.a.getCustomPragmaVal(defaultValue) == 5)
  50. foo(s)
  51. block: # ref types
  52. type
  53. Node = object of RootObj
  54. left {.serializationKey:"l".}, right {.serializationKey:"r".}: NodeRef
  55. NodeRef = ref Node
  56. NodePtr = ptr Node
  57. SpecialNodeRef = ref object of NodeRef
  58. data {.defaultValue"none".}: string
  59. MyFile {.defaultValue: "closed".} = ref object
  60. path {.defaultValue: "invalid".}: string
  61. TypeWithoutPragma = object
  62. var s = NodeRef()
  63. const
  64. leftSerKey = getCustomPragmaVal(s.left, serializationKey)
  65. rightSerKey = getCustomPragmaVal(s.right, serializationKey)
  66. static:
  67. assert leftSerKey == "l"
  68. assert rightSerKey == "r"
  69. var specS = SpecialNodeRef()
  70. const
  71. dataDefVal = hasCustomPragma(specS.data, defaultValue)
  72. specLeftSerKey = hasCustomPragma(specS.left, serializationKey)
  73. static:
  74. assert dataDefVal == true
  75. assert specLeftSerKey == true
  76. var ptrS = NodePtr(nil)
  77. const
  78. ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey)
  79. static:
  80. assert ptrRightSerKey == "r"
  81. var f = MyFile()
  82. const
  83. fileDefVal = f.getCustomPragmaVal(defaultValue)
  84. filePathDefVal = f.path.getCustomPragmaVal(defaultValue)
  85. static:
  86. assert fileDefVal == "closed"
  87. assert filePathDefVal == "invalid"
  88. static:
  89. assert TypeWithoutPragma.hasCustomPragma(defaultValue) == false
  90. block:
  91. type
  92. VariantKind = enum
  93. variInt,
  94. variFloat
  95. variString
  96. variNestedCase
  97. Variant = object
  98. case kind: VariantKind
  99. of variInt: integer {.serializationKey: "int".}: BiggestInt
  100. of variFloat: floatp: BiggestFloat
  101. of variString: str {.serializationKey: "string".}: string
  102. of variNestedCase:
  103. case nestedKind: VariantKind
  104. of variInt..variNestedCase: nestedItem {.defaultValue: "Nimmers of the world, unite!".}: int
  105. let vari = Variant(kind: variInt)
  106. const
  107. hasIntSerKey = vari.integer.hasCustomPragma(serializationKey)
  108. strSerKey = vari.str.getCustomPragmaVal(serializationKey)
  109. nestedItemDefVal = vari.nestedItem.getCustomPragmaVal(defaultValue)
  110. static:
  111. assert hasIntSerKey
  112. assert strSerKey == "string"
  113. assert nestedItemDefVal == "Nimmers of the world, unite!"
  114. block:
  115. template simpleAttr {.pragma.}
  116. type Annotated {.simpleAttr.} = object
  117. proc generic_proc[T]() =
  118. assert Annotated.hasCustomPragma(simpleAttr)
  119. #--------------------------------------------------------------------------
  120. # Pragma on proc type
  121. let a: proc(x: int) {.defaultValue(5).} = nil
  122. static:
  123. doAssert hasCustomPragma(a.type, defaultValue)
  124. # bug #8371
  125. template thingy {.pragma.}
  126. type
  127. Cardinal = enum
  128. north, east, south, west
  129. Something = object
  130. a: float32
  131. case cardinal: Cardinal
  132. of north:
  133. b {.thingy.}: int
  134. of east:
  135. c: int
  136. of south: discard
  137. else: discard
  138. var foo: Something
  139. foo.cardinal = north
  140. doAssert foo.b.hasCustomPragma(thingy) == true
  141. proc myproc(s: string): int =
  142. {.thingy.}:
  143. s.len
  144. doAssert myproc("123") == 3
  145. let xx = compiles:
  146. proc myproc_bad(s: string): int =
  147. {.not_exist.}:
  148. s.len
  149. doAssert: xx == false
  150. macro checkSym(s: typed{nkSym}): untyped =
  151. let body = s.getImpl.body
  152. doAssert body[1].kind == nnkPragmaBlock
  153. doAssert body[1][0].kind == nnkPragma
  154. doAssert body[1][0][0] == bindSym"thingy"
  155. checkSym(myproc)
  156. # var and let pragmas
  157. block:
  158. template myAttr() {.pragma.}
  159. template myAttr2(x: int) {.pragma.}
  160. template myAttr3(x: string) {.pragma.}
  161. type
  162. MyObj2 = ref object
  163. MyObjNotNil = MyObj2 not nil
  164. let a {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0
  165. let b {.myAttr,myAttr2(2),myAttr3:"test".} = 0
  166. var x {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0
  167. var y {.myAttr,myAttr2(2),myAttr3:"test".}: int
  168. var z {.myAttr,myAttr2(2),myAttr3:"test".} = 0
  169. var z2 {.myAttr.}: MyObjNotNil
  170. template check(s: untyped) =
  171. doAssert s.hasCustomPragma(myAttr)
  172. doAssert s.hasCustomPragma(myAttr2)
  173. doAssert s.getCustomPragmaVal(myAttr2) == 2
  174. doAssert s.hasCustomPragma(myAttr3)
  175. doAssert s.getCustomPragmaVal(myAttr3) == "test"
  176. check(a)
  177. check(b)
  178. check(x)
  179. check(y)
  180. check(z)
  181. # pragma with multiple fields
  182. block:
  183. template myAttr(first: string, second: int, third: float) {.pragma.}
  184. let a {.myAttr("one", 2, 3.0).} = 0
  185. let ps = a.getCustomPragmaVal(myAttr)
  186. doAssert ps.first == ps[0] and ps.first == "one"
  187. doAssert ps.second == ps[1] and ps.second == 2
  188. doAssert ps.third == ps[2] and ps.third == 3.0
  189. # pragma with implicit&explicit generic types
  190. block:
  191. template fooBar[T](x: T; c: static[int] = 42; m: char) {.pragma.}
  192. var e {.fooBar("foo", 123, 'u').}: int
  193. doAssert(hasCustomPragma(e, fooBar))
  194. doAssert(getCustomPragmaVal(e, fooBar).c == 123)
  195. block:
  196. macro expectedAst(expectedRepr: static[string], input: untyped): untyped =
  197. assert input.treeRepr & "\n" == expectedRepr
  198. return input
  199. const procTypeAst = """
  200. ProcTy
  201. FormalParams
  202. Empty
  203. IdentDefs
  204. Ident "x"
  205. Ident "int"
  206. Empty
  207. Pragma
  208. Ident "async"
  209. """
  210. type
  211. Foo = proc (x: int) {.expectedAst(procTypeAst), async.}
  212. static: assert Foo is proc(x: int): Future[void]
  213. const asyncProcTypeAst = """
  214. ProcTy
  215. FormalParams
  216. BracketExpr
  217. Ident "Future"
  218. Ident "void"
  219. IdentDefs
  220. Ident "s"
  221. Ident "string"
  222. Empty
  223. Pragma
  224. """
  225. type
  226. Bar = proc (s: string) {.async, expectedAst(asyncProcTypeAst).}
  227. static: assert Bar is proc(x: string): Future[void]
  228. const typeAst = """
  229. TypeDef
  230. PragmaExpr
  231. Ident "Baz"
  232. Pragma
  233. Empty
  234. ObjectTy
  235. Empty
  236. Empty
  237. RecList
  238. IdentDefs
  239. Ident "x"
  240. Ident "string"
  241. Empty
  242. """
  243. type
  244. Baz {.expectedAst(typeAst).} = object
  245. x: string
  246. static: assert Baz.x is string
  247. const procAst = """
  248. ProcDef
  249. Ident "bar"
  250. Empty
  251. Empty
  252. FormalParams
  253. Ident "string"
  254. IdentDefs
  255. Ident "s"
  256. Ident "string"
  257. Empty
  258. Empty
  259. Empty
  260. StmtList
  261. ReturnStmt
  262. Ident "s"
  263. """
  264. proc bar(s: string): string {.expectedAst(procAst).} =
  265. return s
  266. static: assert bar("x") == "x"
  267. #------------------------------------------------------
  268. # issue #13909
  269. template dependency*(id: string, weight = 0.0) {.pragma.}
  270. type
  271. MyObject* = object
  272. provider*: proc(obj: string): pointer {.dependency("Data/" & obj, 16.1), noSideEffect.}
  273. proc myproc(obj: string): string {.dependency("Data/" & obj, 16.1).} =
  274. result = obj