空语句块

  1. func main() {
  2. fset := token.NewFileSet()
  3. f, err := parser.ParseFile(fset, "hello.go", src, parser.AllErrors)
  4. if err != nil {
  5. log.Fatal(err)
  6. return
  7. }
  8. ast.Print(nil, f.Decls[0].(*ast.FuncDecl).Body)
  9. }
  10. const src = `package pkgname
  11. func main() {}
  12. `
  13. ---------------------------output-------------------------
  14. 0 *ast.BlockStmt {
  15. 1 . Lbrace: 29
  16. 2 . Rbrace: 30
  17. 3 }

函数的声明由ast.FuncDecl结构体定义,其中的Body成员是ast.BlockStmt类型。ast.BlockStmt类型的定义如下:

  1. type Stmt interface {
  2. Node
  3. // contains filtered or unexported methods
  4. }
  5. type BlockStmt struct {
  6. Lbrace token.Pos // position of "{"
  7. List []Stmt
  8. Rbrace token.Pos // position of "}"
  9. }

因为由大括弧定义的语句块也是一种合法的语句,因此我们可以在函数体再定义任意个空的语句块:

  1. func main() {
  2. {}
  3. {}
  4. }

再次分析函数体的语法树,可以得到以下的结果:

  1. 0 *ast.BlockStmt {
  2. 1 . Lbrace: 29
  3. 2 . List: []ast.Stmt (len = 2) {
  4. 3 . . 0: *ast.BlockStmt {
  5. 4 . . . Lbrace: 32
  6. 5 . . . Rbrace: 33
  7. 6 . . }
  8. 7 . . 1: *ast.BlockStmt {
  9. 8 . . . Lbrace: 36
  10. 9 . . . Rbrace: 37
  11. 10 . . }
  12. 11 . }
  13. 12 . Rbrace: 39
  14. 13 }

其中List部分有两个新定义的语句块,每个语句块依然是ast.BlockStmt类型。

返回语句

  1. func main() {
  2. return 42, err
  3. }

当然,按照Go语言规范main函数是没有返回值的,因此return语句也不能有返回值。不过我们目前还处在语法树解析阶段,并不会检查返回语句和函数的返回值类型是否匹配,这种类型匹配检查要在语法树构建之后才会进行。

main函数体的语法树结果如下:

  1. 0 *ast.BlockStmt {
  2. 1 . Lbrace: 29
  3. 2 . List: []ast.Stmt (len = 1) {
  4. 3 . . 0: *ast.ReturnStmt {
  5. 4 . . . Return: 32
  6. 5 . . . Results: []ast.Expr (len = 2) {
  7. 6 . . . . 0: *ast.BasicLit {
  8. 7 . . . . . ValuePos: 39
  9. 8 . . . . . Kind: INT
  10. 9 . . . . . Value: "42"
  11. 10 . . . . }
  12. 11 . . . . 1: *ast.Ident {
  13. 12 . . . . . NamePos: 43
  14. 13 . . . . . Name: "err"
  15. 14 . . . . }
  16. 15 . . . }
  17. 16 . . }
  18. 17 . }
  19. 18 . Rbrace: 47
  20. 19 }

返回语句由ast.ReturnStmt类型表示,其中Results成员对应返回值列表,这里分别是基础的数值常量42和标识符err。ast.ReturnStmt类型定义如下:

  1. type ReturnStmt struct {
  2. Return token.Pos // position of "return" keyword
  3. Results []Expr // result expressions; or nil
  4. }

其中Return成员表示return关键字的位置,Results成员对应一个表达式列表,如果为nil表示没有返回值。

声明语句

  1. func main() {
  2. var a int
  3. }

