Ok, so I've been trying to get all procs defined in a given module.
Let's say in myModule.nim we have proc proc1 and proc proc2.
How can I do something like this (at compile-time):
const myProcs = getProcsIn("myModule")
and myProcs containing [proc1, proc2]?
I think it should be doable using macros, but I have no idea how...
Unfortunately no, that's not doable. At least not with existing modules.
The macros module contains a proc getImpl which you could potentially use on a module name. I say could, because actually using it on a module returns a nil node.
The closest I was able to get to this was to create a macro with a typed body and use it with an include:
# procs.nim
proc proc1(x: int): int = x * 2
proc example(a, b: int): int = a * b
# collectprocs.nim
import std/macros
macro collectProcsAux(module: typed): untyped =
# typed parameters are sem-checked before being passed to macros – this
# includes resolving imports and includes, so we'll exploit that
var procSyms: seq[NimNode]
# to get the procedures, we simply iterate over the included module:
for stmt in module[1]:
# and check whether the statement we got is a proc definition:
if stmt.kind == nnkProcDef:
procSyms.add(stmt[0])
# the problem is that you can't really do much with your procs
# outside of the macro. creating a const consisting of all those procs is
# impossible because every one of them has a different type. you'd have to
# work with the procs inside of this macro
# you can also create a helper template for nicer syntax, like so:
template includeAndCollectProcs(moduleName: untyped): untyped =
collectProcsAux:
include moduleName
includeAndCollectProcs procs
But the side effect of includeing the module is that you're effectively compiling it twice, which can result in duplicate definition errors.
In cligen.macUt, I have the caller pass a symbol to any proc in the module to a macro docFromModuleOf*(sym: typed{nkSym}). Then that can use lineInfo to get a pathname and then staticRead can slurp the whole file into a string.
I only do this to get a default for the overall module doc comment (example call), but I suspect you could re-parse the string into an AST with macros.parseStmt. Then you could iterate over said AST looking for proc definitions. This is sort of like implementing your own include, but one where you pass any symbol from the file and then get to intervene at the AST level.
I have used this code very little besides the example test case. So, there could be issues, but the approach might get you started and that test has never failed on me since June 2019. So, it seemed an approach worth mentioning.
This keeps getting asked, and is a very useful feature on which I rely in my own nim fork.
I wrote a PR a while back: https://github.com/nim-lang/Nim/pull/9560 but it was closed without much of a debate.
Maybe there is hope this PR can be re-opened so I can address whatever needs to be addressed to get it in; according to @araq in https://forum.nim-lang.org/t/1817#37522