空语句块
func main() {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "hello.go", src, parser.AllErrors)
if err != nil {
log.Fatal(err)
return
}
ast.Print(nil, f.Decls[0].(*ast.FuncDecl).Body)
}
const src = `package pkgname
func main() {}
`
---------------------------output-------------------------
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . Rbrace: 30
3 }
函数的声明由ast.FuncDecl结构体定义,其中的Body成员是ast.BlockStmt类型。ast.BlockStmt类型的定义如下:
type Stmt interface {
Node
// contains filtered or unexported methods
}
type BlockStmt struct {
Lbrace token.Pos // position of "{"
List []Stmt
Rbrace token.Pos // position of "}"
}
因为由大括弧定义的语句块也是一种合法的语句,因此我们可以在函数体再定义任意个空的语句块:
func main() {
{}
{}
}
再次分析函数体的语法树,可以得到以下的结果:
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . List: []ast.Stmt (len = 2) {
3 . . 0: *ast.BlockStmt {
4 . . . Lbrace: 32
5 . . . Rbrace: 33
6 . . }
7 . . 1: *ast.BlockStmt {
8 . . . Lbrace: 36
9 . . . Rbrace: 37
10 . . }
11 . }
12 . Rbrace: 39
13 }
其中List部分有两个新定义的语句块,每个语句块依然是ast.BlockStmt类型。
返回语句
func main() {
return 42, err
}
当然,按照Go语言规范main函数是没有返回值的,因此return语句也不能有返回值。不过我们目前还处在语法树解析阶段,并不会检查返回语句和函数的返回值类型是否匹配,这种类型匹配检查要在语法树构建之后才会进行。
main函数体的语法树结果如下:
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . List: []ast.Stmt (len = 1) {
3 . . 0: *ast.ReturnStmt {
4 . . . Return: 32
5 . . . Results: []ast.Expr (len = 2) {
6 . . . . 0: *ast.BasicLit {
7 . . . . . ValuePos: 39
8 . . . . . Kind: INT
9 . . . . . Value: "42"
10 . . . . }
11 . . . . 1: *ast.Ident {
12 . . . . . NamePos: 43
13 . . . . . Name: "err"
14 . . . . }
15 . . . }
16 . . }
17 . }
18 . Rbrace: 47
19 }
返回语句由ast.ReturnStmt类型表示,其中Results成员对应返回值列表,这里分别是基础的数值常量42和标识符err。ast.ReturnStmt类型定义如下:
type ReturnStmt struct {
Return token.Pos // position of "return" keyword
Results []Expr // result expressions; or nil
}
其中Return成员表示return关键字的位置,Results成员对应一个表达式列表,如果为nil表示没有返回值。
声明语句
func main() {
var a int
}
语法树解析输出如下:
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . List: []ast.Stmt (len = 1) {
3 . . 0: *ast.DeclStmt {
4 . . . Decl: *ast.GenDecl {
5 . . . . TokPos: 32
6 . . . . Tok: var
7 . . . . Lparen: 0
8 . . . . Specs: []ast.Spec (len = 1) {
9 . . . . . 0: *ast.ValueSpec {
10 . . . . . . Names: []*ast.Ident (len = 1) {
11 . . . . . . . 0: *ast.Ident {
12 . . . . . . . . NamePos: 36
13 . . . . . . . . Name: "a"
14 . . . . . . . . Obj: *ast.Object {...}
20 . . . . . . . }
21 . . . . . . }
22 . . . . . . Type: *ast.Ident {
23 . . . . . . . NamePos: 38
24 . . . . . . . Name: "int"
25 . . . . . . }
26 . . . . . }
27 . . . . }
28 . . . . Rparen: 0
29 . . . }
30 . . }
31 . }
32 . Rbrace: 42
33 }
声明的变量在ast.DeclStmt结构体中表示,结构体定义如下:
type DeclStmt struct {
Decl Decl // *GenDecl with CONST, TYPE, or VAR token
}
短声明和多赋值语句
func main() {
a, b := 1, 2
}
输出的语法树结果如下:
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . List: []ast.Stmt (len = 1) {
3 . . 0: *ast.AssignStmt {
4 . . . Lhs: []ast.Expr (len = 2) {
5 . . . . 0: *ast.Ident {
6 . . . . . NamePos: 32
7 . . . . . Name: "a"
8 . . . . . Obj: *ast.Object {
9 . . . . . . Kind: var
10 . . . . . . Name: "a"
11 . . . . . . Decl: *(obj @ 3)
12 . . . . . }
13 . . . . }
14 . . . . 1: *ast.Ident {
15 . . . . . NamePos: 35
16 . . . . . Name: "b"
17 . . . . . Obj: *ast.Object {
18 . . . . . . Kind: var
19 . . . . . . Name: "b"
20 . . . . . . Decl: *(obj @ 3)
21 . . . . . }
22 . . . . }
23 . . . }
24 . . . TokPos: 37
25 . . . Tok: :=
26 . . . Rhs: []ast.Expr (len = 2) {
27 . . . . 0: *ast.BasicLit {
28 . . . . . ValuePos: 40
29 . . . . . Kind: INT
30 . . . . . Value: "1"
31 . . . . }
32 . . . . 1: *ast.BasicLit {
33 . . . . . ValuePos: 43
34 . . . . . Kind: INT
35 . . . . . Value: "2"
36 . . . . }
37 . . . }
38 . . }
39 . }
40 . Rbrace: 45
41 }
短声明和多赋值语句都通过ast.AssignStmt结构体表达,其定义如下:
type AssignStmt struct {
Lhs []Expr
TokPos token.Pos // position of Tok
Tok token.Token // assignment token, DEFINE
Rhs []Expr
}
其中Lhs表示左边的表达式或标识符列表,而Rhs表示右边的表达式列表。短声明和多赋值语句是通过Tok来进行区分。
if/else分支语句
func main() {
if true {} else {}
}
输出的语法树如下:
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . List: []ast.Stmt (len = 1) {
3 . . 0: *ast.IfStmt {
4 . . . If: 32
5 . . . Cond: *ast.Ident {
6 . . . . NamePos: 35
7 . . . . Name: "true"
8 . . . }
9 . . . Body: *ast.BlockStmt {
10 . . . . Lbrace: 40
11 . . . . Rbrace: 41
12 . . . }
13 . . . Else: *ast.BlockStmt {
14 . . . . Lbrace: 48
15 . . . . Rbrace: 49
16 . . . }
17 . . }
18 . }
19 . Rbrace: 51
20 }
if由ast.IfStmt结构体表示,其中的Cond为分支的条件表达式,Body为分支的主体语句块,Else为补充的语句块。ast.IfStmt结构体完整定义如下:
type IfStmt struct {
If token.Pos // position of "if" keyword
Init Stmt // initialization statement; or nil
Cond Expr // condition
Body *BlockStmt
Else Stmt // else branch; or nil
}
for循环
for语法对应下面四种
for {}
for true {}
for i := 0; true; i++ {}
for i, v := range m {}
以上四个循环语句可以再次归纳为以下两种:
for x; y; z {}
for x, y := range z {}
因此我们先分析经典风格的for x; y; z {}循环:
func main() {
for x; y; z {}
}
其语法树结构如下:
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . List: []ast.Stmt (len = 1) {
3 . . 0: *ast.ForStmt {
4 . . . For: 32
5 . . . Init: *ast.ExprStmt {
6 . . . . X: *ast.Ident {
7 . . . . . NamePos: 36
8 . . . . . Name: "x"
9 . . . . }
10 . . . }
11 . . . Cond: *ast.Ident {
12 . . . . NamePos: 39
13 . . . . Name: "y"
14 . . . }
15 . . . Post: *ast.ExprStmt {
16 . . . . X: *ast.Ident {
17 . . . . . NamePos: 42
18 . . . . . Name: "z"
19 . . . . }
20 . . . }
21 . . . Body: *ast.BlockStmt {
22 . . . . Lbrace: 44
23 . . . . Rbrace: 45
24 . . . }
25 . . }
26 . }
27 . Rbrace: 47
28 }
ast.ForStmt结构体表示经典的for循环,其中Init、Cond、Post和Body分别对应初始化语句、条件语句、迭代语句和循环体语句。ast.ForStmt结构体的定义如下:
type ForStmt struct {
For token.Pos // position of "for" keyword
Init Stmt // initialization statement; or nil
Cond Expr // condition; or nil
Post Stmt // post iteration statement; or nil
Body *BlockStmt
}
在了解了经典风格的循环之后,我们再来看看最简单的for range循环:
func main() {
for range ch {}
}
我们省略来循环中的Key和Value部分。其语法树如下:
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . List: []ast.Stmt (len = 1) {
3 . . 0: *ast.RangeStmt {
4 . . . For: 32
5 . . . TokPos: 0
6 . . . Tok: ILLEGAL
7 . . . X: *ast.Ident {
8 . . . . NamePos: 42
9 . . . . Name: "ch"
10 . . . }
11 . . . Body: *ast.BlockStmt {
12 . . . . Lbrace: 45
13 . . . . Rbrace: 46
14 . . . }
15 . . }
16 . }
17 . Rbrace: 48
18 }
for range循环的语法树由ast.RangeStmt结构表示,其完整定义如下:
type RangeStmt struct {
For token.Pos // position of "for" keyword
Key, Value Expr // Key, Value may be nil
TokPos token.Pos // position of Tok; invalid if Key == nil
Tok token.Token // ILLEGAL if Key == nil, ASSIGN, DEFINE
X Expr // value to range over
Body *BlockStmt
}
其中Key和Value对应循环时的迭代位置和值,X成员是生成要循环对象的表达式(可能是数组、切片、map和管道等),Body表示循环体语句块。另外,Tok成员可以区别Key和Value是多赋值语句还是短变量声明语句。
类型断言
func main() {
x.(int)
}
对x做类型断言,如果成功则返回x里面存储的int类型的值,如果失败则抛出异常。生成的语法树如下:
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . List: []ast.Stmt (len = 1) {
3 . . 0: *ast.ExprStmt {
4 . . . X: *ast.TypeAssertExpr {
5 . . . . X: *ast.Ident {
6 . . . . . NamePos: 32
7 . . . . . Name: "x"
8 . . . . }
9 . . . . Lparen: 34
10 . . . . Type: *ast.Ident {
11 . . . . . NamePos: 35
12 . . . . . Name: "int"
13 . . . . }
14 . . . . Rparen: 38
15 . . . }
16 . . }
17 . }
18 . Rbrace: 40
19 }
需要注意语法树的结构:首先是ast.ExprStmt结构体表示的表达式语句,其中的X成员才是对应类型断言表达式。类型断言由ast.TypeAssertExpr结构体表示,其定义如下:
type TypeAssertExpr struct {
X Expr // expression
Lparen token.Pos // position of "("
Type Expr // asserted type; nil means type switch X.(type)
Rparen token.Pos // position of ")"
}
其中X成员是类型断言的主体表达式(产生一个接口值),Type成员是类型的表达式。如果Type为nil,则表示对应x.(type)形式的断言,否则是类型switch中使用的形式。
go和defer语句
go和defer语句在语法树中分别以ast.GoStmt和ast.DeferStmt结构定义:
type GoStmt struct {
Go token.Pos // position of "go" keyword
Call *CallExpr
}
type DeferStmt struct {
Defer token.Pos // position of "defer" keyword
Call *CallExpr
}
func main() {
go hello("光谷码农")
}
其对应的语法树结果:
0 *ast.BlockStmt {
1 . Lbrace: 29
2 . List: []ast.Stmt (len = 1) {
3 . . 0: *ast.GoStmt {
4 . . . Go: 32
5 . . . Call: *ast.CallExpr {
6 . . . . Fun: *ast.Ident {
7 . . . . . NamePos: 35
8 . . . . . Name: "hello"
9 . . . . }
10 . . . . Lparen: 40
11 . . . . Args: []ast.Expr (len = 1) {
12 . . . . . 0: *ast.BasicLit {
13 . . . . . . ValuePos: 41
14 . . . . . . Kind: STRING
15 . . . . . . Value: "\"光谷码农\""
16 . . . . . }
17 . . . . }
18 . . . . Ellipsis: 0
19 . . . . Rparen: 55
20 . . . }
21 . . }
22 . }
23 . Rbrace: 57
24 }