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的遍历](