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

Reply via email to