Go语言 如何在全局遍历中从子节点中检索父节点?

ct3nt3jp  于 2022-12-20  发布在  Go
关注(0)|答案(2)|浏览(203)

这是测试文件

func demo()  {
    name:=xxx()
    fmt.Println(name)
}

我最后的穿越代码

ast.Inspect(f, func(node ast.Node) bool {
    assign, ok := node.(*ast.AssignStmt) // find -> name:=xxx()
    if !ok {
        return true
    }
    if assign == nil {
        return true
    }
    var expr = assign.Lhs[0]
    fmt.Println(expr) // find -> name
    fmt.Println(nodeString(assign,pass.Fset))
    return true
})

我发现我必须像这样从上到下快速旅行。找到AssignStmt,然后得到AssignStmt-〉Lhs
但我需要先找到ast.Ident(name),然后在某些情况下再查找其父项是否为AssignStmt。
我不确定我是否有可能从下往上走。

u91tlkcl

u91tlkcl1#

管理调用检查器时的祖先节点堆栈:

var stack []ast.Node
ast.Inspect(f, func(n ast.Node) bool {

    // Look for the identifier.

    if n, ok := n.(*ast.Ident); ok {
        if n.Name == "name" {

            // Parent is stack[len(stack)-1]

            fmt.Println("found name")
            for _, n := range stack {
                fmt.Printf("%T\n", n)
            }
        }
    }

    // Manage the stack. Inspect calls a function like this:
    //   f(node)
    //   for each child {
    //      f(child) // and recursively for child's children
    //   }
    //   f(nil)
    if n == nil {
        // Done with node's children. Pop.
        stack = stack[:len(stack)-1]
    } else {
        // Push the current node for children.
        stack = append(stack, n)
    }

    return true
})

Run it on the playground.

tzdcorbm

tzdcorbm2#

我遇到了类似的问题,我需要找到它的兄弟姐妹之间的孩子的索引以及它的父节点。我找不到更接近的问题,所以我张贴在这里。
我将Cerise答案中的逻辑分离到一个函数中,并将答案的特定部分移到函数之外,这样更多的人可以利用这种通用形式,保存时间。
查找索引的逻辑类似于查找父节点,另一个数组用来跟踪索引序列到达当前节点就足够了,在每次调用时,n是nil,我们从序列中删除最后一项,并增加新的最后一项。

func FindParentNodeAndChildIndex(root ast.Node, child ast.Node) (parent ast.Node, childIndex int) {
    var (
        parentTrace     []ast.Node
        childIndexTrace []int
        found           = false
    )
    var (
        updateParentTrace = func(n ast.Node) {
            if n != nil {
                parentTrace = append(parentTrace, n)
            } else {
                parentTrace = parentTrace[:len(parentTrace)-1]
            }
        }
        updateChildIndexTrace = func(n ast.Node) {
            if n != nil {
                childIndexTrace = append(childIndexTrace, 0)
            } else {
                l := len(childIndexTrace)
                childIndexTrace = childIndexTrace[:l-1]
                childIndexTrace[l-2]++
            }
        }
    )
    ast.Inspect(root, func(n ast.Node) bool {
        if !found {
            updateParentTrace(n)
            updateChildIndexTrace(n)
        }
        if n != nil && n == child {
            found = true
        }
        return !found
    })
    if found {
        return parentTrace[len(parentTrace)-2], childIndexTrace[len(childIndexTrace)-2]
    }
    return nil, -1
}

看起来有更多的替代方法来寻找父母比日期问题的答案。一个是astutil.Apply()另一个是inspector.WithStack()
astutil.Apply()与两个回调一起使用,一个在访问每个节点的子节点之前激发,另一个在访问每个节点的子节点之后激发;并接受Cursor示例,该示例保存关于被访问节点的索引和父节点的详细信息。
对于WithStack,存在一个detailed example

相关问题