《Go语言定制指南》-解析篇

目录

Go语言定制指南》:本站后置篇:《Go语言定制指南》-编译篇

一、词法单元

高级语言由许多基本元素构成,基本元素就是词法单元。词法单元构成表达式和语句;表达式和语句构成函数;函数构成源文件;源文件构成软件工程项目。

词法单元三个重要属性:类型、在源代码中的原始文本形式、出现的位置。(特殊的注释和分号可忽略)

1.1 词法单元简介

Go语言中的词法单元分为标识符(包括25个关键字)、运算符和分隔符等几类。

自定义标识符 25个关键字 47个运算符和分隔符 字面量 注释 空白符
1
2
identifier = letter { letter | unicode_digit } .
letter     = unicode_letter | "_" .

1.2 Token定义

1
type token int

源代码参考go/token包中的token.Token枚举表示,分为特殊类型、基础字面量、操作符和关键字大类。

类别 举例
特殊类型 错误ILLEGAL、EOF文件结束、注释COMMENT
基础字面量 IDENT、INT、FLOAT、IMAG、CHAR、STRING
操作符 ADD、SUB、MUL…
关键字 BREAK、CASE、CHAN、CONST…

各种大类之间有枚举值表示开始和结束,用于判断具体类型属于哪个大类,例如literal_begliteral_end之间的都属于字面量类型。

解读:

  • 基础字面量仅包含整数、浮点数、复数、符文和字符串,不包含true和false。
  • 运算符:算数运算符、逻辑运算符、位运算符和比较运算符、取址运算符、管道运算符等;分隔符:圆括号、花括号、方括号、逗号、圆点、分号和冒号。

1.3 FileSet和File

每个FileSet表示一个文件集合,底层抽象为一个一维数组,而Pos类型表示数组的下标位置。FileSet中的每个File元素对应底层数组的一个区间,不同的File之间没有交集,相邻的File之间可能存在填充空间。

File的组成

文件名 base size
文件名 对应File在FileSet中的Pos索引位置 文件大小

File内部通过offset定位下标索引,通过File.base+offset可以将内部的offset转换为FileSet的Pos位置。

1.4 解析Token

使用标准库的go/scanner.Scanner实现Token扫描,包含Init方法和Scan方法,Init指定目标文件、源码字节、错误处理和扫描模式;Scan方法逐个扫描得到具体位置、词法单元和原始字符串

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
type Scanner struct {
    ErrorCount int // number of errors encountered
}
func (s *Scanner) Init(
    file *token.File, src []byte,
    err ErrorHandler, mode Mode,
)
func (s *Scanner) Scan() (
    pos token.Pos, tok token.Token, lit string,
)

使用样例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main
import (
    "fmt"
    "go/scanner"
    "go/token"
)
func main() {
    var src = []byte(`println("你好,世界")`)
    var fset = token.NewFileSet()
    var file = fset.AddFile("hello.go", fset.Base(), len(src))
    var s scanner.Scanner
    s.Init(file, src, nil, scanner.ScanComments)
    for {
        pos, tok, lit := s.Scan()
        if tok == token.EOF {
            break
        }
        fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit)
    }
}
1
2
3
4
5
hello.go:1:1    IDENT   "println"
hello.go:1:8    (       ""
hello.go:1:9    STRING  "\"你好,世界\""
hello.go:1:26   )       ""
hello.go:1:27   ;       "\n"

1.5 Position位置信息

go/token.Position表示更详细的位置信息,fset.Position(pos)可获得对应位置的信息。

二、基础字面量

2.1 基础面值

2.1.1 定义

例如整数的定义(十进制、二进制、八进制和十六进制)

1
2
3
4
5
int_lit        = decimal_lit | binary_lit | octal_lit | hex_lit .
decimal_lit    = "0" | ( "1""9" ) [ [ "_" ] decimal_digits ] .
binary_lit     = "0" ( "b" | "B" ) [ "_" ] binary_digits .
octal_lit      = "0" [ "o" | "O" ] [ "_" ] octal_digits .
hex_lit        = "0" ( "x" | "X" ) [ "_" ] hex_digits .

完整定义参考基础面值定义

2.1.2 基础面值语法树结构

go/ast.BasicLit表示一个基础类型的面值常量结构,开始的字节偏移量、面值类型和原始代码字符串

1
2
3
4
5
type BasicLit struct {
    ValuePos token.Pos   // literal position
    Kind     token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
    Value    string      // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o`
}

2.1.3 手动构造面值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main
import (
    "go/ast"
    "go/token"
)
func main() {
    var lit9527 = &ast.BasicLit{
        Kind:  token.INT,
        Value: "9527",
    }
    ast.Print(nil, lit9527)
}

2.1.4 解析基础面值

使用go/parser.PaseExpr函数解析

1
2
3
4
func main() {
    expr, _ := parser.ParseExpr(`9527`)
    ast.Print(nil, expr)
}
1
2
3
4
5
0  *ast.BasicLit {
1  .  ValuePos: 1
2  .  Kind: STRING
3  .  Value: "\"9527\""
4  }

通过基础面值、指针、结构体、数组和map等其他语法解构的互相嵌套可以构造其他复杂类型。

2.2 标识符面值

2.2.1 结构

1
2
3
4
5
type Ident struct {
    NamePos token.Pos // identifier position
    Name    string    // identifier name
    Obj     *Object   // denoted object; or nil
}

2.2.2 手动构造

1
2
3
func main() {
    ast.Print(nil, ast.NewIdent(`x`))
}

2.2.3 解析标识符面值

1
2
3
func main() {
    ast.Print(nil, ast.NewIdent(`x`))
}
1
2
3
4
5
6
7
8
0  *ast.Ident {
1  .  NamePos: 1
2  .  Name: "x"
3  .  Obj: *ast.Object {
4  .  .  Kind: bad
5  .  .  Name: ""
6  .  }
7  }

ast.Object是一个相对复杂的结构,其中Kind用于描述标识符的类型,Bad表示未知的类型

三、基础表达式

基础表达式是指完全由数值型面值和标识符组成的表达式。

3.1 基础表达式语法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Expression = UnaryExpr | Expression binary_op Expression .
UnaryExpr  = Operand | unary_op UnaryExpr .
Operand    = Literal | identifier | "(" Expression ")" .

binary_op  = "||" | "&&" | rel_op | add_op | mul_op .
rel_op     = "==" | "!=" | "<" | "<=" | ">" | ">=" .
add_op     = "+" | "-" | "|" | "^" .
mul_op     = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" .

unary_op   = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .

其中Expression表示基础表达式的递归定义,可以是UnaryExpr类型的一元表达式,或者是binary_op生成的二元表达式。而基础表达式运算符两边的对象由Operand定义,主要是面值或表达式,也可以是由小括弧包含的表达式。

3.2 解析表达式

