GoのAST全部見る

この記事は Treasure Advent Calendar 2018 - Qiita 16日目の記事です.

クリスマスにちなんで,プログラマ御用達の大木 Abstract Syntax Treeを眺めようと思います.

うまれたてのGopherなので, 間違ってたら優しく教えてください~~

go.astパッケージ

GoはGo自身をParseしてASTに変換するgo.astパッケージを搭載していて, お手軽にASTを眺めることができます.

例えば以下のコードのParse()関数に

package parser

import (
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
)

func Parse(filename string) error {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, filename, nil, parser.Mode(0))

    if err != nil {
        return err
    }

    for _, d := range f.Decls {
        ast.Print(fset, d)
        fmt.Println() // \n したい...
    }
    return nil
}

以下の簡単なGoプログラムを渡すと

package main

func MerryXMas() {
    var hoge = 2
}

それらしいASTが出力されます.

     0  *ast.FuncDecl {
     1  .  Name: *ast.Ident {
     2  .  .  NamePos: example/example.go:3:6
     3  .  .  Name: "MerryXMas"
     4  .  .  Obj: *ast.Object {
     5  .  .  .  Kind: func
     6  .  .  .  Name: "MerryXMas"
     7  .  .  .  Decl: *(obj @ 0)
     8  .  .  }
     9  .  }
    10  .  Type: *ast.FuncType {
    11  .  .  Func: example/example.go:3:1
    12  .  .  Params: *ast.FieldList {
    13  .  .  .  Opening: example/example.go:3:15
    14  .  .  .  Closing: example/example.go:3:16
    15  .  .  }
    16  .  }
    17  .  Body: *ast.BlockStmt {
    18  .  .  Lbrace: example/example.go:3:18
    19  .  .  List: []ast.Stmt (len = 1) {
    20  .  .  .  0: *ast.DeclStmt {
    21  .  .  .  .  Decl: *ast.GenDecl {
    22  .  .  .  .  .  TokPos: example/example.go:4:2
    23  .  .  .  .  .  Tok: var
    24  .  .  .  .  .  Lparen: -
    25  .  .  .  .  .  Specs: []ast.Spec (len = 1) {
    26  .  .  .  .  .  .  0: *ast.ValueSpec {
    27  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {
    28  .  .  .  .  .  .  .  .  0: *ast.Ident {
    29  .  .  .  .  .  .  .  .  .  NamePos: example/example.go:4:6
    30  .  .  .  .  .  .  .  .  .  Name: "hoge"
    31  .  .  .  .  .  .  .  .  .  Obj: *ast.Object {
    32  .  .  .  .  .  .  .  .  .  .  Kind: var
    33  .  .  .  .  .  .  .  .  .  .  Name: "hoge"
    34  .  .  .  .  .  .  .  .  .  .  Decl: *(obj @ 26)
    35  .  .  .  .  .  .  .  .  .  .  Data: 0
    36  .  .  .  .  .  .  .  .  .  }
    37  .  .  .  .  .  .  .  .  }
    38  .  .  .  .  .  .  .  }
    39  .  .  .  .  .  .  .  Values: []ast.Expr (len = 1) {
    40  .  .  .  .  .  .  .  .  0: *ast.BasicLit {
    41  .  .  .  .  .  .  .  .  .  ValuePos: example/example.go:4:13
    42  .  .  .  .  .  .  .  .  .  Kind: INT
    43  .  .  .  .  .  .  .  .  .  Value: "2"
    44  .  .  .  .  .  .  .  .  }
    45  .  .  .  .  .  .  .  }
    46  .  .  .  .  .  .  }
    47  .  .  .  .  .  }
    48  .  .  .  .  .  Rparen: -
    49  .  .  .  .  }
    50  .  .  .  }
    51  .  .  }
    52  .  .  Rbrace: example/example.go:5:1
    53  .  }
    54  }

ASTを眺めていると分かる通り, go.astパッケージはたくさんの構造体でASTを表現しています.今回は,go.astパッケージで実装されている構造体を可能な限り見ていきたいと思います.

構造体の種類

