如何在 AST 解析器中将类型解析为原语
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
类型转换为编译器拥有的真实类型?
添加 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
将 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)
}
}
}
}
}
}
我想提取函数的签名以便能够在它们之上生成一些包装方法。为此,我正在使用
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
类型转换为编译器拥有的真实类型?
添加 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
将 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)
}
}
}
}
}
}