parser.ParseExpr函数解析返回ast.Expr抽象接口

1
2
3
4
5
6
7
8
type Expr interface {
    Node
    // contains filtered or unexported methods
}
type Node interface {
    Pos() token.Pos // position of first character belonging to the node
    End() token.Pos // position of first character immediately after the node
}

具体表达式类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ go doc go/ast | grep Expr
type BadExpr struct{ ... }
type BinaryExpr struct{ ... }
type CallExpr struct{ ... }
type Expr interface{ ... }
type ExprStmt struct{ ... }
type IndexExpr struct{ ... }
type KeyValueExpr struct{ ... }
type ParenExpr struct{ ... }
type SelectorExpr struct{ ... }
type SliceExpr struct{ ... }
type StarExpr struct{ ... }
type TypeAssertExpr struct{ ... }
type UnaryExpr struct{ ... }

解析代码实例

1
2
3
4
func main() {
    expr, _ := parser.ParseExpr(`1+2*3`)
    ast.Print(nil, expr)
}

其中ast.BinaryExpr表示二元表达式的节点,包含两个Expr类型的操作数(可递归)、以及Token类型的操作符

1
2
3
4
5
6
type BinaryExpr struct {
    X     Expr        // left operand
    OpPos token.Pos   // position of Op
    Op    token.Token // operator
    Y     Expr        // right operand
}

3.3 表达式求值

基础字面量ast.BasicLit是特殊的表达式,如果是二元表达式则根据操作符将操作数进行对应的求值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func main() {
    expr, _ := parser.ParseExpr(`1+2*3`)
    fmt.Println(Eval(expr))
}
func Eval(exp ast.Expr) float64 {
    switch exp := exp.(type) {
    case *ast.BinaryExpr:
        return EvalBinaryExpr(exp)
    case *ast.BasicLit:
        f, _ := strconv.ParseFloat(exp.Value, 64)
        return f
    }
    return 0
}
func EvalBinaryExpr(exp *ast.BinaryExpr) float64 {
    switch exp.Op {
    case token.ADD:
        return Eval(exp.X) + Eval(exp.Y)
    case token.MUL:
        return Eval(exp.X) * Eval(exp.Y)
    }
    return 0
}

3.4 带变量的表达式求值

标识符ast.Indent也是表达式,,在求值是带上一个上下文参数,从上下文中获取对应标识符的变量值,进行求值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func main() {
    expr, _ := parser.ParseExpr(`1+2*3+x`)
    fmt.Println(Eval(expr, map[string]float64{
        "x": 100,
    }))
}
func Eval(exp ast.Expr, vars map[string]float64) float64 {
    switch exp := exp.(type) {
    case *ast.BinaryExpr:
        return EvalBinaryExpr(exp, vars)
    case *ast.BasicLit:
        f, _ := strconv.ParseFloat(exp.Value, 64)
        return f
    case *ast.Ident:
        return vars[exp.Name]
    }
    return 0
}
func EvalBinaryExpr(exp *ast.BinaryExpr, vars map[string]float64) float64 {
    switch exp.Op {
    case token.ADD:
        return Eval(exp.X, vars) + Eval(exp.Y, vars)
    case token.MUL:
        return Eval(exp.X, vars) * Eval(exp.Y, vars)
    }
    return 0
}

四、代码结构

4.1 目录结构

parser.ParseDir解析目录内的全部Go语言文件,parser.ParseFile解析单个文件

_test为后缀会自动生成独立的测试包

4.2 文件结构

源文件由包定义、导入声明和顶级声明三个部分组成

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
SourceFile    = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .

PackageClause = "package" PackageName .
PackageName   = identifier .

ImportDecl    = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec    = [ "." | PackageName ] ImportPath .
ImportPath    = string_lit .

TopLevelDecl  = Declaration | FunctionDecl | MethodDecl .
Declaration   = ConstDecl | TypeDecl | VarDecl .

使用parser.ParseFile解析单个文件实例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "hello.go", src, parser.AllErrors)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("package:", f.Name)
    for _, s := range f.Imports {
        fmt.Println("import:", s.Path.Value)
    }
    for _, decl := range f.Decls {
        fmt.Printf("decl: %T\n", decl)
    }
}
const src = `package pkgname
import ("a"; "b")
type SomeType int
const PI = 3.14
var Length = 1
func main() {}
`

返回的类型为*ast.File类型,File.Imports属性对应导入信息,File.Decls属性对应声明;其中import、type、const和var都对应ast.GenDecl类型,函数是独立的ast.FuncDecl类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
type File struct {
    Doc        *CommentGroup   // associated documentation; or nil
    Package    token.Pos       // position of "package" keyword
    Name       *Ident          // package name
    Decls      []Decl          // top-level declarations; or nil
    Scope      *Scope          // package scope (this file only)
    Imports    []*ImportSpec   // imports in this file
    Unresolved []*Ident        // unresolved identifiers in this file
    Comments   []*CommentGroup // list of all comments in the source file
}

4.3 诊断语法树

go/ast包提供了ast.Print函数用于打印语法树,以及ast.Walk遍历语法树(或使用包装函数ast.Inspect遍历)。

4.4 总结

五、通用声明

5.1 导入声明

1
2
3
4
5
ImportDecl  = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec  = [ "." | PackageName ] ImportPath .
ImportPath  = string_lit .

PackageName = identifier .

解析实例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "hello.go", src, parser.ImportsOnly)
    if err != nil {
        log.Fatal(err)
    }

    for _, s := range f.Imports {
        fmt.Printf("import: name = %v, path = %#v\n", s.Name, s.Path)
    }
}
const src = `package foo
import "pkg-a"
import pkg_b_v2 "pkg-b"
import . "pkg-c"
import _ "pkg-d"
`

其中parser.ImportsOnly标识仅解析导入包的部分

1
2
3
4
import: name = <nil>, path = &ast.BasicLit{ValuePos:20, Kind:9, Value:"\"pkg-a\""}
import: name = pkg_b_v2, path = &ast.BasicLit{ValuePos:44, Kind:9, Value:"\"pkg-b\""}
import: name = ., path = &ast.BasicLit{ValuePos:61, Kind:9, Value:"\"pkg-c\""}
import: name = _, path = &ast.BasicLit{ValuePos:78, Kind:9, Value:"\"pkg-d\""}

5.2 基础类型声明

1
2
3
4
5
6
TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec = AliasDecl | TypeDef .

AliasDecl = identifier "=" Type .
TypeDef   = identifier Type .
Type      = identifier | "(" Type ")" .

解析实例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "hello.go", src, parser.AllErrors)
    if err != nil {
        log.Fatal(err)
    }
    ...
}
const src = `package foo
type MyInt1 int
type MyInt2 = int
`

返回的所有声明都在f.Decls列表中,基础声明对应的类型时*ast.GenDecl类型,其中可以通过GenDecl.Specs查看具体的节点元素的类型,例如*ast.TypeSpec

