Hi all,
Can somebody help with this scenario?
const cbassets = @["g", "e", "x"]
template mybootup*(): expr =
bootSystems()
for ipos, i in @[system_map_g, system_map_e, system_map_x]:
echo "system_map_" & cbassets[ipos] & "= ", $i
This template runs a macro named bootSystems(), which generates the "system_flats" variables, that the above code loops through.
I'd next like to call a 2nd macro, bootSystems2(), which uses the "system_flats" variables, but get an "undeclared identifier" error, since those var variables aren't available. How do I make dynamically created variables persist within the entire VM phase, just like they do for a regular program?
The bootSystems2() macro will dynamically create a few procs, but it needs access to the "system_flats" variables. I would love to keep everything within my bootSystems() macro, but that gives "Error: VM problem: too many registers required". (edit: running 0.14.3).
Thanks.
I was able to simplify the bootSystems() macro so that I could create the dynamic procs. The solution was to remove as many variables as possible, and now I don't get the too many registers required VM error.
Now I don't need a 2nd macro (bootSystem2), but I'm still curious how to make make a macro recognize variables which were created by an earlier-executed macro. I'm wondering if one solution (only solution?) is to solely generate constant variables.
Thanks.
Thank you, Araq. I generated as many sequences as possible, and what fixed the "too many registers" VM error was to eliminate some intermediary variables being used with the macro API, like these:
var
section4 = newNimNode(nnkVarSection)
call4 = newNimNode(nnkCall)
bracketExpr4 = newNimNode(nnkBracketExpr)
tupleTy4 = newNimNode(nnkTupleTy)
I am generating a lot of sequences that are used for bookkeeping of all the meta-programming, like these:
7 seq vars like: var system_map_{g,e,x,m,pos,neg,nau} = newSeq[tuple[id:int, sysID:int]]().
7 seq const vars like: const asset_map_{g,e,x,m,pos,neg,nau} = newSeq[int]().
1 seq var like: var system_def = newSeq[tuple[name:string, sysID:int, sysBody:string]]().
7 seq vars like: asset_def_{g|e|x|m|pos|neg|nau} = newSeq[(name:string, procID:int, procBody:string)].
indefinite number of asset procs {g|e|x|m|pos|neg|nau}proc(#): i.e. g1proc(), e8proc(), x4proc(), etc.
If I made everything a constant, will that mean everything is done in the VM phase and subsequent macros may reference const vars created by earlier macros? I tried accessing my const asset.. variables from a later macro and couldn't. I could probably get by with everything being a constant, except the asset.. ones. If I understand correctly, a plus of having var sequences is being able to store a lot on the heap, which I need for the asset.. sequences.
Being able to define these before my program even runs means I can declaratively build-up all the programming building blocks from config files, and my main program can programmatically mix-and-match code blocks, which is incredibly helpful meta-programming capability.
Actually, only procs and templates may see variables my macro created.
I'm wondering how to make subsequent macros see variables created within earlier macros. Within my 1st/main macro, do I need to call bindSym() or genSym()? I'm dynamically creating the names of most variables:
const cbassets = @["g", "e", "x", "m", "pos", "neg", "nau"]
...then within main macro:
... # create ldg, lde, etc sequences.
# Now loop through ldg, lde and create system_map_g, system_map_e, etc.
for ipos, i in @[ldg, lde, ldx, ldm, ldpos, ldneg, ldnau]:
when debug :
when debugv == 9: echo "walking ipos = ", ipos, " ;i = ", i.repr
for j in 0 .. i.len-1:
let call2a = newNimNode(nnkCall)
call2a.add(newDotExpr(ident("system_map_" & cbassets[ipos]), ident("add")))
call2a.add(newPar(newIntLitNode(i[j][0]), newIntLitNode(i[j][1])))
result.add(call2a)