tcustom_pragma.nim 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. {.experimental: "notnil".}
  2. import macros
  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)