语法树解析输出如下:

  1. 0 *ast.BlockStmt {
  2. 1 . Lbrace: 29
  3. 2 . List: []ast.Stmt (len = 1) {
  4. 3 . . 0: *ast.DeclStmt {
  5. 4 . . . Decl: *ast.GenDecl {
  6. 5 . . . . TokPos: 32
  7. 6 . . . . Tok: var
  8. 7 . . . . Lparen: 0
  9. 8 . . . . Specs: []ast.Spec (len = 1) {
  10. 9 . . . . . 0: *ast.ValueSpec {
  11. 10 . . . . . . Names: []*ast.Ident (len = 1) {
  12. 11 . . . . . . . 0: *ast.Ident {
  13. 12 . . . . . . . . NamePos: 36
  14. 13 . . . . . . . . Name: "a"
  15. 14 . . . . . . . . Obj: *ast.Object {...}
  16. 20 . . . . . . . }
  17. 21 . . . . . . }
  18. 22 . . . . . . Type: *ast.Ident {
  19. 23 . . . . . . . NamePos: 38
  20. 24 . . . . . . . Name: "int"
  21. 25 . . . . . . }
  22. 26 . . . . . }
  23. 27 . . . . }
  24. 28 . . . . Rparen: 0
  25. 29 . . . }
  26. 30 . . }
  27. 31 . }
  28. 32 . Rbrace: 42
  29. 33 }

声明的变量在ast.DeclStmt结构体中表示,结构体定义如下:

  1. type DeclStmt struct {
  2. Decl Decl // *GenDecl with CONST, TYPE, or VAR token
  3. }

短声明和多赋值语句

  1. func main() {
  2. a, b := 1, 2
  3. }

输出的语法树结果如下:

  1. 0 *ast.BlockStmt {
  2. 1 . Lbrace: 29
  3. 2 . List: []ast.Stmt (len = 1) {
  4. 3 . . 0: *ast.AssignStmt {
  5. 4 . . . Lhs: []ast.Expr (len = 2) {
  6. 5 . . . . 0: *ast.Ident {
  7. 6 . . . . . NamePos: 32
  8. 7 . . . . . Name: "a"
  9. 8 . . . . . Obj: *ast.Object {
  10. 9 . . . . . . Kind: var
  11. 10 . . . . . . Name: "a"
  12. 11 . . . . . . Decl: *(obj @ 3)
  13. 12 . . . . . }
  14. 13 . . . . }
  15. 14 . . . . 1: *ast.Ident {
  16. 15 . . . . . NamePos: 35
  17. 16 . . . . . Name: "b"
  18. 17 . . . . . Obj: *ast.Object {
  19. 18 . . . . . . Kind: var
  20. 19 . . . . . . Name: "b"
  21. 20 . . . . . . Decl: *(obj @ 3)
  22. 21 . . . . . }
  23. 22 . . . . }
  24. 23 . . . }
  25. 24 . . . TokPos: 37
  26. 25 . . . Tok: :=
  27. 26 . . . Rhs: []ast.Expr (len = 2) {
  28. 27 . . . . 0: *ast.BasicLit {
  29. 28 . . . . . ValuePos: 40
  30. 29 . . . . . Kind: INT
  31. 30 . . . . . Value: "1"
  32. 31 . . . . }
  33. 32 . . . . 1: *ast.BasicLit {
  34. 33 . . . . . ValuePos: 43
  35. 34 . . . . . Kind: INT
  36. 35 . . . . . Value: "2"
  37. 36 . . . . }
  38. 37 . . . }
  39. 38 . . }
  40. 39 . }
  41. 40 . Rbrace: 45
  42. 41 }

短声明和多赋值语句都通过ast.AssignStmt结构体表达,其定义如下:

  1. type AssignStmt struct {
  2. Lhs []Expr
  3. TokPos token.Pos // position of Tok
  4. Tok token.Token // assignment token, DEFINE
  5. Rhs []Expr
  6. }

其中Lhs表示左边的表达式或标识符列表,而Rhs表示右边的表达式列表。短声明和多赋值语句是通过Tok来进行区分。

if/else分支语句

  1. func main() {
  2. if true {} else {}
  3. }

