This works just fine:
    
    
    import macros
    
    type
       Edge = object
          neighbor {.cursor.}: Node
       
       Node = ref NodeObj
       NodeObj = object
          neighbors: seq[Edge]
          label: string
          visited: bool
       
       Graph = object
          nodes: seq[Node]
    
    # without lent it creates a colonTmp, sinks it to the cursor var, and then 
destroys it.
    proc addNode(self: var Graph; label: string): lent Node =
      let node = Node(label: label)
      self.nodes.add(node)
      result = self.nodes[^1]
    
    proc addEdge(self: Graph; source, neighbor: Node) =
      let edge = Edge(neighbor: neighbor)
      source.neighbors.add(edge)
    
    macro operateOn*(x: typed; calls: untyped) =
       result = copyNimNode(calls)
       expectKind calls, {nnkStmtList, nnkStmtListExpr}
       # non-recursive processing because that's exactly what we need here:
       for y in calls:
          expectKind y, nnkCallKinds
          var call = newTree(y.kind)
          call.add y[0]
          call.add x
          for j in 1 ..< y.len: call.add y[j]
          result.add call
    
    proc main =
       var graph: Graph
       
       let nodeA = graph.addNode("a")
       let nodeB = graph.addNode("b")
       let nodeC = graph.addNode("c")
       let nodeD = graph.addNode("d")
       let nodeE = graph.addNode("e")
       let nodeF = graph.addNode("f")
       let nodeG = graph.addNode("g")
       let nodeH = graph.addNode("h")
       
       echo "before addEdge"
       operateOn(graph):
          addEdge(nodeA, neighbor = nodeB)
          addEdge(nodeA, neighbor = nodeC)
          addEdge(nodeB, neighbor = nodeD)
          addEdge(nodeB, neighbor = nodeE)
          addEdge(nodeC, neighbor = nodeF)
          addEdge(nodeC, neighbor = nodeG)
          addEdge(nodeE, neighbor = nodeH)
          addEdge(nodeE, neighbor = nodeF)
          addEdge(nodeF, neighbor = nodeG)
    #       addEdge(nodeF, neighbor = nodeF) # cycle
    #       addEdge(nodeG, neighbor = nodeF) # more cycles
       echo "after addEdge"
    
    main()
    echo getOccupiedMem()
    
    
    Run

Reply via email to