構造体は大きく6種類に分類できます(主観).

  • Declaration : 関数/変数の宣言の外枠
  • Spec : 関数/変数宣言の詳細(Spec)
  • Type : 型情報
  • Statement : ブロックや式情報
  • Literal : 関数リテラル(無名関数) , 整数リテラル(つまり数字)などの即時情報
  • Expression : 評価が必要な式情報 (1+1, !true など)

この他にも, たまに分類不能な雑多な構造体が見受けられます.

皆さんには今日これらを全部?見てもらいます😇

!Notion!

構造体を見ていく(本記事を読む)上での前提をいくつか記述します.

Position

AST情報の一つとして, Positionという言葉が頻出します. これは{typeといったキーワードが .goファイル内のどの位置に出現したものかを記録しています.フォーマットは

example/sampleAstProgram.go:7:11

の形式で, sampleAstProgram.goファイルの7行11文字にキーワードが存在することを表しています. これによって基本ブロックがどこからどこまでか( ≒ {}の位置) 等をコンパイラが把握し, エラー行を詳細に表示することができます.

以降では構造体内のPositionを格納するメンバに関する説明を省略しています.

Comment

Javaのように, 関数や変数に付加されたコメントを格納する構造体メンバも存在します. こちらも説明を省略します.

Bad[Decl, Expr, Stmt]

Parse中にSyntaxErrorが発生し構造体を生成できない場合, 一旦BadDecl, BadExprといった構造体が生成されるようです.

メタ構造体たち

読み飛ばせばいいやつです.

File

1つのGoファイル全体の情報を持つ構造体です.

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
}

Ident

変数, 関数名と, そのオブジェクトのASTのリンカの役割です.

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

Object

変数, 関数など, オブジェクト1つのAST情報などを保存するための構造体です.Identから引くことができます.

type Object struct {
        Kind ObjKind
        Name string      // declared name
        Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil
        Data interface{} // object-specific data; or nil
        Type interface{} // placeholder for type information; may be nil
}
  • Kind
   const (
            Bad ObjKind = iota // for error handling
            Pkg                // package
            Con                // constant
            Typ                // type
            Var                // variable
            Fun                // function or method
            Lbl                // label
    )
  • Name : Ident構造体のメンバNameと一致します.

ここから本題に入っていきます.長いです.あと文体が変わります.

説明順の関係で, どうしても後方参照になってしまっている構造体のメンバがあります. 知らない構造体名が出てきても気にせず進む方が早いと思います.

Declaration

関数, 変数宣言など

GenDecl

import, const, type or var による宣言文

type GenDecl struct {
    Doc    *CommentGroup // associated documentation; or nil
    TokPos token.Pos     // position of Tok
    Tok    token.Token   // IMPORT, CONST, TYPE, VAR
    Lparen token.Pos     // position of '(', if any
    Specs  []Spec
    Rparen token.Pos // position of ')', if any
}
  • Tok : 宣言するオブジェクトのタイプ
    • token.IMPORT import "fmt"
    • token.CONST const string := "hoge"
    • token.VAR var variable int
    • token.TYPE type Hex int
  • Specs : オブジェクトの詳細情報. see ImportSpec, ValueSpec, and TypeSpec

FuncDecl

func による関数宣言

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
}
  • Recv : メソッドfunc (*struct) funcName(){} の場合, struct部分の情報が入る. Listってことは複数書ける...?
  • Name: 関数名
  • Type : どちらもList
    • Params : 引数
    • Results : 返り値
  • Body : 関数のBody部分. see Stmt

Spec

オブジェクトの詳細情報

ImportSpec

import文に関する情報

type 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)
}
  • Name : ローカルパッケージをimportすると, その名前が入ると書いてあるが, "./localpackage"をimportしてもnilのまま😔
  • Path : BasicLit
    • Kind : パスとして指定されるリテラル. おそらく"STRING"以外入らないのではないか.
    • Value : "\"fmt\""など.

ValueSpec