输出的语法树如下:

  1. 0 *ast.BlockStmt {
  2. 1 . Lbrace: 29
  3. 2 . List: []ast.Stmt (len = 1) {
  4. 3 . . 0: *ast.IfStmt {
  5. 4 . . . If: 32
  6. 5 . . . Cond: *ast.Ident {
  7. 6 . . . . NamePos: 35
  8. 7 . . . . Name: "true"
  9. 8 . . . }
  10. 9 . . . Body: *ast.BlockStmt {
  11. 10 . . . . Lbrace: 40
  12. 11 . . . . Rbrace: 41
  13. 12 . . . }
  14. 13 . . . Else: *ast.BlockStmt {
  15. 14 . . . . Lbrace: 48
  16. 15 . . . . Rbrace: 49
  17. 16 . . . }
  18. 17 . . }
  19. 18 . }
  20. 19 . Rbrace: 51
  21. 20 }

if由ast.IfStmt结构体表示,其中的Cond为分支的条件表达式,Body为分支的主体语句块,Else为补充的语句块。ast.IfStmt结构体完整定义如下:

  1. type IfStmt struct {
  2. If token.Pos // position of "if" keyword
  3. Init Stmt // initialization statement; or nil
  4. Cond Expr // condition
  5. Body *BlockStmt
  6. Else Stmt // else branch; or nil
  7. }

for循环

for语法对应下面四种

  1. for {}
  2. for true {}
  3. for i := 0; true; i++ {}
  4. for i, v := range m {}

以上四个循环语句可以再次归纳为以下两种:

  1. for x; y; z {}
  2. for x, y := range z {}

因此我们先分析经典风格的for x; y; z {}循环:

  1. func main() {
  2. for x; y; z {}
  3. }

其语法树结构如下:

  1. 0 *ast.BlockStmt {
  2. 1 . Lbrace: 29
  3. 2 . List: []ast.Stmt (len = 1) {
  4. 3 . . 0: *ast.ForStmt {
  5. 4 . . . For: 32
  6. 5 . . . Init: *ast.ExprStmt {
  7. 6 . . . . X: *ast.Ident {
  8. 7 . . . . . NamePos: 36
  9. 8 . . . . . Name: "x"
  10. 9 . . . . }
  11. 10 . . . }
  12. 11 . . . Cond: *ast.Ident {
  13. 12 . . . . NamePos: 39
  14. 13 . . . . Name: "y"
  15. 14 . . . }
  16. 15 . . . Post: *ast.ExprStmt {
  17. 16 . . . . X: *ast.Ident {
  18. 17 . . . . . NamePos: 42
  19. 18 . . . . . Name: "z"
  20. 19 . . . . }
  21. 20 . . . }
  22. 21 . . . Body: *ast.BlockStmt {
  23. 22 . . . . Lbrace: 44
  24. 23 . . . . Rbrace: 45
  25. 24 . . . }
  26. 25 . . }
  27. 26 . }
  28. 27 . Rbrace: 47
  29. 28 }

ast.ForStmt结构体表示经典的for循环,其中Init、Cond、Post和Body分别对应初始化语句、条件语句、迭代语句和循环体语句。ast.ForStmt结构体的定义如下:

  1. type ForStmt struct {
  2. For token.Pos // position of "for" keyword
  3. Init Stmt // initialization statement; or nil
  4. Cond Expr // condition; or nil
  5. Post Stmt // post iteration statement; or nil
  6. Body *BlockStmt
  7. }

在了解了经典风格的循环之后,我们再来看看最简单的for range循环:

  1. func main() {
  2. for range ch {}
  3. }

我们省略来循环中的Key和Value部分。其语法树如下:

  1. 0 *ast.BlockStmt {
  2. 1 . Lbrace: 29
  3. 2 . List: []ast.Stmt (len = 1) {
  4. 3 . . 0: *ast.RangeStmt {
  5. 4 . . . For: 32
  6. 5 . . . TokPos: 0
  7. 6 . . . Tok: ILLEGAL
  8. 7 . . . X: *ast.Ident {
  9. 8 . . . . NamePos: 42
  10. 9 . . . . Name: "ch"
  11. 10 . . . }
  12. 11 . . . Body: *ast.BlockStmt {
  13. 12 . . . . Lbrace: 45
  14. 13 . . . . Rbrace: 46
  15. 14 . . . }
  16. 15 . . }
  17. 16 . }
  18. 17 . Rbrace: 48
  19. 18 }

