So far this is what I've got:
import macros, htmlgen
macro traverseTree(body: untyped): untyped =
proc processNode(node: NimNode): NimNode =
case node.kind
of nnkCall:
let callee = node[0]
var children: seq[NimNode] = @[]
for arg in node[1..^1]:
children.add(processNode(arg))
var tag = ""
case callee.repr
of "dv": tag = "div"
else: tag = callee.repr
return newCall(tag, children)
of nnkStmtList, nnkStmtListExpr:
var processedChildren = newSeq[NimNode]()
for child in node:
processedChildren.add(processNode(child))
return newNimNode(nnkStmtList).add(processedChildren)
else:
return node
let processedBody = processNode(body)
return processedBody
# Usage example
let html = traverseTree:
dv(id = "1"):
h1(style = "value"):
"hello world"
echo html
Run
Output:
<div id="1"><h1 style="value">hello world</h1></div>
Run
So far so good! But when I attempt to add a sibling to h1:
let html = traverseTree:
dv(id = "1"):
h1(style = "value"):
"hello world"
p: "this is a paragraph"
Run
The following error occurs:
(35, 12) template/generic instantiation of `traverseTree` from here
(39, 8) template/generic instantiation of `div` from here
(38, 7) Error: expression '"<h1 style=\"value\">hello world</h1>"' is of
type 'string' and has to be used (or discarded)
Run
I think the problem is here:
var children: seq[NimNode] = @[]
for arg in node[1..^1]:
children.add(processNode(arg))
Run
I think whats happening is that when it finds a child call it goes down into
that node without accounting for the greater context (such as siblings). This
is supported (I thnk) by the fact that I can get longer chains of html to be
produced so long as I keep passing nodes as children. For example:
let html = traverseTree:
dv(id = "1"):
dv:
dv:
dv:
h1(style = "value"):
"hello world"
Run
output:
<div id="1"><div><div><div><h1 style="value">hello
world</h1></div></div></div></div>
Run
I am however at a loss at how to solve this. Any help is appreciated!