var, constによるフィールド宣言

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
}
  • Names : フィールド名. var x1, x2 int -> {x1, x2}` のように, 複数入る
  • Type : int等の情報が入る. 主に Ident構造体.
  • Values : 式を表すExprや数字, 文字を表すLiteral構造体によるValue定義が入る

TypeSpec

typeによる型宣言

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 the *XxxTypes
        Comment *CommentGroup // line comments; or nil
}
  • Assign : Type Aliasを使用している場合, alias元の型名が入る.
// example: Type Alias
    type myInt int
    type myIntAlias = fuga
    type myInt2 int
    var x1 myInt = 2
    var x2 myIntAlias = x1 // OK
    var x3 myInt2 = x1 // NG
  • Type 宣言される型の種類
    • int -> ast.Ident
    • func(...){...} -> ast.FuncType
    • struct{...} -> ast.StructType
    • type hoge = fuga -> ast.Ident

Type

型情報.

FuncType

関数型の情報. 引数と返り値情報のみで, method情報は含まれない.

type FuncType struct {
        Func    token.Pos  // position of "func" keyword (token.NoPos if there is no "func")
        Params  *FieldList // (incoming) parameters; non-nil
        Results *FieldList // (outgoing) results; or nil
}

StructType

構造体の情報.Incomplete boolをtrueにする条件がわからなかった><

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
}
  • Fields : 構造体のメンバフィールドの情報が入る

InterfaceType

インターフェースの情報

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
}
  • Methods : インターフェース内で宣言されているメソッド(関数)の情報が入る

ArrayType

array, sliceの情報

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
    • []int -> nil
    • [3]int -> "3"(BasicLit構造体)
  • Elt
    • []int -> int(Ident)

MapType

mapの情報

type MapType struct {
        Map   token.Pos // position of "map" keyword
        Key   Expr
        Value Expr
}
  • Key : map[string]int -> string(Ident構造体)
  • Value : map[string]int -> int(Ident)

ChanType

channelの情報

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
}
  • Dir : 下記の通り, 1か2が入りそうな雰囲気だが3が出た.わからん.
   const (
            SEND ChanDir = 1 << iota
            RECV
    )
  • Value : c chan int -> Ident int

    Statement

BlockStmt

{} で囲われたblock全体を表す. blockの中身を, Stmtの配列として持つ.

type BlockStmt struct {
        Lbrace token.Pos // position of "{"
        List   []Stmt
        Rbrace token.Pos // position of "}"
}

ExprStmt

評価式を表す.

type ExprStmt struct {
        X Expr // expression
}

DeclStmt

関数内でのフィールド宣言を表す. ただし:=はAssignStmtで管理される.

グローバル変数の場合はGenDeclが直接呼ばれる.

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

AssignStmt

:=を用いた代入文を表す.

type AssignStmt struct {
    Lhs    []Expr
    TokPos token.Pos   // position of Tok
    Tok    token.Token // assignment token, DEFINE
    Rhs    []Expr
}
  • Lhs,Rhs : c := 4 において, Lhsにはc, Rhsには4の情報が入る
  • Tok : :=が入る

ReturnStmt

return文を表す.

type ReturnStmt struct {
    Return  token.Pos // position of "return" keyword
    Results []Expr    // result expressions; or nil
}
  • Results :
    • return 1 -> 1(BasicLit構造体)
    • return -> nil

IncDecStmt

インクリメントi++ やデクリメントi--を表す.

type IncDecStmt struct {
        X      Expr
        TokPos token.Pos   // position of Tok
        Tok    token.Token // INC or DEC
}
  • X : インクリメント(デクリメント)する変数
  • Tok : ++ or --

ForStmt

for 文を表す.ただしfor range文を除く. 無限ループ for{}のときは, Init,Cond,Postの全てがnilになる.

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
}
  • Init
    • for i := 0; i < 10; i++ {} -> i := 0( AssignStmt構造体 )
  • Cond
    • for i := 0; i < 10; i++ {} -> i < 10(BinaryExpr)
    • for coundown > 0 {} -> coundown > 0(BinaryExpr)
  • Post
    • for i := 0; i < 10; i++ {} -> i++(IncDecStmt)
  • Body : {}の中身

RangeStmt

for range文を表す.

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 : for i, v := range arr {}のASTは次のようになる.

Keyとしてiの情報を得るためには arr(v)の情報が必要であり, どうやら Keyの時点で全ての情報を展開しているようだ. その後ValueXでは, Keyで展開した情報を参照している. Obj: *(obj @ 131)は, ASTの131行目のオブジェクトを参照している雰囲気がある.

    189  .  .  .  .  Key: *ast.Ident {
       190  .  .  .  .  .  NamePos: example/stmt.go:14:6
       191  .  .  .  .  .  Name: "i"
       192  .  .  .  .  .  Obj: *ast.Object {
       193  .  .  .  .  .  .  Kind: var
       194  .  .  .  .  .  .  Name: "i"
       195  .  .  .  .  .  .  Decl: *ast.AssignStmt {
       196  .  .  .  .  .  .  .  Lhs: []ast.Expr (len = 2) {
       197  .  .  .  .  .  .  .  .  0: *(obj @ 189)
       198  .  .  .  .  .  .  .  .  1: *ast.Ident {
       199  .  .  .  .  .  .  .  .  .  NamePos: example/stmt.go:14:9
       200  .  .  .  .  .  .  .  .  .  Name: "s"
       201  .  .  .  .  .  .  .  .  .  Obj: *ast.Object {
       202  .  .  .  .  .  .  .  .  .  .  Kind: var
       203  .  .  .  .  .  .  .  .  .  .  Name: "s"
       204  .  .  .  .  .  .  .  .  .  .  Decl: *(obj @ 195)
       205  .  .  .  .  .  .  .  .  .  }
       206  .  .  .  .  .  .  .  .  }
       207  .  .  .  .  .  .  .  }
       208  .  .  .  .  .  .  .  TokPos: example/stmt.go:14:11
       209  .  .  .  .  .  .  .  Tok: :=
       210  .  .  .  .  .  .  .  Rhs: []ast.Expr (len = 1) {
       211  .  .  .  .  .  .  .  .  0: *ast.UnaryExpr {
       212  .  .  .  .  .  .  .  .  .  OpPos: example/stmt.go:14:14
       213  .  .  .  .  .  .  .  .  .  Op: range
       214  .  .  .  .  .  .  .  .  .  X: *ast.Ident {
       215  .  .  .  .  .  .  .  .  .  .  NamePos: example/stmt.go:14:20
       216  .  .  .  .  .  .  .  .  .  .  Name: "strArray"
       217  .  .  .  .  .  .  .  .  .  .  Obj: *(obj @ 131)
       218  .  .  .  .  .  .  .  .  .  }
       219  .  .  .  .  .  .  .  .  }
       220  .  .  .  .  .  .  .  }
       221  .  .  .  .  .  .  }
       222  .  .  .  .  .  }
       223  .  .  .  .  }
       224  .  .  .  .  Value: *(obj @ 198)
  • Tok ::=など
  • X : for i, v := range arr{} -> arr (ast.Ident構造体 -> UnaryExpr構造体)
  • Body : {}の中身

IfStmt

if, if-else文を表す. if-else if文は, 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
}
  • Init : if a := true; a {} -> a := true;(AssignStmt構造体)
  • Cond
    • if a > 3 {} -> a > 3 (BinaryExpr)
    • if a := true; a {} -> a(Ident)
  • Body : {}の中身
  • Else
    • if a {} else {...} ->{...}( BlockStmt )
    • if a {} else if {...} -> if {...}(IfStmt)

SwitchStmt

switch{} 文を表す.

type SwitchStmt struct {
    Switch token.Pos  // position of "switch" keyword
    Init   Stmt       // initialization statement; or nil
    Tag    Expr       // tag expression; or nil
    Body   *BlockStmt // CaseClauses only
}
  • Init : switch i := 1; i{} -> i := 1(AssignStmt構造体)
  • Tag :
    • switch i {} -> i(Ident)
    • switch {} -> nil
  • Body : inner {} CaseClause構造体によって, case文が管理される.
     type CaseClause struct {
            Case  token.Pos // position of "case" or "default" keyword
            List  []Expr    // list of expressions or types; nil means default case
            Colon token.Pos // position of ":"
            Body  []Stmt    // statement list; or nil
        }
        - List :
            - `case 1,2,3:` -> `1,2,3` ([]BasicLit)
            - `default` ->  nil

TypeSwitchStmt

type switch文と呼ばれる, switch文の条件に型を使用するswitch文のstatement.

// example of Type Switch
    switch v := value.(type) {
        case nil:
        case int:
        default:
    }
type TypeSwitchStmt struct {
        Switch token.Pos  // position of "switch" keyword
        Init   Stmt       // initialization statement; or nil
        Assign Stmt       // x := y.(type) or y.(type)
        Body   *BlockStmt // CaseClauses only
}
  • Init : SwitchStmtと同じ
  • Assign : v := value.(type) -> AssignStmt -> (Ident := TypeAssertExpr)
  • Body : {}の中身. SwitchStmt`と同じ