for range循环的语法树由ast.RangeStmt结构表示,其完整定义如下:

  1. type RangeStmt struct {
  2. For token.Pos // position of "for" keyword
  3. Key, Value Expr // Key, Value may be nil
  4. TokPos token.Pos // position of Tok; invalid if Key == nil
  5. Tok token.Token // ILLEGAL if Key == nil, ASSIGN, DEFINE
  6. X Expr // value to range over
  7. Body *BlockStmt
  8. }

其中Key和Value对应循环时的迭代位置和值,X成员是生成要循环对象的表达式(可能是数组、切片、map和管道等),Body表示循环体语句块。另外,Tok成员可以区别Key和Value是多赋值语句还是短变量声明语句。

类型断言

  1. func main() {
  2. x.(int)
  3. }

对x做类型断言,如果成功则返回x里面存储的int类型的值,如果失败则抛出异常。生成的语法树如下:

  1. 0 *ast.BlockStmt {
  2. 1 . Lbrace: 29
  3. 2 . List: []ast.Stmt (len = 1) {
  4. 3 . . 0: *ast.ExprStmt {
  5. 4 . . . X: *ast.TypeAssertExpr {
  6. 5 . . . . X: *ast.Ident {
  7. 6 . . . . . NamePos: 32
  8. 7 . . . . . Name: "x"
  9. 8 . . . . }
  10. 9 . . . . Lparen: 34
  11. 10 . . . . Type: *ast.Ident {
  12. 11 . . . . . NamePos: 35
  13. 12 . . . . . Name: "int"
  14. 13 . . . . }
  15. 14 . . . . Rparen: 38
  16. 15 . . . }
  17. 16 . . }
  18. 17 . }
  19. 18 . Rbrace: 40
  20. 19 }

需要注意语法树的结构:首先是ast.ExprStmt结构体表示的表达式语句,其中的X成员才是对应类型断言表达式。类型断言由ast.TypeAssertExpr结构体表示,其定义如下:

  1. type TypeAssertExpr struct {
  2. X Expr // expression
  3. Lparen token.Pos // position of "("
  4. Type Expr // asserted type; nil means type switch X.(type)
  5. Rparen token.Pos // position of ")"
  6. }

其中X成员是类型断言的主体表达式(产生一个接口值),Type成员是类型的表达式。如果Type为nil,则表示对应x.(type)形式的断言,否则是类型switch中使用的形式。

go和defer语句

go和defer语句在语法树中分别以ast.GoStmt和ast.DeferStmt结构定义:

  1. type GoStmt struct {
  2. Go token.Pos // position of "go" keyword
  3. Call *CallExpr
  4. }
  5. type DeferStmt struct {
  6. Defer token.Pos // position of "defer" keyword
  7. Call *CallExpr
  8. }
  1. func main() {
  2. go hello("光谷码农")
  3. }

其对应的语法树结果:

  1. 0 *ast.BlockStmt {
  2. 1 . Lbrace: 29
  3. 2 . List: []ast.Stmt (len = 1) {
  4. 3 . . 0: *ast.GoStmt {
  5. 4 . . . Go: 32
  6. 5 . . . Call: *ast.CallExpr {
  7. 6 . . . . Fun: *ast.Ident {
  8. 7 . . . . . NamePos: 35
  9. 8 . . . . . Name: "hello"
  10. 9 . . . . }
  11. 10 . . . . Lparen: 40
  12. 11 . . . . Args: []ast.Expr (len = 1) {
  13. 12 . . . . . 0: *ast.BasicLit {
  14. 13 . . . . . . ValuePos: 41
  15. 14 . . . . . . Kind: STRING
  16. 15 . . . . . . Value: "\"光谷码农\""
  17. 16 . . . . . }
  18. 17 . . . . }
  19. 18 . . . . Ellipsis: 0
  20. 19 . . . . Rparen: 55
  21. 20 . . . }
  22. 21 . . }
  23. 22 . }
  24. 23 . Rbrace: 57
  25. 24 }