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...