LabeledStmt

JUMP:のようなラベルと, その直後の1つのstatementブロックを表す switch文における case 1:のようなラベルは対象外.

type LabeledStmt struct {
        Label *Ident
        Colon token.Pos // position of ":"
        Stmt  Stmt
}
  • Label :
   44  .  .  .  1: *ast.LabeledStmt {
    45  .  .  .  .  Label: *ast.Ident {
    46  .  .  .  .  .  NamePos: example/label-stmt.go:7:1
    47  .  .  .  .  .  Name: "FOR_LABEL"
    48  .  .  .  .  .  Obj: *ast.Object {
    49  .  .  .  .  .  .  Kind: label
    50  .  .  .  .  .  .  Name: "FOR_LABEL"
    51  .  .  .  .  .  .  Decl: *(obj @ 44)
    52  .  .  .  .  .  }
    53  .  .  .  .  }
  • Stmt : ラベルの直後のstatementが入る.下の例では, fmt.Println("hello")が当てはまる.
   FOR_LABEL:
        fmt.Println("hello")
        fmt.Println("world")

BranchStmt

break, continue, goto, or fallthrough キーワードを含むstatement.

fallthroughはswitch-case文の中で使われ,現在の次のcase項の先頭(条件比較式)にジャンプできる.つまり, cace文内で自動breakされるのを回避することができる.

goto文以外にも, break, continue文もラベルを引数に取ることができる.この場合, そのラベル直後のstatementから処理を再開する.

type BranchStmt struct {
        TokPos token.Pos   // position of Tok
        Tok    token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH)
        Label  *Ident      // label name; or nil
}
  • Tok
    • break [LABEL_NAME]
    • continue [LABEL_NAME]
    • goto LABEL_NAME
    • fallthrough : switch文の中で使われ,
  • Label
    • break : ラベルが付加されているstatementはForStmt, SwitchStmt, SelectStmtいづれかでなければならない
    • continue : ラベルが付加されているstatementはForStmtでなければならない.

