I'm trying to learn macros and am playing with fusion/matching too.
Here, I've attempted to basically create a macro that stupidly inserts an exising pragma:
import macros, options, strformat
import fusion/matching
macro exportc_pragma(prefix: string, val: untyped): untyped =
echo prefix
if val.matches(
ProcDef[@name, Empty(), @generic, [@returnType, all @arguments], @pragmas, _, @body]
):
# let export_name = fmt"\"{prefix}\""
let export_name = "\"oops\""
let export_pragma = newColonExpr(ident"exportc", ident(export_name))
var new_pragma = newTree(nnkPragma, export_pragma)
val.addPragma(new_pragma)
echo val.repr
return val
proc f(x: int){.exportc_pragma: "my_export_name".} =
echo "hello"
as you can see I've commented out the used of the defined prefix as this gave: cannot create null element for: tyProxy
without that line I just put in "oops"
the last echo shows the result is as I expect:
proc f(x: int) {.exportc: "oops".} =
echo "hello"
but the error is invalid pragma: {.exportc: "oops".} and identifier expected, but found ' {.exportc: "oops".}'
of course no problem with it copy and pasted
proc f(x: int) {.exportc: "oops".} =
echo "hello"
would someone try explaining this to me?
Thanks a lot
If you do echo val.treeRepr instead of repr, you get the output
ProcDef
Ident "f"
Empty
Empty
FormalParams
Empty
IdentDefs
Ident "x"
Ident "int"
Empty
Pragma
Pragma
ExprColonExpr
Ident "exportc"
Ident "\"oops\""
Empty
StmtList
Command
Ident "echo"
StrLit "hello"
Notice how there is a double Pragma. By calling addPragma, you are adding a node of kind Pragma to the pragmas.
Also, you are creating an identifier node for the value of exportc. You should be creating a string literal, with newLit.
Fixing these, you get:
import macros, options, strformat
macro exportc_pragma(prefix: string, val: untyped): untyped =
let export_name = "oops"
let export_pragma = newColonExpr(ident"exportc", newLit(export_name))
val.addPragma(export_pragma)
echo val.repr
return val
proc f(x: int){.exportc_pragma: "my_export_name".} =
echo "hello"