1
2
3
4
5
6
7
type TypeSpec struct {
    Doc     *CommentGroup // associated documentation; or nil
    Name    *Ident        // type name
    Assign  token.Pos     // position of '=', if any
    Type    Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
    Comment *CommentGroup // line comments; or nil
}

Name:新声明类型的名字或则已有类型的别名。Assign:对应=符号的位置,位置有效则标识已有类型的别名。Type:表示具体类型的表达式。

5.3 常量声明

1
2
3
4
5
ConstDecl      = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
ConstSpec      = IdentifierList [ [ Type ] "=" ExpressionList ] .

IdentifierList = identifier { "," identifier } .
ExpressionList = Expression { "," Expression } .

解析目标代码样例

1
2
const Pi = 3.14
const E float64 = 2.71828

ast.GenDecl.Specs类型为*ast.ValueSpec类型

1
2
3
4
5
6
7
type ValueSpec struct {
    Doc     *CommentGroup // associated documentation; or nil
    Names   []*Ident      // value names (len(Names) > 0)
    Type    Expr          // value type; or nil
    Values  []Expr        // initial values; or nil
    Comment *CommentGroup // line comments; or nil
}

因为Go支持多赋值表达式,所以Names和Values均为列表,Type用于区分常量是否指定了强类型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 0  *ast.ValueSpec {
 1  .  Names: []*ast.Ident (len = 1) {
 2  .  .  0: *ast.Ident {
 3  .  .  .  NamePos: 19
 4  .  .  .  Name: "Pi"
 5  .  .  .  Obj: *ast.Object {
 6  .  .  .  .  Kind: const
 7  .  .  .  .  Name: "Pi"
 8  .  .  .  .  Decl: *(obj @ 0)
 9  .  .  .  .  Data: 0
10  .  .  .  }
11  .  .  }
12  .  }
13  .  Values: []ast.Expr (len = 1) {
14  .  .  0: *ast.BasicLit {
15  .  .  .  ValuePos: 24
16  .  .  .  Kind: FLOAT
17  .  .  .  Value: "3.14"
18  .  .  }
19  .  }
20  }
 0  *ast.ValueSpec {
 1  .  Names: []*ast.Ident (len = 1) {
 2  .  .  0: *ast.Ident {
 3  .  .  .  NamePos: 35
 4  .  .  .  Name: "E"
 5  .  .  .  Obj: *ast.Object {
 6  .  .  .  .  Kind: const
 7  .  .  .  .  Name: "E"
 8  .  .  .  .  Decl: *(obj @ 0)
 9  .  .  .  .  Data: 0
10  .  .  .  }
11  .  .  }
12  .  }
13  .  Type: *ast.Ident {
14  .  .  NamePos: 37
15  .  .  Name: "float64"
16  .  }
17  .  Values: []ast.Expr (len = 1) {
18  .  .  0: *ast.BasicLit {
19  .  .  .  ValuePos: 47
20  .  .  .  Kind: FLOAT
21  .  .  .  Value: "2.71828"
22  .  .  }
23  .  }
24  }

5.4 变量声明

1
2
3
4
5
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
VarSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .

IdentifierList = identifier { "," identifier } .
ExpressionList = Expression { "," Expression } .

解析实例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "hello.go", src, parser.AllErrors)
    if err != nil {
        log.Fatal(err)
    }
    for _, decl := range f.Decls {
        if v, ok := decl.(*ast.GenDecl); ok {
            fmt.Printf("token: %v\n", v.Tok)
            for _, spec := range v.Specs {
                ast.Print(nil, spec)
            }
        }
    }
}
const src = `package foo
var Pi = 3.14
`
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
token: var
 0  *ast.ValueSpec {
 1  .  Names: []*ast.Ident (len = 1) {
 2  .  .  0: *ast.Ident {
 3  .  .  .  NamePos: 17
 4  .  .  .  Name: "Pi"
 5  .  .  .  Obj: *ast.Object {
 6  .  .  .  .  Kind: var
 7  .  .  .  .  Name: "Pi"
 8  .  .  .  .  Decl: *(obj @ 0)
 9  .  .  .  .  Data: 0
10  .  .  .  }
11  .  .  }
12  .  }
13  .  Values: []ast.Expr (len = 1) {
14  .  .  0: *ast.BasicLit {
15  .  .  .  ValuePos: 22
16  .  .  .  Kind: FLOAT
17  .  .  .  Value: "3.14"
18  .  .  }
19  .  }
20  }

5.5 按组声明

1
2
XxxDecl = "xxx" ( XxxSpec | "(" { XxxSpec ";" } ")" ) .
XxxSpec = ...

语法树的逻辑结构图

六、函数声明

6.1 函数的语法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
FunctionDecl = "func" MethodName Signature [ FunctionBody ] .
MethodDecl   = "func" Receiver MethodName Signature [ FunctionBody ] .

MethodName     = identifier .
Receiver       = Parameters .
Signature      = Parameters [ Result ] .
Result         = Parameters | Type .
Parameters     = "(" [ ParameterList [ "," ] ] ")" .
ParameterList  = ParameterDecl { "," ParameterDecl } .
ParameterDecl  = [ IdentifierList ] [ "..." ] Type .
  • Function函数定义:func字符串 函数名称 函数签名 可选的函数体
  • Method方法定义:func字符串 接受者 函数名称 函数签名 可选的函数体

6.2 函数

包一级的函数只有包函数和方法两种类型(闭包函数只能在函数体内部创建),而包函数可以看作是没有接收者的方法函数。

解析以下代码得到函数对应的声明类型*ast.FuncDecl

1
func (p *xType) Hello(arg1, arg2 int) (bool, error) { ... }
1
2
3
4
5
6
7
type FuncDecl struct {
    Doc  *CommentGroup // associated documentation; or nil
    Recv *FieldList    // receiver (methods); or nil (functions)
    Name *Ident        // function/method name
    Type *FuncType     // function signature: parameters, results, and position of "func" keyword
    Body *BlockStmt    // function body; or nil for external (non-Go) function
}

其中输入参数和返回值又被封装为ast.FuncType类型;对于没有接收者的包函数,ast.FuncDecl.Recv部分为nil。

6.3 参数分组

  • 接收者、输入和返回值参数均由ast.FieldList定义
  • FieldList其实时[]*Field结构的再次包装
  • Field可以表示一组相同类型的参数,例如func Hello1(s0, s1 string, s2 string)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
type FieldList struct {
    Opening token.Pos // position of opening parenthesis/brace, if any
    List    []*Field  // field list; or nil
    Closing token.Pos // position of closing parenthesis/brace, if any
}
type Field struct {
    Doc     *CommentGroup // associated documentation; or nil
    Names   []*Ident      // field/method/parameter names; or nil
    Type    Expr          // field/method/parameter type
    Tag     *BasicLit     // field tag; or nil
    Comment *CommentGroup // line comments; or nil
}

