That's what I'm presently doing. I'm using the following pattern (presented
top-down for easier reading):
template dsl*(bodyDsl: untyped) =
# Structure of the DSL
block:
# Inject context variables and do init...
template action(bodyAction: untyped) =
# Here in action context.
actionImpl(bodyAction)
...
macro actionImpl(body: untyped): untyped =
# Delegate syntax processing to procs
... extract pieces of syntax
proc1(var1, code1)
proc2(var2, code2)
...
proc proc1(var1: int; body: NimNode) =
# Procs can mix different type of arguments and
# easier to use in proc body.
...
v = op(v1, v2)
template op(v1: Type1; v2: Type2) =
# Optimize operators at the lowest level
Run
Using procs below the macro level means that I don't have to take care of
`typed/untyped` arguments and automatic macro `untyped` conversions. And I use
again templates at the lowest level, for small operations or optimizations. I
hope this pattern will make sense and that the code will be easy to
understand...