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

Reply via email to