七、复合类型

复合类型包含其它包中的基础类型(需要通过点号选择操作符)、指针类型、 数组类型、切片类型、结构体类型、map类型、管道类型、函数类型和接口类型,以及它们之间再次组合产生的更复杂的类型。

7.1 类型语法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
TypeDecl  = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec  = AliasDecl | TypeDef .

AliasDecl = identifier "=" Type .
TypeDef   = identifier Type .

Type      = TypeName | TypeLit | "(" Type ")" .
TypeName  = identifier | PackageName "." identifier .
TypeLit   = PointerType | ArrayType | SliceType
          | StructType | MapType | ChannelType
          | FunctionType | InterfaceType
          .

TypeName表示当前包的类型标识符或则其他包的类型;TypeLit表示类型面值(比如已有类型的指针或则匿名结构体)

类型定义

1
2
3
4
5
6
7
type TypeSpec struct {
    Doc     *CommentGroup // associated documentation; or nil
    Name    *Ident        // type name
    Assign  token.Pos     // position of '=', if any; added in Go 1.9
    Type    Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of th *XxxTypes
    Comment *CommentGroup // line comments; or nil
}

Type通过特殊的类型表达式表示类型的定义;Assign被设置则表明时类型的别名

7.2 基础类型

1
2
3
4
5
6
7
TypeDecl  = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec  = AliasDecl | TypeDef .

AliasDecl = identifier "=" Type .
TypeDef   = identifier Type .

Type      = identifier | PackageName "." identifier .

对已有的类型的包装

1
2
type Int1 int
type Int2 pkg.Int

解析实例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "hello.go", src, parser.AllErrors)
    if err != nil {
        log.Fatal(err)
    }

    for _, decl := range f.Decls {
        ast.Print(nil, decl.(*ast.GenDecl).Specs[0])
    }
}
const src = `package foo
type Int1 int
type Int2 pkg.int
`
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 0  *ast.TypeSpec {
 1  .  Name: *ast.Ident {
 2  .  .  NamePos: 18
 3  .  .  Name: "Int1"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: type
 6  .  .  .  Name: "Int1"
 7  .  .  .  Decl: *(obj @ 0)
 8  .  .  }
 9  .  }
10  .  Assign: 0
11  .  Type: *ast.Ident {
12  .  .  NamePos: 23
13  .  .  Name: "int"
14  .  }
15  }
 0  *ast.TypeSpec {
 1  .  Name: *ast.Ident {
 2  .  .  NamePos: 32
 3  .  .  Name: "Int2"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: type
 6  .  .  .  Name: "Int2"
 7  .  .  .  Decl: *(obj @ 0)
 8  .  .  }
 9  .  }
10  .  Assign: 0
11  .  Type: *ast.SelectorExpr {
12  .  .  X: *ast.Ident {
13  .  .  .  NamePos: 37
14  .  .  .  Name: "pkg"
15  .  .  }
16  .  .  Sel: *ast.Ident {
17  .  .  .  NamePos: 41
18  .  .  .  Name: "int"
19  .  .  }
20  .  }
21  }

7.3 指针类型StarExpr

1
2
3
4
5
PointerType = "*" BaseType .
BaseType    = Type .

Type        = TypeName | TypeLit | "(" Type ")" .
...

解析实例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "hello.go", src, parser.AllErrors)
    if err != nil {
        log.Fatal(err)
    }

    for _, decl := range f.Decls {
        ast.Print(nil, decl.(*ast.GenDecl).Specs[0])
    }
}
const src = `package foo
type IntPtr *int
`
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 0  *ast.TypeSpec {
 1  .  Name: *ast.Ident {
 2  .  .  NamePos: 18
 3  .  .  Name: "IntPtr"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: type
 6  .  .  .  Name: "IntPtr"
 7  .  .  .  Decl: *(obj @ 0)
 8  .  .  }
 9  .  }
10  .  Assign: 0
11  .  Type: *ast.StarExpr {
12  .  .  Star: 25
13  .  .  X: *ast.Ident {
14  .  .  .  NamePos: 26
15  .  .  .  Name: "int"
16  .  .  }
17  .  }
18  }

新的类型*ast.StarExpr表示指针类型

1
2
3
4
type StarExpr struct {
    Star token.Pos // position of "*"
    X    Expr      // operand
}

多级指针

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
type IntPtrPtr **int

11  .  Type: *ast.StarExpr {
12  .  .  Star: 28
13  .  .  X: *ast.StarExpr {
14  .  .  .  Star: 29
15  .  .  .  X: *ast.Ident {
16  .  .  .  .  NamePos: 30
17  .  .  .  .  Name: "int"
18  .  .  .  }
19  .  .  }
20  .  }

7.4 数组类型ArrayType

1
2
3
ArrayType   = "[" ArrayLength "]" ElementType .
ArrayLength = Expression .
ElementType = Type .

解析实例

1
type IntArray [1]int
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 0  *ast.TypeSpec {
 1  .  Name: *ast.Ident {
 2  .  .  NamePos: 18
 3  .  .  Name: "IntArray"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: type
 6  .  .  .  Name: "IntArray"
 7  .  .  .  Decl: *(obj @ 0)
 8  .  .  }
 9  .  }
10  .  Assign: 0
11  .  Type: *ast.ArrayType {
12  .  .  Lbrack: 27
13  .  .  Len: *ast.BasicLit {
14  .  .  .  ValuePos: 28
15  .  .  .  Kind: INT
16  .  .  .  Value: "1"
17  .  .  }
18  .  .  Elt: *ast.Ident {
19  .  .  .  NamePos: 30
20  .  .  .  Name: "int"
21  .  .  }
22  .  }
23  }

数据类型对应的类型为*ast.ArrayType

1
2
3
4
5
type ArrayType struct {
    Lbrack token.Pos // position of "["
    Len    Expr      // Ellipsis node for [...]T array types, nil for slice types
    Elt    Expr      // element type
}

Len:数组长度表达式;Elt:元素类型表达式

多重数组

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
11  .  Type: *ast.ArrayType {
12  .  .  Lbrack: 32
13  .  .  Len: *ast.BasicLit {
14  .  .  .  ValuePos: 33
15  .  .  .  Kind: INT
16  .  .  .  Value: "1"
17  .  .  }
18  .  .  Elt: *ast.ArrayType {
19  .  .  .  Lbrack: 35
20  .  .  .  Len: *ast.BasicLit {
21  .  .  .  .  ValuePos: 36
22  .  .  .  .  Kind: INT
23  .  .  .  .  Value: "2"
24  .  .  .  }
25  .  .  .  Elt: *ast.Ident {
26  .  .  .  .  NamePos: 38
27  .  .  .  .  Name: "int"
28  .  .  .  }
29  .  .  }
30  .  }