DeferStmt

defer文を表す.

type DeferStmt struct {
        Defer token.Pos // position of "defer" keyword
        Call  *CallExpr
}
  • Call : 呼び出される関数

GoStmt

goキーワードを用いた並列処理文を表す.

type GoStmt struct {
        Go   token.Pos // position of "go" keyword
        Call *CallExpr
}
  • Call : 呼び出される関数

SelectStmt

channelのselect文を表す.

   select {
    case ch <- v:
    default:
    }
type SelectStmt struct {
        Select token.Pos  // position of "select" keyword
        Body   *BlockStmt // CommClauses only
}
  • Body : CommClauses構造体で表される.
   type CommClause struct {
        Case  token.Pos // position of "case" or "default" keyword
        Comm  Stmt      // send or receive statement; nil means default case
        Colon token.Pos // position of ":"
        Body  []Stmt    // statement list; or nil
    }
- Comm : 
    - `case ch <- v:` -> SendStmt
    - `case a := <- ch:` -> AssignStmt -> (Ident := UnaryExpr)
    - `case 2:` -> ExprStmt. syntax errorにはならなかったが, semantics errorか否かは試してない
    - switch-case文のように, caseの後に複数条件を書くことはできない
- Body : caseに対応する処理

SendStmt

channelへのメッセージ送信 ch <- aを表す.

type SendStmt struct {
        Chan  Expr
        Arrow token.Pos // position of "<-"
        Value Expr
}
  • Chan : ch <- a -> ch(Ident)
  • Value : ch <- a -> a(Ident)

EmptyStmt

nop! 不要な;を除去するためにある...?

type EmptyStmt struct {
        Semicolon token.Pos // position of following ";"
        Implicit  bool      // if set, ";" was omitted in the source; added in Go 1.5
}

Literal

BasicLit

