I solved this problem with a two layer macro. The outer macro had an untyped
argument and an inner macro with a typed argument. The outer macro was the
macro that the user of the dsl would call and it has the nice syntax to call
it. The outer macro transforms the untyped ast in an ast that then can be type
checked. I did this by adding some function calls that didn't do anything, they
were just there, so that the type checker could do it's job. The now
typecheckable ast is then passed to the inner macro that has a typed argument.
Now you can do whatever you want from here on. In your case the outer macro
would generate the let expression you talked about.
over simplifiled example:
proc decoration[T](arg: T): int = 1
macro inner(arg: typed): untyped = [...]
macro outer*(arg: untyped) =
result = quote do:
inner:
decoration(`arg`)