{.experimental: "notnil".}
import macros, asyncmacro, asyncfutures
block:
template myAttr() {.pragma.}
proc myProc():int {.myAttr.} = 2
const hasMyAttr = myProc.hasCustomPragma(myAttr)
static:
doAssert(hasMyAttr)
block:
template myAttr(a: string) {.pragma.}
type
MyObj = object
myField1, myField2 {.myAttr: "hi".}: int
var o: MyObj
static:
doAssert o.myField2.hasCustomPragma(myAttr)
doAssert(not o.myField1.hasCustomPragma(myAttr))
import custom_pragma
block: # A bit more advanced case
type
Subfield {.defaultValue: "catman".} = object
`c`* {.serializationKey: "cc".}: float
MySerializable = object
a {.serializationKey"asdf", defaultValue: 5.} : int
b {.custom_pragma.defaultValue"hello".} : int
field: Subfield
d {.alternativeKey("df", 5).}: float
e {.alternativeKey(V = 5).}: seq[bool]
proc myproc(x: int, s: string) {.alternativeKey(V = 5), serializationKey"myprocSS".} =
echo x, s
var s: MySerializable
const aDefVal = s.a.getCustomPragmaVal(defaultValue)
static: doAssert(aDefVal == 5)
const aSerKey = s.a.getCustomPragmaVal(serializationKey)
static: doAssert(aSerKey == "asdf")
const cSerKey = getCustomPragmaVal(s.field.c, serializationKey)
static: doAssert(cSerKey == "cc")
const procSerKey = getCustomPragmaVal(myproc, serializationKey)
static: doAssert(procSerKey == "myprocSS")
static: doAssert(hasCustomPragma(myproc, alternativeKey))
const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue)
static: doAssert(hasFieldCustomPragma == false)
# pragma on an object
static:
doAssert Subfield.hasCustomPragma(defaultValue)
doAssert(Subfield.getCustomPragmaVal(defaultValue) == "catman")
doAssert hasCustomPragma(type(s.field), defaultValue)
proc foo(s: var MySerializable) =
static: doAssert(s.a.getCustomPragmaVal(defaultValue) == 5)
foo(s)
block: # ref types
type
Node = object of RootObj
left {.serializationKey:"l".}, right {.serializationKey:"r".}: NodeRef
NodeRef = ref Node
NodePtr = ptr Node
SpecialNodeRef = ref object of NodeRef
data {.defaultValue"none".}: string
MyFile {.defaultValue: "closed".} = ref object
path {.defaultValue: "invalid".}: string
TypeWithoutPragma = object
var s = NodeRef()
const
leftSerKey = getCustomPragmaVal(s.left, serializationKey)
rightSerKey = getCustomPragmaVal(s.right, serializationKey)
static:
doAssert leftSerKey == "l"
doAssert rightSerKey == "r"
var specS = SpecialNodeRef()
const
dataDefVal = hasCustomPragma(specS.data, defaultValue)
specLeftSerKey = hasCustomPragma(specS.left, serializationKey)
static:
doAssert dataDefVal == true
doAssert specLeftSerKey == true
var ptrS = NodePtr(nil)
const
ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey)
static:
doAssert ptrRightSerKey == "r"
var f = MyFile()
const
fileDefVal = f.getCustomPragmaVal(defaultValue)
filePathDefVal = f.path.getCustomPragmaVal(defaultValue)
static:
doAssert fileDefVal == "closed"
doAssert filePathDefVal == "invalid"
static:
doAssert TypeWithoutPragma.hasCustomPragma(defaultValue) == false
block:
type
VariantKind = enum
variInt,
variFloat
variString
variNestedCase
Variant = object
case kind: VariantKind
of variInt: integer {.serializationKey: "int".}: BiggestInt
of variFloat: floatp: BiggestFloat
of variString: str {.serializationKey: "string".}: string
of variNestedCase:
case nestedKind: VariantKind
of variInt..variNestedCase: nestedItem {.defaultValue: "Nimmers of the world, unite!".}: int
let vari = Variant(kind: variInt)
const
hasIntSerKey = vari.integer.hasCustomPragma(serializationKey)
strSerKey = vari.str.getCustomPragmaVal(serializationKey)
nestedItemDefVal = vari.nestedItem.getCustomPragmaVal(defaultValue)
static:
doAssert hasIntSerKey
doAssert strSerKey == "string"
doAssert nestedItemDefVal == "Nimmers of the world, unite!"
block:
template simpleAttr {.pragma.}
type Annotated {.simpleAttr.} = object
proc generic_proc[T]() =
doAssert Annotated.hasCustomPragma(simpleAttr)
#--------------------------------------------------------------------------
# Pragma on proc type
let a: proc(x: int) {.defaultValue(5).} = nil
static:
doAssert hasCustomPragma(a.type, defaultValue)
# bug #8371
template thingy {.pragma.}
type
Cardinal = enum
north, east, south, west
Something = object
a: float32
case cardinal: Cardinal
of north:
b {.thingy.}: int
of east:
c: int
of south: discard
else: discard
var foo: Something
foo.cardinal = north
doAssert foo.b.hasCustomPragma(thingy) == true
proc myproc(s: string): int =
{.thingy.}:
s.len
doAssert myproc("123") == 3
let xx = compiles:
proc myproc_bad(s: string): int =
{.not_exist.}:
s.len
doAssert: xx == false
macro checkSym(s: typed{nkSym}): untyped =
let body = s.getImpl.body
doAssert body[1].kind == nnkPragmaBlock
doAssert body[1][0].kind == nnkPragma
doAssert body[1][0][0] == bindSym"thingy"
checkSym(myproc)
# var and let pragmas
block:
template myAttr() {.pragma.}
template myAttr2(x: int) {.pragma.}
template myAttr3(x: string) {.pragma.}
type
MyObj2 = ref object
MyObjNotNil = MyObj2 not nil
let a {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0
let b {.myAttr,myAttr2(2),myAttr3:"test".} = 0
var x {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0
var y {.myAttr,myAttr2(2),myAttr3:"test".}: int
var z {.myAttr,myAttr2(2),myAttr3:"test".} = 0
var z2 {.myAttr.}: MyObjNotNil
template check(s: untyped) =
doAssert s.hasCustomPragma(myAttr)
doAssert s.hasCustomPragma(myAttr2)
doAssert s.getCustomPragmaVal(myAttr2) == 2
doAssert s.hasCustomPragma(myAttr3)
doAssert s.getCustomPragmaVal(myAttr3) == "test"
check(a)
check(b)
check(x)
check(y)
check(z)
# pragma with multiple fields
block:
template myAttr(first: string, second: int, third: float) {.pragma.}
let a {.myAttr("one", 2, 3.0).} = 0
let ps = a.getCustomPragmaVal(myAttr)
doAssert ps.first == ps[0] and ps.first == "one"
doAssert ps.second == ps[1] and ps.second == 2
doAssert ps.third == ps[2] and ps.third == 3.0
# pragma with implicit&explicit generic types
block:
template fooBar[T](x: T; c: static[int] = 42; m: char) {.pragma.}
var e {.fooBar("foo", 123, 'u').}: int
doAssert(hasCustomPragma(e, fooBar))
doAssert(getCustomPragmaVal(e, fooBar).c == 123)
block:
macro expectedAst(expectedRepr: static[string], input: untyped): untyped =
doAssert input.treeRepr & "\n" == expectedRepr
return input
const procTypeAst = """
ProcTy
FormalParams
Empty
IdentDefs
Ident "x"
Ident "int"
Empty
Pragma
Ident "async"
"""
type
Foo = proc (x: int) {.expectedAst(procTypeAst), async.}
static: doAssert Foo is proc(x: int): Future[void]
const asyncProcTypeAst = """
ProcTy
FormalParams
BracketExpr
Ident "Future"
Ident "void"
IdentDefs
Ident "s"
Ident "string"
Empty
Pragma
"""
type
Bar = proc (s: string) {.async, expectedAst(asyncProcTypeAst).}
static: doAssert Bar is proc(x: string): Future[void]
const typeAst = """
TypeDef
PragmaExpr
Ident "Baz"
Pragma
Empty
ObjectTy
Empty
Empty
RecList
IdentDefs
Ident "x"
Ident "string"
Empty
"""
type
Baz {.expectedAst(typeAst).} = object
x: string
static: doAssert Baz.x is string
const procAst = """
ProcDef
Ident "bar"
Empty
Empty
FormalParams
Ident "string"
IdentDefs
Ident "s"
Ident "string"
Empty
Empty
Empty
StmtList
ReturnStmt
Ident "s"
"""
proc bar(s: string): string {.expectedAst(procAst).} =
return s
static: doAssert bar("x") == "x"
#------------------------------------------------------
# bug #13909
template dependency*(id: string, weight = 0.0) {.pragma.}
type
MyObject* = object
provider*: proc(obj: string): pointer {.dependency("Data/" & obj, 16.1), noSideEffect.}
proc myproc(obj: string): string {.dependency("Data/" & obj, 16.1).} =
result = obj
# bug 12523
template myCustomPragma {.pragma.}
type
RefType = ref object
field {.myCustomPragma.}: int
ObjType = object
field {.myCustomPragma.}: int
RefType2 = ref ObjType
block:
let x = RefType()
for fieldName, fieldSym in fieldPairs(x[]):
doAssert hasCustomPragma(fieldSym, myCustomPragma)
block:
let x = RefType2()
for fieldName, fieldSym in fieldPairs(x[]):
doAssert hasCustomPragma(fieldSym, myCustomPragma)
# bug 8457
block:
template world {.pragma.}
type
Hello = ref object
a: float32
b {.world.}: int
discard Hello(a: 1.0, b: 12)