跨包使用go/parser [英] Usage of go/parser across packages

查看:80
本文介绍了跨包使用go/parser的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用 go/parser 来解析golang文件并检查它的AST.我有一个要使用go/parser的特定问题,但遇到了障碍.

I have used go/parser to parse a golang file and examine it's AST. I have a specific problem for which I want to use go/parser but I hit a roadblock.

请考虑GOPATH/src中存在以下文件

Consider that the following files are present in GOPATH/src

$GOPATH/src/
    example.go
    example_package/
        example_package.go

以下是上面文件的内容

example.go

package main

import (
    "example_package"
)

type MyObject struct {
    base *example_package.BaseObject
}

func DoMyThing(arg *example_package.FirstArg) {
    arg.Write(10)
}

func DoMyAnotherThing() {
}

func main() {
    example_package.GetItStarted(&MyObject{})
}

example_package.go

package example_package

func GetItStarted(obj interface{}) {
}

type FirstArg interface {
    Read() int
    Write(x int)
}

type BaseObject struct {
}

func (p *BaseObject) DoSomething(arg *FirstArg, a int) {
    arg.Write(arg.Read() + a)
}

我的意图是编写一个名为 gen_structure 的go程序,其用法如下:

My intention is to write a go program called gen_structure that is used like this

$ gen_structure example.go

输出应为

> MyObject
- DoMyThing(arg)
- base
    - DoSomething(arg, a)

gen_structure是做什么的?

它解析example.go和

It parses example.go and

  1. 从main()函数内部的 example_package.GetItStarted(& MyObject {})行中提取"MyObject".
  2. MyObject 上查找具有至少一个参数且第一个参数为 * package_example.FirstArg 类型的方法.它会找到 DoMyThing (并忽略了 DoMyAnotherThing ).
  3. 标识成员 base 并在其中偷看(通过打开 example_package ).
  4. 应用相同的过程来查找上述方法并找到 DoSomething
  5. 使用收集的信息,它将打印所需的输出.
  1. Extracts "MyObject" from the line example_package.GetItStarted(&MyObject{}) from inside the main() function.
  2. Looks for methods on MyObject that have atleast one argument with the first one being of type *package_example.FirstArg. It finds DoMyThing (and ignored DoMyAnotherThing).
  3. Identifies the member base and peeks inside (by opening the example_package).
  4. Applies the same process to find methods as above and finds DoSomething
  5. Using the collected information, it prints the required output.

我了解我可以使用 go/parser 中的功能来解析同一目录中的单个文件或一堆文件.但是,我无法弄清楚如何在包之间解析符号(在本例中为 example_package ).

I understand I can parse a single file or a bunch of files in the same directory using the functionality within go/parser. However, I am unable to figure out how to resolve symbols across packages (In this case, example_package).

我该怎么做?

推荐答案

致电 ast.NewPackage 解析程序包名称.您将需要提供一个进口商,它返回一个 * ast.Object ,并且种类设置为名称设置为程序包的名称.导入程序中的大部分繁琐工作都可以通过 go/build 软件包来完成.如果要解析对目标程序包的AST,则需要解析该程序包并返回该程序包的ast.Object.为防止多次加载同一软件包,请使用导入器的map参数作为以前加载的软件包的缓存.

Call ast.NewPackage to resolve a package names. You will need to supply an importer that returns an *ast.Object for the given import path. If all you want to do is resolve the name to a path, the importer can simply return an *ast.Object with the Kind set to ast.Pkg and the Name set to name of the package. Most of the heavy lifting in the importer can be done with the go/build package. If want to resolve do the AST for the target package, you will need to parse the package and return the ast.Object for the package. To prevent loading the same package multiple times, use the map argument to the importer as a cache of previously loaded packages.

这里有一些未经测试的代码,用于从 * ast.SelectorExpr se 查找已解析的程序包路径:

Here's some untested code for finding the resolved package path from the *ast.SelectorExpr se:

    if x, _ := se.X.(*ast.Ident); x != nil {
        if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg {
            if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil {
                if path, err := strconv.Unquote(spec.Path.Value); err == nil {
                    // path is resolved path for selector expression se.
                }
            }
         }
     }

go/types 包也可以用于获取此信息以及更多信息.我建议您使用go/types,而不要直接使用go/ast.

The go/types package can also be used to get this information and more. I recommend using go/types instead of using go/ast directly.

这篇关于跨包使用go/parser的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