7.5 切片类型ArrayType

切片和数组的差异就是省略了数组的长度而已。

1
2
SliceType   = "[" "]" ElementType .
ElementType = Type .
1
type IntSlice []int
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 0  *ast.TypeSpec {
 1  .  Name: *ast.Ident {
 2  .  .  NamePos: 18
 3  .  .  Name: "IntSlice"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: type
 6  .  .  .  Name: "IntSlice"
 7  .  .  .  Decl: *(obj @ 0)
 8  .  .  }
 9  .  }
10  .  Assign: 0
11  .  Type: *ast.ArrayType {
12  .  .  Lbrack: 27
13  .  .  Elt: *ast.Ident {
14  .  .  .  NamePos: 29
15  .  .  .  Name: "int"
16  .  .  }
17  .  }
18  } 

*ast.ArrayType可以表示数组和切片,通过Len长度成员是否为nil判断

7.6 结构体类型StructType

1
2
3
4
5
6
7
StructType     = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl      = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField  = [ "*" ] TypeName .
Tag            = string_lit .

IdentifierList = identifier { "," identifier } .
TypeName       = identifier | PackageName "." identifier .

解析实例

1
2
3
4
type MyStruct struct {
    a, b int "int value"
    string
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
11  .  Type: *ast.StructType {
12  .  .  Struct: 27
13  .  .  Fields: *ast.FieldList {
14  .  .  .  Opening: 34
15  .  .  .  List: []*ast.Field (len = 2) {
16  .  .  .  .  0: *ast.Field {
17  .  .  .  .  .  Names: []*ast.Ident (len = 2) {
18  .  .  .  .  .  .  0: *ast.Ident {
19  .  .  .  .  .  .  .  NamePos: 37
20  .  .  .  .  .  .  .  Name: "a"
21  .  .  .  .  .  .  .  Obj: *ast.Object {...}
26  .  .  .  .  .  .  }
27  .  .  .  .  .  .  1: *ast.Ident {
28  .  .  .  .  .  .  .  NamePos: 40
29  .  .  .  .  .  .  .  Name: "b"
30  .  .  .  .  .  .  .  Obj: *ast.Object {...}
35  .  .  .  .  .  .  }
36  .  .  .  .  .  }
37  .  .  .  .  .  Type: *ast.Ident {
38  .  .  .  .  .  .  NamePos: 42
39  .  .  .  .  .  .  Name: "int"
40  .  .  .  .  .  }
41  .  .  .  .  .  Tag: *ast.BasicLit {
42  .  .  .  .  .  .  ValuePos: 46
43  .  .  .  .  .  .  Kind: STRING
44  .  .  .  .  .  .  Value: "\"int value\""
45  .  .  .  .  .  }
46  .  .  .  .  }
47  .  .  .  .  1: *ast.Field {
48  .  .  .  .  .  Type: *ast.Ident {
49  .  .  .  .  .  .  NamePos: 59
50  .  .  .  .  .  .  Name: "string"
51  .  .  .  .  .  }
52  .  .  .  .  }
53  .  .  .  }
54  .  .  .  Closing: 66
55  .  .  }
56  .  .  Incomplete: false
57  .  }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
type StructType struct {
    Struct     token.Pos  // position of "struct" keyword
    Fields     *FieldList // list of field declarations
    Incomplete bool       // true if (source) fields are missing in the Fields list
}
type FieldList struct {
    Opening token.Pos // position of opening parenthesis/brace, if any
    List    []*Field  // field list; or nil
    Closing token.Pos // position of closing parenthesis/brace, if any
}
type Field struct {
    Doc     *CommentGroup // associated documentation; or nil
    Names   []*Ident      // field/method/parameter names; or nil
    Type    Expr          // field/method/parameter type
    Tag     *BasicLit     // field tag; or nil
    Comment *CommentGroup // line comments; or nil
}

ast.Field不仅可以表示结构体成员,也可以表示结构方法列表、函数或方法的各种参数列表

7.7 Map类型MapType

1
2
MapType = "map" "[" KeyType "]" ElementType .
KeyType = Type .

解析实例

1
type IntStringMap map[int]string
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
11  .  Type: *ast.MapType {
12  .  .  Map: 31
13  .  .  Key: *ast.Ident {
14  .  .  .  NamePos: 35
15  .  .  .  Name: "int"
16  .  .  }
17  .  .  Value: *ast.Ident {
18  .  .  .  NamePos: 39
19  .  .  .  Name: "string"
20  .  .  }
21  .  }
1
2
3
4
5
type MapType struct {
    Map   token.Pos // position of "map" keyword
    Key   Expr
    Value Expr
}

其中Key和Value部分都是类型表达式,可以是其它更复杂的组合类型。

7.8 管道类型ChanType

1
ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
type ChanType struct {
    Begin token.Pos // position of "chan" keyword or "<-" (whichever comes first)
    Arrow token.Pos // position of "<-" (token.NoPos if there is no "<-"); added in Go 1.1
    Dir   ChanDir   // channel direction
    Value Expr      // value type
}
type ChanDir int
const (
    SEND ChanDir = 1 << iota
    RECV
)

ast.ChanType.Dir是管道的方向,SEND表示发送、RECV表示接收、SEND|RECV比特位组合表示双向管道。

解析实例

1
type IntChan chan int
1
2
3
4
5
6
7
8
9
11  .  Type: *ast.ChanType {
12  .  .  Begin: 26
13  .  .  Arrow: 0
14  .  .  Dir: 3
15  .  .  Value: *ast.Ident {
16  .  .  .  NamePos: 31
17  .  .  .  Name: "int"
18  .  .  }
19  .  }

7.9 函数类型FuncType

1
2
3
4
5
6
FunctionType   = "func" Signature .
Signature      = Parameters [ Result ] .
Result         = Parameters | Type .
Parameters     = "(" [ ParameterList [ "," ] ] ")" .
ParameterList  = ParameterDecl { "," ParameterDecl } .
ParameterDecl  = [ IdentifierList ] [ "..." ] Type .
1
type FuncType func(a, b int) bool

7.10 接口类型InterfaceType

1
2
3
4
5
6
7
InterfaceType      = "interface" "{" { MethodSpec ";" } "}" .
MethodSpec         = MethodName Signature | InterfaceTypeName .
MethodName         = identifier .
InterfaceTypeName  = TypeName .

Signature          = Parameters [ Result ] .
Result             = Parameters | Type .

解析实例

1
2
3
type IntReader interface {
    Read() int
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
11  .  Type: *ast.InterfaceType {
12  .  .  Interface: 28
13  .  .  Methods: *ast.FieldList {
14  .  .  .  Opening: 38
15  .  .  .  List: []*ast.Field (len = 1) {
16  .  .  .  .  0: *ast.Field {
17  .  .  .  .  .  Names: []*ast.Ident (len = 1) {
18  .  .  .  .  .  .  0: *ast.Ident {
19  .  .  .  .  .  .  .  NamePos: 41
20  .  .  .  .  .  .  .  Name: "Read"
21  .  .  .  .  .  .  .  Obj: *ast.Object {
22  .  .  .  .  .  .  .  .  Kind: func
23  .  .  .  .  .  .  .  .  Name: "Read"
24  .  .  .  .  .  .  .  .  Decl: *(obj @ 16)
25  .  .  .  .  .  .  .  }
26  .  .  .  .  .  .  }
27  .  .  .  .  .  }
28  .  .  .  .  .  Type: *ast.FuncType {
29  .  .  .  .  .  .  Func: 0
30  .  .  .  .  .  .  Params: *ast.FieldList {
31  .  .  .  .  .  .  .  Opening: 45
32  .  .  .  .  .  .  .  Closing: 46
33  .  .  .  .  .  .  }
34  .  .  .  .  .  .  Results: *ast.FieldList {
35  .  .  .  .  .  .  .  Opening: 0
36  .  .  .  .  .  .  .  List: []*ast.Field (len = 1) {
37  .  .  .  .  .  .  .  .  0: *ast.Field {
38  .  .  .  .  .  .  .  .  .  Type: *ast.Ident {
39  .  .  .  .  .  .  .  .  .  .  NamePos: 48
40  .  .  .  .  .  .  .  .  .  .  Name: "int"
41  .  .  .  .  .  .  .  .  .  }
42  .  .  .  .  .  .  .  .  }
43  .  .  .  .  .  .  .  }
44  .  .  .  .  .  .  .  Closing: 0
45  .  .  .  .  .  .  }
46  .  .  .  .  .  }
47  .  .  .  .  }
48  .  .  .  }
49  .  .  .  Closing: 52
50  .  .  }
51  .  .  Incomplete: false
52  .  }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
type InterfaceType struct {
    Interface  token.Pos  // position of "interface" keyword
    Methods    *FieldList // list of methods
    Incomplete bool       // true if (source) methods are missing in the Methods list
}
type StructType struct {
    Struct     token.Pos  // position of "struct" keyword
    Fields     *FieldList // list of field declarations
    Incomplete bool       // true if (source) fields are missing in the Fields list
}

7.11 组合类型

通过不同组合生成更复杂的类型

八、复合面值

非基础面值包含函数面值和复合类型面值。

8.1 面值语法

完整面值由Literal定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Literal       = BasicLit | CompositeLit | FunctionLit .

BasicLit      = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .

CompositeLit  = LiteralType LiteralValue .
LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
                SliceType | MapType | TypeName .
LiteralValue  = "{" [ ElementList [ "," ] ] "}" .
ElementList   = KeyedElement { "," KeyedElement } .
KeyedElement  = [ Key ":" ] Element .
Key           = FieldName | Expression | LiteralValue .
FieldName     = identifier .
Element       = Expression | LiteralValue .

其中BasicLit是基础面值,CompositeLit是复合面值,FunctionLit是函数面值

8.2 函数面值FunctionLit

1
FunctionLit   = "func" Signature FunctionBody .

解析实例

1
2
3
4
func main() {
    expr, _ := parser.ParseExpr(`func(){}`)
    ast.Print(nil, expr)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
 0  *ast.FuncLit {
 1  .  Type: *ast.FuncType {
 2  .  .  Func: 1
 3  .  .  Params: *ast.FieldList {
 4  .  .  .  Opening: 5
 5  .  .  .  Closing: 6
 6  .  .  }
 7  .  }
 8  .  Body: *ast.BlockStmt {
 9  .  .  Lbrace: 7
10  .  .  Rbrace: 8
11  .  }
12  }

函数面值由*ast.FunctionLit结构体表示,其中Type成员表示类型,Body表示函数体

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
type FuncLit struct {
    Type *FuncType  // function type
    Body *BlockStmt // function body
}
type FuncDecl struct {
    Doc  *CommentGroup // associated documentation; or nil
    Recv *FieldList    // receiver (methods); or nil (functions)
    Name *Ident        // function/method name
    Type *FuncType     // function signature: parameters, results, and position of "func" keyword
    Body *BlockStmt    // function body; or nil for external (non-Go) function
}

8.3 复合类型面值CompositeLit

复合类型主要包含结构体、数组、切片和map类型

1
2
3
4
5
6
7
8
9
CompositeLit  = LiteralType LiteralValue .
LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
                SliceType | MapType | TypeName .
LiteralValue  = "{" [ ElementList [ "," ] ] "}" .
ElementList   = KeyedElement { "," KeyedElement } .
KeyedElement  = [ Key ":" ] Element .
Key           = FieldName | Expression | LiteralValue .
FieldName     = identifier .
Element       = Expression | LiteralValue .
1
2
3
4
5
6
7
[1]int{1}
[...]int{100:1,200:2}
[]int{1,2,3}
[]int{100:1,200:2}
struct {X int}{1}
struct {X int}{X:1}
map[int]int{1:1, 2:2}
1
2
3
4
5
6
7
type CompositeLit struct {
    Type       Expr      // literal type; or nil
    Lbrace     token.Pos // position of "{"
    Elts       []Expr    // list of composite elements; or nil
    Rbrace     token.Pos // position of "}"
    Incomplete bool      // true if (source) expressions are missing in the Elts list
}

ast.CompositeLit.Type对应复合类型的表达式,ast.CompositeLit.Elts是复合类型初始元素列表。

8.3.1 数组和切片面值ArrayType

Type为ArrayType的CompositeLit

1
2
3
4
func main() {
    expr, _ := parser.ParseExpr(`[...]int{1,2:3}`)
    ast.Print(nil, expr)
}

复合面值语法树由ast.CompositeLit结构体表示,其中ast.CompositeLit.Type成员为ast.ArrayType表示这是数组或切片类型(如果没有长度信息则为切片类型,否则就是数组),而ast.CompositeLitElts成员则是元素的值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 0  *ast.CompositeLit {
 1  .  Type: *ast.ArrayType {
 2  .  .  Lbrack: 1
 3  .  .  Len: *ast.Ellipsis {
 4  .  .  .  Ellipsis: 2
 5  .  .  }
 6  .  .  Elt: *ast.Ident {
 7  .  .  .  NamePos: 6
 8  .  .  .  Name: "int"
 9  .  .  .  Obj: *ast.Object {
10  .  .  .  .  Kind: bad
11  .  .  .  .  Name: ""
12  .  .  .  }
13  .  .  }
14  .  }
15  .  Lbrace: 9
16  .  Elts: []ast.Expr (len = 2) {
17  .  .  0: *ast.BasicLit {
18  .  .  .  ValuePos: 10
19  .  .  .  Kind: INT
20  .  .  .  Value: "1"
21  .  .  }
22  .  .  1: *ast.KeyValueExpr {
23  .  .  .  Key: *ast.BasicLit {
24  .  .  .  .  ValuePos: 12
25  .  .  .  .  Kind: INT
26  .  .  .  .  Value: "2"
27  .  .  .  }
28  .  .  .  Colon: 13
29  .  .  .  Value: *ast.BasicLit {
30  .  .  .  .  ValuePos: 14
31  .  .  .  .  Kind: INT
32  .  .  .  .  Value: "3"
33  .  .  .  }
34  .  .  }
35  .  }
36  .  Rbrace: 15
37  .  Incomplete: false
38  }

8.3.2 结构体面值StructType

Type为StructType的CompositeLit

1
2
3
4
func main() {
    expr, _ := parser.ParseExpr(`struct{X int}{X:1}`)
    ast.Print(nil, expr)
}

结构体面值依然是通过ast.CompositeLit结构体描述。结构体中成员的初始化通过ast.KeyValueExpr结构体初始化,Key部分为X表示成员名字,Value部分为X成员的初始值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
 0 *ast.CompositeLit {
 1  .  Type: *ast.StructType {...}
32  .  Lbrace: 14
33  .  Elts: []ast.Expr (len = 1) {
34  .  .  0: *ast.KeyValueExpr {
35  .  .  .  Key: *ast.Ident {
36  .  .  .  .  NamePos: 15
37  .  .  .  .  Name: "X"
38  .  .  .  }
39  .  .  .  Colon: 16
40  .  .  .  Value: *ast.BasicLit {
41  .  .  .  .  ValuePos: 17
42  .  .  .  .  Kind: INT
43  .  .  .  .  Value: "1"
44  .  .  .  }
45  .  .  }
46  .  }
47  .  Rbrace: 18
48  .  Incomplete: false
49  }

8.3.3 map面值MapType

Type为MapType的CompositeLit

1
2
3
4
func main() {
    expr, _ := parser.ParseExpr(`map[int]int{1:2}`)
    ast.Print(nil, expr)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
18  .  Elts: []ast.Expr (len = 1) {
19  .  .  0: *ast.KeyValueExpr {
20  .  .  .  Key: *ast.BasicLit {
21  .  .  .  .  ValuePos: 13
22  .  .  .  .  Kind: INT
23  .  .  .  .  Value: "1"
24  .  .  .  }
25  .  .  .  Colon: 14
26  .  .  .  Value: *ast.BasicLit {
27  .  .  .  .  ValuePos: 15
28  .  .  .  .  Kind: INT
29  .  .  .  .  Value: "2"
30  .  .  .  }
31  .  .  }
32  .  }

九、复合表达式

9.1 表达式语法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
PrimaryExpr = Operand
            | Conversion
            | MethodExpr
            | PrimaryExpr Selector
            | PrimaryExpr Index
            | PrimaryExpr Slice
            | PrimaryExpr TypeAssertion
            | PrimaryExpr Arguments
            .

Selector       = "." identifier .
Index          = "[" Expression "]" .
Slice          = "[" [ Expression ] ":" [ Expression ] "]" 
               | "[" [ Expression ] ":" Expression ":" Expression "]" .

TypeAssertion  = "." "(" Type ")" .
Arguments      = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .

9.2 转型和函数调用CallExpr

1
2
Conversion = Type "(" Expression [ "," ] ")" .
Arguments  = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .

转型操作和一个参数的函数相似,但以一个类型开始,例如int(x)将x转换为int类型

1
2
3
4
func main() {
    expr, _ := parser.ParseExpr(`int(x)`)
    ast.Print(nil, expr)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
 0  *ast.CallExpr {
 1  .  Fun: *ast.Ident {
 2  .  .  NamePos: 1
 3  .  .  Name: "int"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: bad
 6  .  .  .  Name: ""
 7  .  .  }
 8  .  }
 9  .  Lparen: 4
10  .  Args: []ast.Expr (len = 1) {
11  .  .  0: *ast.Ident {
12  .  .  .  NamePos: 5
13  .  .  .  Name: "x"
14  .  .  .  Obj: *(obj @ 4)
15  .  .  }
16  .  }
17  .  Ellipsis: 0
18  .  Rparen: 6
19  }

转型和函数调用均使用ast.CallExpr表示,如果Fun是类型表达式则表示一个转型操作

1
2
3
4
5
6
7
type CallExpr struct {
    Fun      Expr      // function expression
    Lparen   token.Pos // position of "("
    Args     []Expr    // function arguments; or nil
    Ellipsis token.Pos // position of "..." (token.NoPos if there is no "...")
    Rparen   token.Pos // position of ")"
}

9.3 点选择运算SelectorExpr

1
2
PrimaryExpr = PrimaryExpr Selector .
Selector    = "." identifier .

如果有表达式x,则可以通过x.y访问其成员或方法函数。如果是x导入包,那么x.y将变成标识符含义。在语法树解析阶段并无法区分一个选择表达式和导入包中的标识符。

x.y解析的语法树结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 0  *ast.SelectorExpr {
 1  .  X: *ast.Ident {
 2  .  .  NamePos: 1
 3  .  .  Name: "x"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: bad
 6  .  .  .  Name: ""
 7  .  .  }
 8  .  }
 9  .  Sel: *ast.Ident {
10  .  .  NamePos: 3
11  .  .  Name: "y"
12  .  }
13  }

使用ast.SelectorExpr表示点选择运算表达式

1
2
3
4
type SelectorExpr struct {
    X   Expr   // expression
    Sel *Ident // field selector
}

9.4 索引运算IndexExpr

1
2
PrimaryExpr = PrimaryExpr Index .
Index       = "[" Expression "]" .

x[y]解析的语法树结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 0  *ast.IndexExpr {
 1  .  X: *ast.Ident {
 2  .  .  NamePos: 1
 3  .  .  Name: "x"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: bad
 6  .  .  .  Name: ""
 7  .  .  }
 8  .  }
 9  .  Lbrack: 2
10  .  Index: *ast.Ident {
11  .  .  NamePos: 3
12  .  .  Name: "y"
13  .  .  Obj: *(obj @ 4)
14  .  }
15  .  Rbrack: 4
16  }

使用ast.IndexExpr表示索引运算表达式

1
2
3
4
5
6
type IndexExpr struct {
    X      Expr      // expression
    Lbrack token.Pos // position of "["
    Index  Expr      // index expression
    Rbrack token.Pos // position of "]"
}

其中X和Index成员都是表达式,具体的语义需要根据上下文判断X表达式的类型才能决定Index索引表达式的类型。

9.5 切片运算SliceExpr

切片运算是在数组或切片基础上生成新的切片,切片运算主要包含开始索引、结束索引和最大范围三个部分。

1
2
3
4
PrimaryExpr =  PrimaryExpr Slice
Slice       = "[" [ Expression ] ":" [ Expression ] "]" 
            | "[" [ Expression ] ":" Expression ":" Expression "]"
            .

x[1:2:3]切片运算的语法树

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 0  *ast.SliceExpr {
 1  .  X: *ast.Ident {
 2  .  .  NamePos: 1
 3  .  .  Name: "x"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: bad
 6  .  .  .  Name: ""
 7  .  .  }
 8  .  }
 9  .  Lbrack: 2
10  .  Low: *ast.BasicLit {
11  .  .  ValuePos: 3
12  .  .  Kind: INT
13  .  .  Value: "1"
14  .  }
15  .  High: *ast.BasicLit {
16  .  .  ValuePos: 5
17  .  .  Kind: INT
18  .  .  Value: "2"
19  .  }
20  .  Max: *ast.BasicLit {
21  .  .  ValuePos: 7
22  .  .  Kind: INT
23  .  .  Value: "3"
24  .  }
25  .  Slice3: true
26  .  Rbrack: 8
27  }
1
2
3
4
5
6
7
8
9
type SliceExpr struct {
    X      Expr      // expression
    Lbrack token.Pos // position of "["
    Low    Expr      // begin of slice range; or nil
    High   Expr      // end of slice range; or nil
    Max    Expr      // maximum capacity of slice; or nil
    Slice3 bool      // true if 3-index slice (2 colons present)
    Rbrack token.Pos // position of "]"
}

其中X、Low、High、Max分别表示切片运算的主体、开始索引、结束索引和最大范围。

9.6 类型断言TypeAssertExpr

类型断言是判断一个接口对象是否满足另一个接口、或者接口持有的对象是否是一个确定的非接口类型。

1
2
PrimaryExpr    = PrimaryExpr TypeAssertion .
TypeAssertion  = "." "(" Type ")" .

x.(y)就是将x接口断言为y接口或y类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 0  *ast.TypeAssertExpr {
 1  .  X: *ast.Ident {
 2  .  .  NamePos: 1
 3  .  .  Name: "x"
 4  .  .  Obj: *ast.Object {
 5  .  .  .  Kind: bad
 6  .  .  .  Name: ""
 7  .  .  }
 8  .  }
 9  .  Lparen: 3
10  .  Type: *ast.Ident {
11  .  .  NamePos: 4
12  .  .  Name: "y"
13  .  .  Obj: *(obj @ 4)
14  .  }
15  .  Rparen: 5
16  }

使用ast.TypeAssertExpr表示断言运算表达式

1
2
3
4
5
6
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 ")"
}