Integer, Float, Imaginary(虚数), Char, String literalを表す.

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`
}

CompositeLit

Composite literalsを表す. 例えば以下のような初期化時代入のものをいう.

/// example of composite literals
type fuga struct {
    a int
    b string
}

var fooo = fuga{1} // here

var arr = []int{1, 2, 3} // here
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; added in Go 1.11
}
  • Type :構造体や配列の型情報
  • Elts : var fooo = fuga{1} -> 1(BasicLit)

FuncLit

関数リテラル(無名関数)を表す.

// example of function literal
var f = func(src string) string { return "<<" + src + ">>" }
type FuncLit struct {
        Type *FuncType  // function type
        Body *BlockStmt // function body
}

Expression

評価が必要な値を表す.

BinaryExpr

1+3, x == 2

type BinaryExpr struct {
    X     Expr        // left operand
    OpPos token.Pos   // position of Op
    Op    token.Token // operator
    Y     Expr        // right operand
}

CallExpr

func(1,2)

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 ")"
}

IndexExpr

arr[2]

type IndexExpr struct {
    X      Expr      // expression
    Lbrack token.Pos // position of "["
    Index  Expr      // index expression
    Rbrack token.Pos // position of "]"
}

KeyValueExpr

var s = MyStruct{key: "value"}

type KeyValueExpr struct {
        Key   Expr
        Colon token.Pos // position of ":"
        Value Expr
}

ParenExpr

(1+2)/3

type ParenExpr struct {
    Lparen token.Pos // position of "("
    X      Expr      // parenthesized expression
    Rparen token.Pos // position of ")"
}

SelectorExpr

fmt.Println("")

type SelectorExpr struct {
        X   Expr   // expression
        Sel *Ident // field selector
}
  • X : fmt.Println("🍣") -> "fmt"
  • Sel : fmt.Println("🍖") -> "Println"

SliceExpr

c := a[2:4]

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; added in Go 1.2
        Slice3 bool      // true if 3-index slice (2 colons present); added in Go 1.2
        Rbrack token.Pos // position of "]"
}
  • X : c := a[2:4] -> a (Ident構造体)
  • Low : c := a[2:4] -> 2 (BasicLit)
  • High : c := a[2:4] -> 4 (BasicLit)
  • Max : c := a[2:4:3] -> 3 (BasicLit)
  • Slice3 : sliceはa[low : high : max]のようにmaxを指定することができる. 指定していればtrue.

StarExpr

*Hoge

type StarExpr struct {
        Star token.Pos // position of "*"
        X    Expr      // operand
}
  • Star : position
  • X : *Hoge -> Expr of Hoge (ex, CompositeLit)

TypeAssertExpr

3.00.(int)

type TypeAssertExpr struct {
        X      Expr      // expression
        Lparen token.Pos // position of "("; added in Go 1.2
        Type   Expr      // asserted type; nil means type switch X.(type)
        Rparen token.Pos // position of ")"; added in Go 1.2
}
  • X : 3.00.(int) -> 3.00(FLOAT) (BasicLit構造体)
  • Type :3.00.(int) ->int ( Ident )

UnaryExpr

ポインタ* (StarExpr)を除く単項演算子による評価を表す.

(ex, !true, var b = &a, ^2)

type UnaryExpr struct {
        OpPos token.Pos   // position of Op
        Op    token.Token // operator
        X     Expr        // operand
}
  • Op : &a -> "&"
  • X : &a -> a (Ident 構造体)

その他

どうしても分類できなかったもの

Field, FieldList

実は今までたくさん出てきたField構造体. フィールド情報を表す.

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
}

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
}

Ellipsis

可変長引数, 配列を表す... <- これ

type Ellipsis struct {
        Ellipsis token.Pos // position of "..."
        Elt      Expr      // ellipsis element type (parameter lists only); or nil
}

見逃していなければ, go.astによって生成されるAST構造体はこれで全部のはず...?お疲れ様でした.

まとめ

書いてて思ったけど誰が読むんですかねこれ. 読ませる気がないですね... 自分用メモは こちら

ASTを眺めると, 知らなかった書き方(というかGoの全記法)を知れて良いですね. 一回読むだけで, 書き方でググる機会も減る気がします.

さて, ASTがだいたい判明したので, 誰かGoコンパイラ読んでみた記事書いてくれませんか?協力します☀️