Я использовал go / parser для анализа файла golang и изучения его AST. У меня есть конкретная проблема, для которой я хочу использовать go / parser, но столкнулся с препятствием.
Учтите, что в 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)
}
Я намерен написать программу go, gen_structure
которая будет использоваться вот так
$ gen_structure example.go
Результат будет
> MyObject
- DoMyThing(arg)
- base
- DoSomething(arg, a)
Что сделала gen_structure?
Он анализирует example.go и
example_package.GetItStarted(&MyObject{})
внутри функции main ().MyObject
которые имеют хотя бы один аргумент, первый из которых имеет тип *package_example.FirstArg
. Находит DoMyThing
(и игнорирует DoMyAnotherThing
).base
и заглядывает внутрь (открывая example_package
).DoSomething
Я понимаю, что могу проанализировать один файл или несколько файлов в одном каталоге, используя внутренние функции go/parser
. Однако я не могу понять, как разрешать символы в пакетах (в данном случае example_package
).
Как мне это сделать?
Вызов ast.NewPackage для разрешения имен пакетов. Вам нужно будет предоставить импортер, который возвращает * ast.Object для заданного пути импорта. Если все, что вы хотите сделать, это преобразовать имя в путь, импортер может просто вернуть * ast.Object с Kind, установленным на ast.Pkg, и Name, установленным на имя пакета. Большую часть тяжелой работы в импортере можно выполнить с помощью go / build.пакет. Если вы хотите решить, выполните AST для целевого пакета, вам нужно будет проанализировать пакет и вернуть ast.Object для пакета. Чтобы предотвратить загрузку одного и того же пакета несколько раз, используйте аргумент map для импортера в качестве кеша ранее загруженных пакетов.
Вот некоторый непроверенный код для поиска разрешенного пути к пакету из *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.
Эта статья взята из Интернета, укажите источник при перепечатке.
Если есть какие-либо нарушения, пожалуйста, свяжитесь с[email protected] Удалить.
я говорю два предложения