英文:
How to resolve types into a primitives in AST parser
问题
我想提取函数的签名,以便能够在其上生成一些包装方法。为此,我正在使用golang.org/x/tools/go/packages
,它提供了读取AST的可能性。
例如,对于函数func MyFunc(param int)
的定义,你会得到一些内容:
ast.FuncDecl{
Type: *FieldList{
List: []*Field{
{
Names: []*Ident{ /*...*/ },
Type: nil, /*...*/
},
},
},
}
其中Type表示类型。
我想为所有int
参数生成一些特殊代码,但是int
也可以通过某些类型声明进行隐藏:
type MyType int
如何将ast
类型转换为编译器实际使用的真实类型?
英文:
I want to extract signatures of functions to be able generate some wrapper methods over them. For this, I'm using
golang.org/x/tools/go/packages
which provides me a possibility to read AST.
For example, for the function func MyFunc(param int)
definition, you receive some
ast.FuncDecl{
Type: *FieldList{
List: []*Field{
{
Names: []*Ident{ /*...*/ },
Type: nil, /*...*/
},
},
},
}
Where Type represents a type.
I want to generate some special code for all int
parameters, but int can be also hidden with some type declaration
type MyType int
How can I convert ast
type to the real one that the compiler has?
答案1
得分: 2
将packages.NeedTypes
和packages.NeedTypesInfo
添加到加载模式中。这样,每个加载的包都将初始化其TypesInfo
字段,而该字段的类型*types.Info
具有一个名为Types
的字段,它将AST表达式映射到类型。您可以按照以下方式使用它:
func main() {
loadConfig := new(packages.Config)
loadConfig.Mode = packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesInfo
loadConfig.Fset = token.NewFileSet()
pkgs, err := packages.Load(loadConfig, "syscall")
if err != nil {
panic(err)
}
for _, pkg := range pkgs {
for _, syn := range pkg.Syntax {
for _, dec := range syn.Decls {
if fd, ok := dec.(*ast.FuncDecl); ok && fd.Name.Name == "Kill" {
x1 := fd.Type.Params.List[0].Type // int
x2 := fd.Type.Params.List[1].Type // syscall.Signal
tv1 := pkg.TypesInfo.Types[x1]
tv2 := pkg.TypesInfo.Types[x2]
if basic, ok := tv1.Type.(*types.Basic); ok {
fmt.Printf("%#v\n", basic) // int
}
if named, ok := tv2.Type.(*types.Named); ok {
fmt.Printf("%v\n", named.Obj()) // *types.TypeName (Signal)
fmt.Printf("%#v\n", named.Underlying()) // *types.Basic (int)
}
}
}
}
}
}
英文:
Add packages.NeedTypes
and packages.NeedTypesInfo
to the load mode. With that each loaded package will have its TypesInfo
field initialized, and that field's type *types.Info
has a field called Types
which maps ast expressions to types. You can use that in the following way:
func main() {
loadConfig := new(packages.Config)
loadConfig.Mode = packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesInfo
loadConfig.Fset = token.NewFileSet()
pkgs, err := packages.Load(loadConfig, "syscall")
if err != nil {
panic(err)
}
for _, pkg := range pkgs {
for _, syn := range pkg.Syntax {
for _, dec := range syn.Decls {
if fd, ok := dec.(*ast.FuncDecl); ok && fd.Name.Name == "Kill" {
x1 := fd.Type.Params.List[0].Type // int
x2 := fd.Type.Params.List[1].Type // syscall.Signal
tv1 := pkg.TypesInfo.Types[x1]
tv2 := pkg.TypesInfo.Types[x2]
if basic, ok := tv1.Type.(*types.Basic); ok {
fmt.Printf("%#v\n", basic) // int
}
if named, ok := tv2.Type.(*types.Named); ok {
fmt.Printf("%v\n", named.Obj()) // *types.TypeName (Signal)
fmt.Printf("%#v\n", named.Underlying()) // *types.Basic (int)
}
}
}
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论