十、语句块和语句

10.1 语句规范

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
FunctionBody  = Block .

Block         = "{" StatementList "}" .
StatementList = { Statement ";" } .

Statement     = Declaration | LabeledStmt | SimpleStmt
              | GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt
              | FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt
              | DeferStmt
              .
  • FunctionBody函数体对应一个Block语句块。每个Block语句块内部由多个语句列表StatementList组成,每个语句之间通过分号分割。
  • 语句又分为声明语句、标签语句、普通表达式语句和其他诸多控制流语句。

10.2 空语句块Stmt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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() {}
`
1
2
3
4
0  *ast.BlockStmt {
1  .  Lbrace: 29
2  .  Rbrace: 30
3  }

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

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

10.3 表达式语句ExprStmt

1
ExpressionStmt = Expression .
1
2
3
func main() {
    42
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
chai-mba:02 chai$ go run main.go 
 0  *ast.BlockStmt {
 1  .  Lbrace: 29
 2  .  List: []ast.Stmt (len = 1) {
 3  .  .  0: *ast.ExprStmt {
 4  .  .  .  X: *ast.BasicLit {
 5  .  .  .  .  ValuePos: 32
 6  .  .  .  .  Kind: INT
 7  .  .  .  .  Value: "42"
 8  .  .  .  }
 9  .  .  }
10  .  }
11  .  Rbrace: 35
12  }

使用ExprStmt表示表达式语句

1
2
3
type ExprStmt struct {
    X Expr // expression
}

10.4 返回语句ReturnStmt

1
2
ReturnStmt     = "return" [ ExpressionList ] .
ExpressionList = Expression { "," Expression } .
1
2
3
func main() {
    return 42, err
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
 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表示返回语句表达式

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

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

10.5 声明语句DeclStmt

1
2
Declaration  = ConstDecl | TypeDecl | VarDecl .
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
1
2
3
func main() {
    var a int
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 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表示声明语句表达式

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

10.6 短声明和多赋值语句AssignStmt

短声明语法和多赋值语句类似,它是在声明变量的同时进行多赋值初始化,变量类型从赋值表达式自动推导。

1
2
Assignment   = ExpressionList assign_op ExpressionList .
ShortVarDecl = IdentifierList ":=" ExpressionList .
1
2
3
func main() {
    a, b := 1, 2
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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表示短声明和多赋值语句表达式

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

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

10.7 if/else分支语句IfStmt

1
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
1
2
3
func main() {
    if true {} else {}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
 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  }

使用ast.IfStmt表示if/else语句表达式

1
2
3
4
5
6
7
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
}

其中的Cond为分支的条件表达式,Body为分支的主体语句块,Else为补充的语句块。

10.8 for循环ForStmt

1
2
3
4
5
6
7
8
9
ForStmt     = "for" [ Condition | ForClause | RangeClause ] Block .

Condition   = Expression .

ForClause   = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
InitStmt    = SimpleStmt .
PostStmt    = SimpleStmt .

RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .

四种支持的语法规范

1
2
3
4
for {}
for true {}
for i := 0; true; i++ {}
for i, v := range m {}
1
2
3
func main() {
    for x; y; z {}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 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-condition循环表达式

1
2
3
4
5
6
7
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
}

其中条件部分必须是表达式,初始化和迭代部分可以是普通的语句(普通语句是短声明和多赋值等,不能包含分支等复杂语句)

1
2
3
func main() {
    for range ch {}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 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  }

使用ast.RangeStmt表示for-range循环表达式

1
2
3
4
5
6
7
8
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表示循环体语句块。

10.9 类型断言TypeAssertExpr

1
2
PrimaryExpr     = PrimaryExpr TypeAssertion.
TypeAssertion   = "." "(" Type ")" .
1
2
3
func main() {
    x.(int)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
 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.TypeAssertExpr表示类型断言语句表达式

1
2
3
4
5
6
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成员是类型的表达式。

10.10 go和defer语句GoStmt/DeferStmt

1
2
3
4
5
6
7
8
type GoStmt struct {
    Go   token.Pos // position of "go" keyword
    Call *CallExpr
}
type DeferStmt struct {
    Defer token.Pos // position of "defer" keyword
    Call  *CallExpr
}
1
2
3
func main() {
    go hello("光谷码农")
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 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  }
0%