この記事は 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
- token.IMPORT
- 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
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.Identfunc(...){...}-> ast.FuncTypestruct{...}-> ast.StructTypetype 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 }
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-> IdentintStatement
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の時点で全ての情報を展開しているようだ. その後ValueやXでは, 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_NAMEfallthrough: switch文の中で使われ,
- Label
- break : ラベルが付加されているstatementは
ForStmt,SwitchStmt,SelectStmtのいづれかでなければならない - continue : ラベルが付加されているstatementは
ForStmtでなければならない.
- break : ラベルが付加されているstatementは
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 ofHoge(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コンパイラ読んでみた記事書いてくれませんか?協力します☀️