1. 源码示例
package mainimport ("context"
)// Foo 结构体
type Foo struct {i int
}// Bar 接口
type Bar interface {Do(ctx context.Context) error
}// main方法
func main() {a := 1
}
2. Golang中的AST
golang官方提供的几个包,可以帮助我们进行AST分析:
-
go/scanner:词法解析,将源代码分割成一个个token
-
go/token:token类型及相关结构体定义
-
go/ast:ast的结构定义
-
- ast的各种结构定义入口在
go/ast/ast.go
上
- ast的各种结构定义入口在
-
go/parser:语法分析,读取token流生成ast
通过上述的四个库,我们就可以实现golang代码的语法树分析
3. 使用main.go解析demo.go的AST树
package mainimport ("go/ast""go/parser""go/token""log""path/filepath"
)func main() {fset := token.NewFileSet()// 这里取绝对路径,方便打印出来的语法树可以转跳到编辑器path, _ := filepath.Abs("./demo.go")f, err := parser.ParseFile(fset, path, nil, parser.AllErrors)if err != nil {log.Println(err)return}// 打印语法树ast.Print(fset, f)
}
3.1. 解析的结果如下
可在http://goast.yuroyoro.net/里贴上源代码后查看
*ast.File {1 . Package: 1:12 . Name: *ast.Ident {3 . . NamePos: 1:94 . . Name: "main"5 . }6 . Decls: []ast.Decl (len = 4) {7 . . 0: *ast.GenDecl {8 . . . TokPos: 3:19 . . . Tok: import10 . . . Lparen: 3:811 . . . Specs: []ast.Spec (len = 1) {12 . . . . 0: *ast.ImportSpec {13 . . . . . Path: *ast.BasicLit {14 . . . . . . ValuePos: 4:215 . . . . . . Kind: STRING16 . . . . . . Value: "\"context\""17 . . . . . }18 . . . . . EndPos: -19 . . . . }20 . . . }21 . . . Rparen: 5:122 . . }23 . . 1: *ast.GenDecl {24 . . . TokPos: 8:125 . . . Tok: type26 . . . Lparen: -27 . . . Specs: []ast.Spec (len = 1) {28 . . . . 0: *ast.TypeSpec {29 . . . . . Name: *ast.Ident {30 . . . . . . NamePos: 8:631 . . . . . . Name: "Foo"32 . . . . . . Obj: *ast.Object {33 . . . . . . . Kind: type34 . . . . . . . Name: "Foo"35 . . . . . . . Decl: *(obj @ 28)36 . . . . . . }37 . . . . . }38 . . . . . Type: *ast.StructType {39 . . . . . . Struct: 8:1040 . . . . . . Fields: *ast.FieldList {41 . . . . . . . Opening: 8:1742 . . . . . . . List: []*ast.Field (len = 1) {43 . . . . . . . . 0: *ast.Field {44 . . . . . . . . . Names: []*ast.Ident (len = 1) {45 . . . . . . . . . . 0: *ast.Ident {46 . . . . . . . . . . . NamePos: 9:247 . . . . . . . . . . . Name: "i"48 . . . . . . . . . . . Obj: *ast.Object {49 . . . . . . . . . . . . Kind: var50 . . . . . . . . . . . . Name: "i"51 . . . . . . . . . . . . Decl: *(obj @ 43)52 . . . . . . . . . . . }53 . . . . . . . . . . }54 . . . . . . . . . }55 . . . . . . . . . Type: *ast.Ident {56 . . . . . . . . . . NamePos: 9:457 . . . . . . . . . . Name: "int"58 . . . . . . . . . }59 . . . . . . . . }60 . . . . . . . }61 . . . . . . . Closing: 10:162 . . . . . . }63 . . . . . . Incomplete: false64 . . . . . }65 . . . . }66 . . . }67 . . . Rparen: -68 . . }69 . . 2: *ast.GenDecl {70 . . . TokPos: 13:171 . . . Tok: type72 . . . Lparen: -73 . . . Specs: []ast.Spec (len = 1) {74 . . . . 0: *ast.TypeSpec {75 . . . . . Name: *ast.Ident {76 . . . . . . NamePos: 13:677 . . . . . . Name: "Bar"78 . . . . . . Obj: *ast.Object {79 . . . . . . . Kind: type80 . . . . . . . Name: "Bar"81 . . . . . . . Decl: *(obj @ 74)82 . . . . . . }83 . . . . . }84 . . . . . Type: *ast.InterfaceType {85 . . . . . . Interface: 13:1086 . . . . . . Methods: *ast.FieldList {87 . . . . . . . Opening: 13:2088 . . . . . . . List: []*ast.Field (len = 1) {89 . . . . . . . . 0: *ast.Field {90 . . . . . . . . . Names: []*ast.Ident (len = 1) {91 . . . . . . . . . . 0: *ast.Ident {92 . . . . . . . . . . . NamePos: 14:293 . . . . . . . . . . . Name: "Do"94 . . . . . . . . . . . Obj: *ast.Object {95 . . . . . . . . . . . . Kind: func96 . . . . . . . . . . . . Name: "Do"97 . . . . . . . . . . . . Decl: *(obj @ 89)98 . . . . . . . . . . . }99 . . . . . . . . . . }100 . . . . . . . . . }101 . . . . . . . . . Type: *ast.FuncType {102 . . . . . . . . . . Func: -103 . . . . . . . . . . Params: *ast.FieldList {104 . . . . . . . . . . . Opening: 14:4105 . . . . . . . . . . . List: []*ast.Field (len = 1) {106 . . . . . . . . . . . . 0: *ast.Field {107 . . . . . . . . . . . . . Names: []*ast.Ident (len = 1) {108 . . . . . . . . . . . . . . 0: *ast.Ident {109 . . . . . . . . . . . . . . . NamePos: 14:5110 . . . . . . . . . . . . . . . Name: "ctx"111 . . . . . . . . . . . . . . . Obj: *ast.Object {112 . . . . . . . . . . . . . . . . Kind: var113 . . . . . . . . . . . . . . . . Name: "ctx"114 . . . . . . . . . . . . . . . . Decl: *(obj @ 106)115 . . . . . . . . . . . . . . . }116 . . . . . . . . . . . . . . }117 . . . . . . . . . . . . . }118 . . . . . . . . . . . . . Type: *ast.SelectorExpr {119 . . . . . . . . . . . . . . X: *ast.Ident {120 . . . . . . . . . . . . . . . NamePos: 14:9121 . . . . . . . . . . . . . . . Name: "context"122 . . . . . . . . . . . . . . }123 . . . . . . . . . . . . . . Sel: *ast.Ident {124 . . . . . . . . . . . . . . . NamePos: 14:17125 . . . . . . . . . . . . . . . Name: "Context"126 . . . . . . . . . . . . . . }127 . . . . . . . . . . . . . }128 . . . . . . . . . . . . }129 . . . . . . . . . . . }130 . . . . . . . . . . . Closing: 14:24131 . . . . . . . . . . }132 . . . . . . . . . . Results: *ast.FieldList {133 . . . . . . . . . . . Opening: -134 . . . . . . . . . . . List: []*ast.Field (len = 1) {135 . . . . . . . . . . . . 0: *ast.Field {136 . . . . . . . . . . . . . Type: *ast.Ident {137 . . . . . . . . . . . . . . NamePos: 14:26138 . . . . . . . . . . . . . . Name: "error"139 . . . . . . . . . . . . . }140 . . . . . . . . . . . . }141 . . . . . . . . . . . }142 . . . . . . . . . . . Closing: -143 . . . . . . . . . . }144 . . . . . . . . . }145 . . . . . . . . }146 . . . . . . . }147 . . . . . . . Closing: 15:1148 . . . . . . }149 . . . . . . Incomplete: false150 . . . . . }151 . . . . }152 . . . }153 . . . Rparen: -154 . . }155 . . 3: *ast.FuncDecl {156 . . . Name: *ast.Ident {157 . . . . NamePos: 18:6158 . . . . Name: "main"159 . . . . Obj: *ast.Object {160 . . . . . Kind: func161 . . . . . Name: "main"162 . . . . . Decl: *(obj @ 155)163 . . . . }164 . . . }165 . . . Type: *ast.FuncType {166 . . . . Func: 18:1167 . . . . Params: *ast.FieldList {168 . . . . . Opening: 18:10169 . . . . . Closing: 18:11170 . . . . }171 . . . }172 . . . Body: *ast.BlockStmt {173 . . . . Lbrace: 18:13174 . . . . List: []ast.Stmt (len = 1) {175 . . . . . 0: *ast.AssignStmt {176 . . . . . . Lhs: []ast.Expr (len = 1) {177 . . . . . . . 0: *ast.Ident {178 . . . . . . . . NamePos: 19:2179 . . . . . . . . Name: "a"180 . . . . . . . . Obj: *ast.Object {181 . . . . . . . . . Kind: var182 . . . . . . . . . Name: "a"183 . . . . . . . . . Decl: *(obj @ 175)184 . . . . . . . . }185 . . . . . . . }186 . . . . . . }187 . . . . . . TokPos: 19:4188 . . . . . . Tok: :=189 . . . . . . Rhs: []ast.Expr (len = 1) {190 . . . . . . . 0: *ast.BasicLit {191 . . . . . . . . ValuePos: 19:7192 . . . . . . . . Kind: INT193 . . . . . . . . Value: "1"194 . . . . . . . }195 . . . . . . }196 . . . . . }197 . . . . }198 . . . . Rbrace: 20:1199 . . . }200 . . }201 . }202 . Scope: *ast.Scope {203 . . Objects: map[string]*ast.Object (len = 3) {204 . . . "Foo": *(obj @ 32)205 . . . "Bar": *(obj @ 78)206 . . . "main": *(obj @ 159)207 . . }208 . }209 . Imports: []*ast.ImportSpec (len = 1) {210 . . 0: *(obj @ 12)211 . }212 . Unresolved: []*ast.Ident (len = 3) {213 . . 0: *(obj @ 55)214 . . 1: *(obj @ 119)215 . . 2: *(obj @ 136)216 . }217 }
4. AST树结构
// 该结构体位于标准包 go/ast/ast.go 中,有兴趣可以转跳到源码阅读更详尽的注释
type File struct {Doc *CommentGroup // 如果文件有文档,则文档会被存储在这个结构体中,否则为 nilPackage token.Pos // "package"关键字,主要是所在的位置信息Name *Ident // package的名字Decls []Decl // 文件级别的声明。它包含文件中所有变量、函数、类型声明。如果文件中没有声明,则 decls 值为 nilScope *Scope // 包级作用域。它代表包级作用域,包含所有在包内声明的变量和函数。它对当前文件有效Imports []*ImportSpec // imports in this fileUnresolved []*Ident // unresolved identifiers in this file。未使用的标识符Comments []*CommentGroup // 文件中的所有注释。它包含文件中所有注释的列表
}
4.1. Doc
如果文件有文档,则文档会被存储在这个结构体中,否则为 nil
todo:目前没找到什么样的源代码解析成AST树后有Doc的
4.2. Package
*ast.File {1 . Package: 1:12 . Name: *ast.Ident {3 . . NamePos: 1:94 . . Name: "main"5 . }
Package: 1:1
, package关键字所在的位置
4.3. Name
type为ast.ident
,表示它是一个变量值,可以看到内容为"main"
4.4. Decls
文件级别的声明。它包含文件中所有变量、函数、类型声明。如果文件中没有声明,则 decls 值为 nil
4.5. Decls总共有三种类型
4.5.1. BadDecl
语法出错的声明
4.5.2. GenDecl
常规的声明,包含以下部分
- import
- constant
- type
- variable
4.5.2.1. import
4.5.2.2. constant
4.5.2.3. type
4.5.2.4. variable
4.5.3. FunDecl
方法的声明
4.6. Scope
包级作用域。它代表包级作用域,包含所有在包内声明的变量和函数。它对当前文件有效
4.6.1. 示例如下
4.7. Imports
回顾以下File
结构体定义,其中Imports
为ImportSpec
类型数组
// 该结构体位于标准包 go/ast/ast.go 中,有兴趣可以转跳到源码阅读更详尽的注释
type File struct {Doc *CommentGroup // 如果文件有文档,则文档会被存储在这个结构体中,否则为 nilPackage token.Pos // "package"关键字,主要是所在的位置信息Name *Ident // package的名字Decls []Decl // 文件级别的声明。它包含文件中所有变量、函数、类型声明。如果文件中没有声明,则 decls 值为 nilScope *Scope // 包级作用域。它代表包级作用域,包含所有在包内声明的变量和函数。它对当前文件有效Imports []*ImportSpec // imports in this fileUnresolved []*Ident // unresolved identifiers in this file。未使用的标识符Comments []*CommentGroup // 文件中的所有注释。它包含文件中所有注释的列表
}
ImportSpec
结构体定义如下,一条import就是一个ImportSpec
// An ImportSpec node represents a single package import.ImportSpec struct {Doc *CommentGroup // associated documentation; or nilName *Ident // local package name (including "."); or nilPath *BasicLit // import pathComment *CommentGroup // line comments; or nilEndPos token.Pos // end of spec (overrides Path.Pos if nonzero)}
4.8. Unresolved
unresolved identifiers in this file。未使用的标识符
4.9. Comments
文件中的所有注释。它包含文件中所有注释的列表。实际上这块有问题,并没有注释解析出来
5. AST数节点类型
6. 参考资料
- Golang AST语法树使用教程及示例
- GoAst Viewer
- https://github.com/DrmagicE/ast-example
- [golang深入源代码系列之一:AST的遍历](