I made a following macro for which when a proc is called inside "classProc"
block, insert a self argument and access these member variable by self.x. Now,
I want to make the macro to be
1. member variables(such as self.x) are changeable i.e. I want to insert
"self: var S" instead of "self:S"
2. accessible by only x instead of by self.x. (I believe this is possible by
inserting "template x():auto = self.x" to proc body automatically. But I must
get names of member variable compile time. It seems that "fields" function do
such things. But I couldn't use it in macro statement. )
Are there any way? Thanks!
{.experimental.}
import macros
proc convertToMemberProc( procDefNode:NimNode, className:string ) =
var formalParamsNode = procDefNode[3]
formalParamsNode.expectKind( nnkFormalParams )
var selfIdentNode = newIdentDefs( ident("self"), ident(className))
formalParamsNode.insert( 1, selfIdentNode )
type TraverseOp = enum Continue, Break, SkipChild, SkipSibling, Finished
proc traverse(n: NimNode; action:proc(n:NimNode;parents:ref
seq[NimNode]):TraverseOp; parents:ref seq[NimNode] = nil ):TraverseOp
{.discardable.} =
var parents = parents
if parents == nil:
parents.new
parents.newseq( 0 )
parents.add( n )
for it in n.children:
case action( it, parents )
of Continue: discard
of Break: return Break
of SkipSibling: return SkipSibling
of SkipChild: continue
else: assert false
case traverse( it, action, parents )
of Break: return Break
else: discard
return Finished
macro classproc(className:untyped,stmtList:untyped):untyped=
var classNameStr = `$`(className)
stmtList.traverse do (n:NimNode;parents:ref seq[NimNode]) -> TraverseOp:
case n.kind
of nnkProcDef, nnkMethodDef, nnkIteratorDef:
n.convertToMemberProc( classNameStr )
else: discard
result = stmtList
type S = object
x:int
classProc(S):
proc f() =
echo self.x
var s = S(x:2021)
s.f()
Run