[インデックス 1264] ファイルの概要
このコミットは、Go言語の初期のpretty
パッケージ(コード整形ツール)における複数の改善を含んでいます。具体的には、ステートメントリスト内でのソースレベルの改行の扱いに関する見落としの修正、空の構造体やインターフェースの出力の修正、そしてこれら修正によってパスするようになった2つのテストの有効化が行われています。
コミット
commit acfd1fd4438060eebf929778cfef982f0b03e0f2
Author: Robert Griesemer <gri@golang.org>
Date: Tue Dec 2 17:01:31 2008 -0800
- oversight: extra allow source-level line breaks inside statement lists
- fixed printing of empty structs/interfaces
- enable two more tests
R=r
OCL=20296
CL=20296
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/acfd1fd4438060eebf929778cfef982f0b03e0f2
元コミット内容
- oversight: extra allow source-level line breaks inside statement lists
- fixed printing of empty structs/interfaces
- enable two more tests
R=r
OCL=20296
CL=20296
変更の背景
このコミットは、Go言語の初期段階におけるコード整形ツール(pretty
パッケージ)の品質向上を目的としています。
- ステートメントリスト内の改行処理の改善: コミットメッセージの「oversight: extra allow source-level line breaks inside statement lists」は、ステートメントのリスト(例えば、
{ ... }
ブロック内の文の並び)において、本来許容されるべきではない場所で余分な改行が挿入されたり、あるいは逆に、必要な改行が適切に処理されていなかったりする問題があったことを示唆しています。これは、コードの可読性や一貫性を損なうため、整形ツールとしては重要な修正点です。 - 空の構造体/インターフェースの出力修正: 「fixed printing of empty structs/interfaces」は、
struct {}
やinterface {}
のような空の型が、pretty
パッケージによって正しく整形・出力されていなかったバグがあったことを示しています。これは、Go言語の基本的な型定義に関わる問題であり、正確なコード出力のために修正が必要でした。 - テストの有効化: 上記の修正により、これまで失敗していた、あるいはスキップされていた2つのテストが正常にパスするようになったため、それらをテストスイートに再度含める(有効化する)ことが可能になりました。これは、修正が期待通りに機能していることの検証と、リグレッション防止のための重要なステップです。
これらの変更は、Go言語のコンパイラやツールチェーンがまだ活発に開発されていた時期に、コードの整形と表示の正確性を高めるための継続的な取り組みの一環として行われました。
前提知識の解説
このコミットを理解するためには、以下の概念が役立ちます。
- Go言語の初期開発: このコミットは2008年12月のものであり、Go言語が一般に公開される前の非常に初期の段階に当たります。当時のコードベースは現在とは異なる構造や命名規則を持つことがあり、
usr/gri/pretty
のようなパスは、開発者(Robert Griesemer)の個人作業ディレクトリを示している可能性があります。 - コード整形(Pretty Printing): プログラミング言語のソースコードを、読みやすく一貫性のあるスタイルで自動的にフォーマットするプロセスです。Go言語には公式の
gofmt
ツールがありますが、このコミットで言及されているpretty
パッケージは、その前身または関連する実験的なツールであったと考えられます。コード整形ツールは、構文木(AST)を解析し、その構造に基づいて適切なインデント、改行、スペースなどを挿入します。 - 抽象構文木(Abstract Syntax Tree, AST): ソースコードの抽象的な構文構造を木構造で表現したものです。コンパイラやコード分析ツールは、ソースコードをまずASTに変換し、そのASTを操作することで、コードの解析、最適化、変換、そして整形を行います。
printer.go
がASTノードを処理していることから、このツールがASTに基づいていることがわかります。 array.Array
: Go言語の初期には、現在のスライス([]T
)やマップ(map[K]V
)がまだ存在しないか、あるいは現在とは異なる形で実装されていました。array.Array
は、当時のGo言語で可変長リストを扱うためのデータ構造の一つであったと考えられます。現在のGo言語では、通常は組み込みのスライス型が使用されます。P.state
: コード整形ツール内部で、現在の整形処理の状態を管理するための変数です。例えば、opening_scope
は{
のようなスコープ開始記号を処理している状態、inside_list
はリストの内部を処理している状態などを示し、これによって改行やインデントのルールが動的に適用されます。test.sh
: シェルスクリプトは、ソフトウェア開発において、ビルド、テスト、デプロイなどの自動化されたタスクを実行するためによく使用されます。このtest.sh
は、pretty
パッケージのテストスイートを実行するためのスクリプトであり、特定のテストファイルをスキップしたり、含めたりするロジックが含まれています。
技術的詳細
このコミットは、主にusr/gri/pretty/printer.go
、usr/gri/pretty/selftest2.go
、usr/gri/pretty/test.sh
の3つのファイルに変更を加えています。
-
usr/gri/pretty/printer.go
の変更:- 空の構造体/インターフェースの出力修正:
Fields
関数内で、リストが空の場合の条件がlist != nil
からlist.Len() > 0
に変更されました。- 変更前:
if list != nil {
- 変更後:
if list.Len() > 0 {
- これは、
list
がnil
ではないが、要素が一つも含まれていない(Len() == 0
)場合に、{}
のように空のブロックとして正しく出力されるようにするための修正です。以前の実装では、nil
でない空のリストが渡された場合に、意図しない出力になっていた可能性があります。
- 変更前:
- ステートメントリスト内の改行処理の改善:
StatementList
関数内で、各ステートメントを処理した後にP.state = inside_list;
が追加されました。- 変更前: (なし)
- 変更後:
P.state = inside_list;
- この変更は、ステートメントリストの各要素を整形する際に、整形器の内部状態を
inside_list
に設定することで、その後の改行やスペースの挿入ルールが「リストの内部」に適したものになるように調整します。これにより、ステートメント間の改行がより適切に制御され、不必要な改行が抑制されたり、必要な改行が挿入されたりするようになります。
- 空の構造体/インターフェースの出力修正:
-
usr/gri/pretty/selftest2.go
の変更:- このファイルには、新しいテストケースとして空の構造体
type S struct {}
が追加されました。 - この追加は、
printer.go
で修正された空の構造体の出力バグが正しく修正されたことを検証するためのものです。
- このファイルには、新しいテストケースとして空の構造体
-
usr/gri/pretty/test.sh
の変更:- テストスクリプト内で、スキップされるファイルリストから
decimal.go
とtabwriter_test.go
が削除されました。 - 変更前:
log.go | decimal.go | type.go | tabwriter_test.go | \
- 変更後:
log.go | type.go | \
- これは、
printer.go
の修正によって、これらのファイルに関連するテストがパスするようになったため、もはやスキップする必要がなくなったことを意味します。これにより、テストカバレッジが向上し、リグレッションが防止されます。
- テストスクリプト内で、スキップされるファイルリストから
コアとなるコードの変更箇所
usr/gri/pretty/printer.go
における変更がコアとなります。
--- a/usr/gri/pretty/printer.go
+++ b/usr/gri/pretty/printer.go
@@ -348,7 +348,7 @@ func (P *Printer) Fields(list *array.Array, end int) {
P.state = opening_scope;
P.String(0, "{");
- if list != nil {
+ if list.Len() > 0 {
P.newlines = 1;
var prev int;
for i, n := 0, list.Len(); i < n; i++ {
@@ -547,6 +547,7 @@ func (P *Printer) StatementList(list *array.Array) {
for i, n := 0, list.Len(); i < n; i++ {
P.Stat(list.At(i).(*AST.Stat));
P.newlines = 1;
+ P.state = inside_list;
}
}
}
コアとなるコードの解説
-
func (P *Printer) Fields(list *array.Array, end int)
内の変更:if list != nil {
からif list.Len() > 0 {
への変更は、Go言語の初期のarray.Array
型が、nil
ではないが要素数が0である状態(空の配列)を持つ可能性を考慮したものです。以前の条件では、空の配列が渡された場合に、{}
と出力されるべきところが、{
だけが出力されたり、あるいは内部でエラーが発生したりする可能性がありました。list.Len() > 0
とすることで、要素が存在する場合にのみリストの内容を処理し、要素がない場合は適切に空のブロックとして扱われるようになります。これは、空の構造体やインターフェースの正しい出力に直接貢献します。
-
func (P *Printer) StatementList(list *array.Array)
内の追加:P.state = inside_list;
の追加は、コード整形器の内部状態管理をより正確にするためのものです。StatementList
関数は、複数のステートメント(文)のリストを整形する役割を担っています。各ステートメントを処理した後、整形器の状態をinside_list
に明示的に設定することで、次のステートメントやリストの終端を処理する際に、リスト内部での改行やインデントに関する整形ルールが適用されるようになります。これにより、ステートメント間の不適切な改行が修正され、より自然で一貫性のあるコードフォーマットが実現されます。例えば、if { ... } else { ... }
のような構造で、else
が}
と同じ行に続くべきか、新しい行に続くべきかといった判断に影響を与える可能性があります。
これらの変更は、Go言語のコード整形ツールが、より堅牢で正確な出力を生成するための基盤を強化するものであり、Go言語の初期の進化における重要なステップを示しています。
関連リンク
- Go言語公式サイト: https://go.dev/
- Go言語の
gofmt
ツールに関するドキュメント(現代のGoにおけるコード整形): https://go.dev/blog/gofmt
参考にした情報源リンク
- GitHub上のコミットページ: https://github.com/golang/go/commit/acfd1fd4438060eebf929778cfef982f0b03e0f2
- Go言語の歴史に関する一般的な情報(Go言語の初期開発段階を理解するため)