Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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.ObjectDeclフィールドは、通常の変数宣言、関数宣言、型宣言などの宣言文については、対応する宣言ノードへの参照を保持していました。しかし、短い変数宣言(:=)については、この関連付けが不完全でした。これにより、ASTを解析するツールやコンパイラの他の部分で、短い変数宣言に関する情報を正確に取得することが困難でした。

このコミットでは、短い変数宣言で作成される識別子オブジェクトのDeclフィールドに、対応する代入文(AssignStmt)への参照を保存するように改善されました。これにより、AST解析ツールがより一貫性のある情報を得られるようになりました。

前提知識の解説

Go言語の短い変数宣言(:=)について

Go言語では、変数を宣言する方法が複数あります:

  1. 通常の変数宣言: var x int = 10
  2. 短い変数宣言: 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.ObjectDeclフィールドは以下のような宣言に対してのみ、対応する宣言ノードへの参照を保持していました:

  • 通常の変数宣言(var文)
  • 関数宣言(func文)
  • 型宣言(type文)
  • ラベル文(label:

しかし、短い変数宣言(:=)については、この関連付けが行われていませんでした。短い変数宣言は構文的には代入文(AssignStmt)として扱われるため、従来のDeclフィールドの仕組みでは適切に処理されていませんでした。

解決策の詳細

このコミットでは、以下の変更が行われました:

  1. ast.ObjectDeclフィールドの拡張: コメントを更新し、AssignStmtも含むことを明示しました。

  2. Object.Pos()メソッドの拡張: AssignStmtの場合の処理を追加し、左辺の識別子から位置情報を取得できるようにしました。

  3. shortVarDecl関数の改善: 短い変数宣言の処理において、作成されるast.ObjectDeclフィールドに対応するAssignStmtへの参照を設定するように変更しました。

  4. パーサーの改善: parseSimpleStmtparseCommClause関数で、AssignStmtの作成とshortVarDeclの呼び出しを統合し、より効率的な処理を実現しました。

コアとなるコードの変更箇所

1. ast.ObjectDeclフィールドの拡張

// 変更前
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.ObjectDeclフィールドに対応するAssignStmtを設定できるようになりました。

パーサーの統合改善について

parseSimpleStmt関数では、AssignStmtの作成とshortVarDeclの呼び出しが統合されました。これにより、同じAssignStmtオブジェクトがshortVarDeclに渡され、適切な関連付けが行われるようになりました。

select文の解析の簡略化について

parseCommClause関数では、receive文の処理が簡略化されました。複雑だった条件分岐が整理され、より読みやすく保守しやすいコードになりました。

関連リンク

参考にした情報源リンク