Misc macro things (#10612)

* Misc cleanup in macro code

Generate error messages using `error` instead of `assert`.

Fixes #10574

* Fix crash with hasCustomPragma on quoted fields

Use the `$` operator instead of reaching for the `strVal` field directly
This commit is contained in:
LemonBoy 2019-02-09 18:22:07 +01:00 • committed by Andreas Rumpf
commit 1e88bf1def
2 changed files with 19 additions and 14 deletions

View file

@ -1027,7 +1027,10 @@ const
nnkCallStrLit, nnkHiddenCallConv} nnkCallStrLit, nnkHiddenCallConv}
proc expectKind*(n: NimNode; k: set[NimNodeKind]) {.compileTime.} = proc expectKind*(n: NimNode; k: set[NimNodeKind]) {.compileTime.} =
assert n.kind in k, "Expected one of " & $k & ", got " & $n.kind ## checks that `n` is of kind `k`. If this is not the case,
## compilation aborts with an error message. This is useful for writing
## macros that check the AST that is passed to them.
if n.kind notin k: error("Expected one of " & $k & ", got " & $n.kind, n)
proc newProc*(name = newEmptyNode(); params: openArray[NimNode] = [newEmptyNode()]; proc newProc*(name = newEmptyNode(); params: openArray[NimNode] = [newEmptyNode()];
body: NimNode = newStmtList(), procType = nnkProcDef): NimNode {.compileTime.} = body: NimNode = newStmtList(), procType = nnkProcDef): NimNode {.compileTime.} =
@ -1035,7 +1038,8 @@ proc newProc*(name = newEmptyNode(); params: openArray[NimNode] = [newEmptyNode(
## ##
## The ``params`` array must start with the return type of the proc, ## The ``params`` array must start with the return type of the proc,
## followed by a list of IdentDefs which specify the params. ## followed by a list of IdentDefs which specify the params.
assert procType in RoutineNodes if procType notin RoutineNodes:
error("Expected one of " & $RoutineNodes & ", got " & $procType)
result = newNimNode(procType).add( result = newNimNode(procType).add(
name, name,
newEmptyNode(), newEmptyNode(),
@ -1077,7 +1081,8 @@ proc newEnum*(name: NimNode, fields: openArray[NimNode],
## ##
expectKind name, nnkIdent expectKind name, nnkIdent
doAssert len(fields) > 0, "Enum must contain at least one field" if len(fields) < 1:
error("Enum must contain at least one field")
for field in fields: for field in fields:
expectKind field, {nnkIdent, nnkEnumFieldDef} expectKind field, {nnkIdent, nnkEnumFieldDef}
@ -1133,7 +1138,7 @@ proc params*(someProc: NimNode): NimNode {.compileTime.} =
result = someProc[3] result = someProc[3]
proc `params=`* (someProc: NimNode; params: NimNode) {.compileTime.}= proc `params=`* (someProc: NimNode; params: NimNode) {.compileTime.}=
someProc.expectRoutine someProc.expectRoutine
assert params.kind == nnkFormalParams expectKind(params, nnkFormalParams)
someProc[3] = params someProc[3] = params
proc pragma*(someProc: NimNode): NimNode {.compileTime.} = proc pragma*(someProc: NimNode): NimNode {.compileTime.} =
@ -1144,7 +1149,7 @@ proc pragma*(someProc: NimNode): NimNode {.compileTime.} =
proc `pragma=`*(someProc: NimNode; val: NimNode){.compileTime.}= proc `pragma=`*(someProc: NimNode; val: NimNode){.compileTime.}=
## Set the pragma of a proc type ## Set the pragma of a proc type
someProc.expectRoutine someProc.expectRoutine
assert val.kind in {nnkEmpty, nnkPragma} expectKind(val, {nnkEmpty, nnkPragma})
someProc[4] = val someProc[4] = val
proc addPragma*(someProc, pragma: NimNode) {.compileTime.} = proc addPragma*(someProc, pragma: NimNode) {.compileTime.} =
@ -1156,8 +1161,8 @@ proc addPragma*(someProc, pragma: NimNode) {.compileTime.} =
someProc.pragma = pragmaNode someProc.pragma = pragmaNode
pragmaNode.add(pragma) pragmaNode.add(pragma)
template badNodeKind(k, f) = template badNodeKind(n, f) =
assert false, "Invalid node kind " & $k & " for macros.`" & $f & "`" error("Invalid node kind " & $n.kind & " for macros.`" & $f & "`", n)
proc body*(someProc: NimNode): NimNode {.compileTime.} = proc body*(someProc: NimNode): NimNode {.compileTime.} =
case someProc.kind: case someProc.kind:
@ -1168,7 +1173,7 @@ proc body*(someProc: NimNode): NimNode {.compileTime.} =
of nnkForStmt: of nnkForStmt:
return someProc.last return someProc.last
else: else:
badNodeKind someProc.kind, "body" badNodeKind someProc, "body"
proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} = proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
case someProc.kind case someProc.kind
@ -1179,7 +1184,7 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
of nnkForStmt: of nnkForStmt:
someProc[len(someProc)-1] = val someProc[len(someProc)-1] = val
else: else:
badNodeKind someProc.kind, "body=" badNodeKind someProc, "body="
proc basename*(a: NimNode): NimNode {.compiletime, benign.} proc basename*(a: NimNode): NimNode {.compiletime, benign.}
@ -1195,7 +1200,7 @@ proc `$`*(node: NimNode): string {.compileTime.} =
of nnkAccQuoted: of nnkAccQuoted:
result = $node[0] result = $node[0]
else: else:
badNodeKind node.kind, "$" badNodeKind node, "$"
proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.} proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.}
## Create a new ident node from a string ## Create a new ident node from a string
@ -1281,7 +1286,7 @@ proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {.
proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string; proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
right: NimNode] {.compileTime.} = right: NimNode] {.compileTime.} =
assert node.kind == nnkInfix expectKind(node, nnkInfix)
result = (node[1], $node[0], node[2]) result = (node[1], $node[0], node[2])
proc copy*(node: NimNode): NimNode {.compileTime.} = proc copy*(node: NimNode): NimNode {.compileTime.} =
@ -1342,7 +1347,7 @@ else:
proc hasArgOfName*(params: NimNode; name: string): bool {.compiletime.}= proc hasArgOfName*(params: NimNode; name: string): bool {.compiletime.}=
## Search nnkFormalParams for an argument. ## Search nnkFormalParams for an argument.
assert params.kind == nnkFormalParams expectKind(params, nnkFormalParams)
for i in 1 ..< params.len: for i in 1 ..< params.len:
template node: untyped = params[i] template node: untyped = params[i]
if name.eqIdent( $ node[0]): if name.eqIdent( $ node[0]):
@ -1451,7 +1456,7 @@ proc customPragmaNode(n: NimNode): NimNode =
if varName.kind == nnkPostfix: if varName.kind == nnkPostfix:
# This is a public field. We are skipping the postfix * # This is a public field. We are skipping the postfix *
varName = varName[1] varName = varName[1]
if eqIdent(varName.strVal, name): if eqIdent($varName, name):
return varNode[1] return varNode[1]
if obj[1].kind == nnkOfInherit: # explore the parent object if obj[1].kind == nnkOfInherit: # explore the parent object

View file

@ -22,7 +22,7 @@ import custom_pragma
block: # A bit more advanced case block: # A bit more advanced case
type type
Subfield {.defaultValue: "catman".} = object Subfield {.defaultValue: "catman".} = object
c* {.serializationKey: "cc".}: float `c`* {.serializationKey: "cc".}: float
MySerializable = object MySerializable = object
a {.serializationKey"asdf", defaultValue: 5.} : int a {.serializationKey"asdf", defaultValue: 5.} : int