I'm getting the following error for the code below `(172, 9) Error: cannot
prove that it's safe to initialize 'child' with the runtime value for the
discriminator 'kind'`
I sort of understand the general idea, since the child of the NtmlElement is
conditional, and since I am creating NtmlElement at compile time, the compiler
must be able to determine before runtime whether the child will be of kind
elementNode or textNode. What I don't understand is how to eliminate the
uncertainty.
import
macros
type
NtmlNodeType = enum
fragmentNode,
h1Node,
pNode,
divNode
NtmlElementType = enum
elementNode,
textNode
NtmlProp = object of RootObj
key: string
value: string
NtmlElement = object of RootObj
nodeType: NtmlNodeType
props: seq[NtmlProp]
case kind: NtmlElementType
of elementNode:
children: seq[NtmlElement]
of textNode:
child: string
macro generateNtml(tree: untyped): untyped =
proc processNtml(tree: NimNode): NimNode =
case tree.kind:
of nnkStmtList:
var fragmentChildren = newSeq[NimNode]()
for branch in tree:
fragmentChildren.add(processNtml(branch))
result = nnkObjConstr.newTree(
newIdentNode("NtmlElement"),
nnkExprColonExpr.newTree(
newIdentNode("nodeType"),
newIdentNode("fragmentNode")
),
nnkExprColonExpr.newTree(
newIdentNode("props"),
nnkPrefix.newTree(
newIdentNode("@"),
nnkBracket.newTree()
)
),
nnkExprColonExpr.newTree(
newIdentNode("kind"),
newIdentNode("elementNode")
),
nnkExprColonExpr.newTree(
newIdentNode("children"),
nnkPrefix.newTree(
newIdentNode("@"),
nnkBracket.newTree(fragmentChildren)
)
)
)
of nnkCall:
var ntmlElement: NimNode
var props = newSeq[NimNode]()
var children = newSeq[NimNode]()
var child = ""
var nodeType: NtmlNodeType
var elementType: NtmlElementType
for branch in tree:
if branch.kind == nnkIdent:
case $branch
of "dv":
nodeType = divNode
elementType = elementNode
of "h1":
nodeType = h1Node
elementType = textNode
of "p":
nodeType = pNode
elementType = textNode
elif branch.kind == nnkExprEqExpr:
props.add(
nnkObjConstr.newTree(
newIdentNode("NtmlProp"),
nnkExprColonExpr.newTree(
newIdentNode("key"),
newLit($branch[0])
),
nnkExprColonExpr.newTree(
newIdentNode("value"),
newLit($branch[1])
)
)
)
elif branch.kind == nnkStmtList and elementType == elementNode:
children.add(processNtml(branch))
elif branch.kind == nnkStmtList and elementType == textNode:
for leaf in branch:
child.add($leaf)
return nnkObjConstr.newTree(
newIdentNode("NtmlElement"),
nnkExprColonExpr.newTree(
newIdentNode("nodeType"),
newIdentNode($nodeType)
),
nnkExprColonExpr.newTree(
newIdentNode("props"),
nnkPrefix.newTree(
newIdentNode("@"),
nnkBracket.newTree(props)
)
),
nnkExprColonExpr.newTree(
newIdentNode("elementType"),
newIdentNode($elementType)
),
case elementType
of elementNode:
nnkExprColonExpr.newTree(
newIdentNode("children"),
nnkPrefix.newTree(
newIdentNode("@"),
nnkBracket.newTree(children)
)
)
of textNode:
nnkExprColonExpr.newTree(
newIdentNode("child"),
newLit(child)
)
)
else:
# add empty fragment here, code removed for brevity
return processNtml(tree)
let generatedNtml = generateNtml:
dv:
h1: "hello"
p: "world"
Run