1. 源码示例
package main
import (
"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 main
import (
"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:1
2 . Name: *ast.Ident {
3 . . NamePos: 1:9
4 . . Name: "main"
5 . }
6 . Decls: []ast.Decl (len = 4) {
7 . . 0: *ast.GenDecl {
8 . . . TokPos: 3:1
9 . . . Tok: import
10 . . . Lparen: 3:8
11 . . . Specs: []ast.Spec (len = 1) {
12 . . . . 0: *ast.ImportSpec {
13 . . . . . Path: *ast.BasicLit {
14 . . . . . . ValuePos: 4:2
15 . . . . . . Kind: STRING
16 . . . . . . Value: "\"context\""
17 . . . . . }
18 . . . . . EndPos: -
19 . . . . }
20 . . . }
21 . . . Rparen: 5:1
22 . . }
23 . . 1: *ast.GenDecl {
24 . . . TokPos: 8:1
25 . . . Tok: type
26 . . . Lparen: -
27 . . . Specs: []ast.Spec (len = 1) {
28 . . . . 0: *ast.TypeSpec {
29 . . . . . Name: *ast.Ident {
30 . . . . . . NamePos: 8:6
31 . . . . . . Name: "Foo"
32 . . . . . . Obj: *ast.Object {
33 . . . . . . . Kind: type
34 . . . . . . . Name: "Foo"
35 . . . . . . . Decl: *(obj @ 28)
36 . . . . . . }
37 . . . . . }
38 . . . . . Type: *ast.StructType {
39 . . . . . . Struct: 8:10
40 . . . . . . Fields: *ast.FieldList {
41 . . . . . . . Opening: 8:17
42 . . . . . . . List: []*ast.Field (len = 1) {
43 . . . . . . . . 0: *ast.Field {
44 . . . . . . . . . Names: []*ast.Ident (len = 1) {
45 . . . . . . . . . . 0: *ast.Ident {
46 . . . . . . . . . . . NamePos: 9:2
47 . . . . . . . . . . . Name: "i"
48 . . . . . . . . . . . Obj: *ast.Object {
49 . . . . . . . . . . . . Kind: var
50 . . . . . . . . . . . . Name: "i"
51 . . . . . . . . . . . . Decl: *(obj @ 43)
52 . . . . . . . . . . . }
53 . . . . . . . . . . }
54 . . . . . . . . . }
55 . . . . . . . . . Type: *ast.Ident {
56 . . . . . . . . . . NamePos: 9:4
57 . . . . . . . . . . Name: "int"
58 . . . . . . . . . }
59 . . . . . . . . }
60 . . . . . . . }
61 . . . . . . . Closing: 10:1
62 . . . . . . }
63 . . . . . . Incomplete: false
64 . . . . . }
65 . . . . }
66 . . . }
67 . . . Rparen: -
68 . . }
69 . . 2: *ast.GenDecl {
70 . . . TokPos: 13:1
71 . . . Tok: type
72 . . . Lparen: -
73 . . . Specs: []ast.Spec (len = 1) {
74 . . . . 0: *ast.TypeSpec {
75 . . . . . Name: *ast.Ident {
76 . . . . . . NamePos: 13:6
77 . . . . . . Name: "Bar"
78 . . . . . . Obj: *ast.Object {
79 . . . . . . . Kind: type
80 . . . . . . . Name: "Bar"
81 . . . . . . . Decl: *(obj @ 74)
82 . . . . . . }
83 . . . . . }
84 . . . . . Type: *ast.InterfaceType {
85 . . . . . . Interface: 13:10
86 . . . . . . Methods: *ast.FieldList {
87 . . . . . . . Opening: 13:20
88 . . . . . . . List: []*ast.Field (len = 1) {
89 . . . . . . . . 0: *ast.Field {
90 . . . . . . . . . Names: []*ast.Ident (len = 1) {
91 . . . . . . . . . . 0: *ast.Ident {
92 . . . . . . . . . . . NamePos: 14:2
93 . . . . . . . . . . . Name: "Do"
94 . . . . . . . . . . . Obj: *ast.Object {
95 . . . . . . . . . . . . Kind: func
96 . . . . . . . . . . . . Name: "Do"
97 . . . . . . . . . . . . Decl: *(obj @ 89)
98 . . . . . . . . . . . }
99 . . . . . . . . . . }
100 . . . . . . . . . }
101 . . . . . . . . . Type: *ast.FuncType {
102 . . . . . . . . . . Func: -
103 . . . . . . . . . . Params: *ast.FieldList {
104 . . . . . . . . . . . Opening: 14:4
105 . . . . . . . . . . . List: []*ast.Field (len = 1) {
106 . . . . . . . . . . . . 0: *ast.Field {
107 . . . . . . . . . . . . . Names: []*ast.Ident (len = 1) {
108 . . . . . . . . . . . . . . 0: *ast.Ident {
109 . . . . . . . . . . . . . . . NamePos: 14:5
110 . . . . . . . . . . . . . . . Name: "ctx"
111 . . . . . . . . . . . . . . . Obj: *ast.Object {
112 . . . . . . . . . . . . . . . . Kind: var
113 . . . . . . . . . . . . . . . . Name: "ctx"
114 . . . . . . . . . . . . . . . . Decl: *(obj @ 106)
115 . . . . . . . . . . . . . . . }
116 . . . . . . . . . . . . . . }
117 . . . . . . . . . . . . . }
118 . . . . . . . . . . . . . Type: *ast.SelectorExpr {
119 . . . . . . . . . . . . . . X: *ast.Ident {
120 . . . . . . . . . . . . . . . NamePos: 14:9
121 . . . . . . . . . . . . . . . Name: "context"
122 . . . . . . . . . . . . . . }
123 . . . . . . . . . . . . . . Sel: *ast.Ident {
124 . . . . . . . . . . . . . . . NamePos: 14:17
125 . . . . . . . . . . . . . . . Name: "Context"
126 . . . . . . . . . . . . . . }
127 . . . . . . . . . . . . . }
128 . . . . . . . . . . . . }
129 . . . . . . . . . . . }
130 . . . . . . . . . . . Closing: 14:24
131 . . . . . . . . . . }
132 . . . . . . . . . . Results: *ast.FieldList {
133 . . . . . . . . . . . Opening: -
134 . . . . . . . . . . . List: []*ast.Field (len = 1) {
135 . . . . . . . . . . . . 0: *ast.Field {
136 . . . . . . . . . . . . . Type: *ast.Ident {
137 . . . . . . . . . . . . . . NamePos: 14:26
138 . . . . . . . . . . . . . . Name: "error"
139 . . . . . . . . . . . . . }
140 . . . . . . . . . . . . }
141 . . . . . . . . . . . }
142 . . . . . . . . . . . Closing: -
143 . . . . . . . . . . }
144 . . . . . . . . . }
145 . . . . . . . . }
146 . . . . . . . }
147 . . . . . . . Closing: 15:1
148 . . . . . . }
149 . . . . . . Incomplete: false
150 . . . . . }
151 . . . . }
152 . . . }
153 . . . Rparen: -
154 . . }
155 . . 3: *ast.FuncDecl {
156 . . . Name: *ast.Ident {
157 . . . . NamePos: 18:6
158 . . . . Name: "main"
159 . . . . Obj: *ast.Object {
160 . . . . . Kind: func
161 . . . . . Name: "main"
162 . . . . . Decl: *(obj @ 155)
163 . . . . }
164 . . . }
165 . . . Type: *ast.FuncType {
166 . . . . Func: 18:1
167 . . . . Params: *ast.FieldList {
168 . . . . . Opening: 18:10
169 . . . . . Closing: 18:11
170 . . . . }
171 . . . }
172 . . . Body: *ast.BlockStmt {
173 . . . . Lbrace: 18:13
174 . . . . List: []ast.Stmt (len = 1) {
175 . . . . . 0: *ast.AssignStmt {
176 . . . . . . Lhs: []ast.Expr (len = 1) {
177 . . . . . . . 0: *ast.Ident {
178 . . . . . . . . NamePos: 19:2
179 . . . . . . . . Name: "a"
180 . . . . . . . . Obj: *ast.Object {
181 . . . . . . . . . Kind: var
182 . . . . . . . . . Name: "a"
183 . . . . . . . . . Decl: *(obj @ 175)
184 . . . . . . . . }
185 . . . . . . . }
186 . . . . . . }
187 . . . . . . TokPos: 19:4
188 . . . . . . Tok: :=
189 . . . . . . Rhs: []ast.Expr (len = 1) {
190 . . . . . . . 0: *ast.BasicLit {
191 . . . . . . . . ValuePos: 19:7
192 . . . . . . . . Kind: INT
193 . . . . . . . . Value: "1"
194 . . . . . . . }
195 . . . . . . }
196 . . . . . }
197 . . . . }
198 . . . . Rbrace: 20:1
199 . . . }
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 // 如果文件有文档,则文档会被存储在这个结构体中,否则为 nil
Package token.Pos // "package"关键字,主要是所在的位置信息
Name *Ident // package的名字
Decls []Decl // 文件级别的声明。它包含文件中所有变量、函数、类型声明。如果文件中没有声明,则 decls 值为 nil
Scope *Scope // 包级作用域。它代表包级作用域,包含所有在包内声明的变量和函数。它对当前文件有效
Imports []*ImportSpec // imports in this file
Unresolved []*Ident // unresolved identifiers in this file。未使用的标识符
Comments []*CommentGroup // 文件中的所有注释。它包含文件中所有注释的列表
}
4.1. Doc
如果文件有文档,则文档会被存储在这个结构体中,否则为 nil
todo:目前没找到什么样的源代码解析成AST树后有Doc的
4.2. Package
*ast.File {
1 . Package: 1:1
2 . Name: *ast.Ident {
3 . . NamePos: 1:9
4 . . 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 // 如果文件有文档,则文档会被存储在这个结构体中,否则为 nil
Package token.Pos // "package"关键字,主要是所在的位置信息
Name *Ident // package的名字
Decls []Decl // 文件级别的声明。它包含文件中所有变量、函数、类型声明。如果文件中没有声明,则 decls 值为 nil
Scope *Scope // 包级作用域。它代表包级作用域,包含所有在包内声明的变量和函数。它对当前文件有效
Imports []*ImportSpec // imports in this file
Unresolved []*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 nil
Name *Ident // local package name (including "."); or nil
Path *BasicLit // import path
Comment *CommentGroup // line comments; or nil
EndPos 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的遍历](