[インデックス 10899] ファイルの概要
コミット
コミットハッシュ: b9697d4a58bfd6dd99e03123c3d53e4f1b035787
作成者: Robert Griesemer gri@golang.org
日付: 2011年12月20日 9:59:09 -0800
コミットメッセージ: go/ast, parser: remember short variable decls. w/ correspoding ident objects
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b9697d4a58bfd6dd99e03123c3d53e4f1b035787
元コミット内容
go/ast, parser: remember short variable decls. w/ correspoding ident objects
The ast.Object's Decl field pointed back to the corresponding declaration for
all but short variable declarations. Now remember corresponding assignment
statement in the Decl field.
Also: simplified some code for parsing select statements.
R=golang-dev, r, bradfitz
CC=golang-dev
https://golang.org/cl/5492072
変更の背景
このコミットは、Go言語の抽象構文木(AST)における短い変数宣言(:=
)の処理を改善するものです。2011年12月の時点で、Go言語はまだ公式リリース1.0(2012年3月)に向けて開発が進められていた時期でした。
従来、ast.Object
のDecl
フィールドは、通常の変数宣言、関数宣言、型宣言などの宣言文については、対応する宣言ノードへの参照を保持していました。しかし、短い変数宣言(:=
)については、この関連付けが不完全でした。これにより、ASTを解析するツールやコンパイラの他の部分で、短い変数宣言に関する情報を正確に取得することが困難でした。
このコミットでは、短い変数宣言で作成される識別子オブジェクトのDecl
フィールドに、対応する代入文(AssignStmt
)への参照を保存するように改善されました。これにより、AST解析ツールがより一貫性のある情報を得られるようになりました。
前提知識の解説
Go言語の短い変数宣言(:=
)について
Go言語では、変数を宣言する方法が複数あります:
- 通常の変数宣言:
var x int = 10
- 短い変数宣言:
x := 10
短い変数宣言(:=
)は、新しい変数を宣言し、同時に値を代入するために使用されます。これは、少なくとも1つの変数が新しく宣言される場合にのみ有効です。
抽象構文木(AST)について
ASTは、プログラムの構造を階層的に表現したデータ構造です。Go言語では、go/ast
パッケージがASTの各ノードを表現する型を定義しています。
ast.Object
について
ast.Object
は、識別子(変数名、関数名など)を表現するASTノードです。この構造体は以下のフィールドを持ちます:
Kind
: オブジェクトの種類(変数、関数、型など)Name
: 識別子名Decl
: 対応する宣言ノードへの参照Data
: オブジェクト固有のデータType
: 型情報のプレースホルダー
Go言語のパーサーについて
go/parser
パッケージは、Go言語のソースコードをASTに変換する役割を担っています。パーサーは、字句解析(トークン化)と構文解析を行い、ASTノードを作成します。
技術的詳細
問題の詳細
変更前の実装では、ast.Object
のDecl
フィールドは以下のような宣言に対してのみ、対応する宣言ノードへの参照を保持していました:
- 通常の変数宣言(
var
文) - 関数宣言(
func
文) - 型宣言(
type
文) - ラベル文(
label:
)
しかし、短い変数宣言(:=
)については、この関連付けが行われていませんでした。短い変数宣言は構文的には代入文(AssignStmt
)として扱われるため、従来のDecl
フィールドの仕組みでは適切に処理されていませんでした。
解決策の詳細
このコミットでは、以下の変更が行われました:
-
ast.Object
のDecl
フィールドの拡張: コメントを更新し、AssignStmt
も含むことを明示しました。 -
Object.Pos()
メソッドの拡張:AssignStmt
の場合の処理を追加し、左辺の識別子から位置情報を取得できるようにしました。 -
shortVarDecl
関数の改善: 短い変数宣言の処理において、作成されるast.Object
のDecl
フィールドに対応するAssignStmt
への参照を設定するように変更しました。 -
パーサーの改善:
parseSimpleStmt
とparseCommClause
関数で、AssignStmt
の作成とshortVarDecl
の呼び出しを統合し、より効率的な処理を実現しました。
コアとなるコードの変更箇所
1. ast.Object
のDecl
フィールドの拡張
// 変更前
Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
// 変更後
Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, or AssignStmt; or nil
2. Object.Pos()
メソッドにAssignStmt
のケースを追加
case *AssignStmt:
for _, x := range d.Lhs {
if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
return ident.Pos()
}
}
3. shortVarDecl
関数の改善
// 変更前
func (p *parser) shortVarDecl(idents []*ast.Ident) {
// ...
obj := ast.NewObj(ast.Var, ident.Name)
// short var declarations cannot have redeclaration errors
// and are not global => no need to remember the respective
// declaration
ident.Obj = obj
// ...
}
// 変更後
func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []ast.Expr) {
// ...
obj := ast.NewObj(ast.Var, ident.Name)
// remember corresponding assignment for other tools
obj.Decl = decl
ident.Obj = obj
// ...
}
コアとなるコードの解説
shortVarDecl
関数の改善について
変更前のshortVarDecl
関数は、識別子のリストを受け取り、それぞれに対してast.Object
を作成していました。しかし、Decl
フィールドは設定されていませんでした。
変更後の実装では、関数のシグネチャが変更され、AssignStmt
と式のリストを受け取るようになりました。これにより、作成されるast.Object
のDecl
フィールドに対応するAssignStmt
を設定できるようになりました。
パーサーの統合改善について
parseSimpleStmt
関数では、AssignStmt
の作成とshortVarDecl
の呼び出しが統合されました。これにより、同じAssignStmt
オブジェクトがshortVarDecl
に渡され、適切な関連付けが行われるようになりました。
select文の解析の簡略化について
parseCommClause
関数では、receive文の処理が簡略化されました。複雑だった条件分岐が整理され、より読みやすく保守しやすいコードになりました。