Following the IRC discussion, I had the hope that using a second macro may help. But while "genVar("X")" does indeed work, all tries to get it working with t("X") fails...
import macros
macro genVar(c: string): typed =
result = newNimNode(nnkStmtList)
var
#section = newNimNode(nnkConstSection)
section = newNimNode(nnkVarSection)
constDef = newNimNode(nnkIdentDefs)
constDef.add(newIdentNode("myvar"))
constDef.add(newEmptyNode())
constDef.add(newIdentNode("C" & $c))
section.add(constDef)
result.add(section)
const CX = 7
macro t(s: string): typed =
var hhh = "X"
#genVar("X")
genVar($s)
echo myVar + 1
t("X")
As far as I know you can't call a macro inside another macro. It doen't make sense anyway.
Use a compiletime proc.
import macros
proc genVar(c: string): NimNode {.compiletime.} =
# {.compiletime.} pragma is automatically inferred if one of its argument is of type NimNode.
result = newNimNode(nnkStmtList)
var
#section = newNimNode(nnkConstSection)
section = newNimNode(nnkVarSection)
constDef = newNimNode(nnkIdentDefs)
constDef.add(newIdentNode("myvar"))
constDef.add(newEmptyNode())
constDef.add(newIdentNode("C" & $c))
section.add(constDef)
result.add(section)
const CX = 7
macro t(s: string): typed =
var hhh = "X"
#genVar("X")
genVar($s) # this return a NimNode
# echo myVar + 1 # this makes no sense inside a macro
# NimNode are not variable in the traditional sense.
t("X")
echo myVar + 1 # this works
Thanks.
I was not aware that macros can not call each other. And I was not aware that code generally used inside macros like newIdentNode() can be used also in procs. I tried to use static and compileTime pragma myself, but I applied compileTime pragma to macro. Which does not work -- of course macro is compileTime already.
One problem may be still, that I have to access the const, which name we construct from a string, already inside the macro t. Indeed what I really need is a string constant which name I construct from strings and I have to process that string constant inside macro t. Will try that. (As I wrote yesterday in IRC, using a table in combination with static keyword works also for my purpose.)
The purpose of all that is to handle connecting to callbacks from GTK.
What currently works is
let b = newButton()
b.connect("clicked", callback, optArg)
That is used in the gintro tutorial.
But for a few signal names things are more complicated. For example using the "draw" signal user wants to type
b.connect("draw", drawcallback, optArg)
For this signal name, callback proc has an additional parameter, which I have to handle in the connect macro. I can do that because my gtk.nim module contains constants like
const SCI_draw_Widget* = "1|(cr: ptr cairo.Context00): gboolean|(cast[cairo.Context00](cr.impl))|"
Parsing that const gives me the information which I need in the macro. "draw" in not unique, I have to access the type of the first parameter of the connect call also, which may be button, which i a subtype of widget.
We may have about 30 of such advanced callbacks, I still hope that I have not to write all 30 macro variants manually.
No, can not access the const with constructed name inside the macro :-(
import macros
const CX = 7
proc genVar(c: static[string]): NimNode {.compiletime.} =
result = newNimNode(nnkStmtList)
var
section = newNimNode(nnkVarSection)
constDef = newNimNode(nnkIdentDefs)
constDef.add(newIdentNode("myvar"))
constDef.add(newEmptyNode())
constDef.add(newIdentNode("C" & $c))
section.add(constDef)
result.add(section)
macro t(s: static[string]): typed =
genVar($s)
if myVar == 7:
echo "GREAT"
t("X")
And splitting the macro does not help:
import macros
const CX = 7
proc genVar(c: string): NimNode {.compiletime.} =
result = newNimNode(nnkStmtList)
var
section = newNimNode(nnkVarSection)
constDef = newNimNode(nnkIdentDefs)
constDef.add(newIdentNode("myvar"))
constDef.add(newEmptyNode())
constDef.add(newIdentNode("C" & $c))
section.add(constDef)
result.add(section)
macro prep(s: string): typed =
echo "prep"
genVar($s)
macro t(otherArgs): typed =
echo "t"
if myVar == 7:
echo "GREAT"
template t(s: static[string]): typed =
prep(s)
t("ignoreForNow")
t("X")
[EDIT]
Problem seems to be really hard.
I think I will generate in module gtk.nim (and in a few other like gdk) an array of strings, then my macro can do a linear search in that array to find the needed information.
you might also try something like this
import macros
#const CX = "8"
const CX = "7"
macro process_const_str(s: static[string]): typed =
result = newNimNode(nnkStmtList)
if s[0] == '7':
for i in 0..<3:
result.add newCall("echo", newLit"is 7")
else:
for i in 0..<2:
result.add newCall("echo", newLit"not 7")
macro prep(s: static[string]): typed =
result = newNimNode(nnkStmtList)
# this generate the string constant symbol from `s`
# and call a secondary level macro that parse the const string to generate
# some code.
result.add newCall("process_const_str", newIdentNode("C" & $s))
prep("X")