[インデックス 1796] ファイルの概要
このコミットは、Go言語のpretty
パッケージにおける変更を記録しています。具体的には、tabwriter
インターフェースの調整と、parser
のコメント追加が主な内容です。
コミット
commit 47ba59ddb0dc6405bbe186e9718b1183b3fc6479
Author: Robert Griesemer <gri@golang.org>
Date: Tue Mar 10 16:31:19 2009 -0700
- adjustments due to changed tabwriter interface
- more comments in parser
R=r
OCL=26060
CL=26060
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/47ba59ddb0dc6405bbe186e9718b1183b3fc6479
元コミット内容
このコミットの元のメッセージは以下の通りです。
tabwriter
インターフェースの変更による調整- パーサーへのコメント追加
変更の背景
このコミットは、Go言語の初期開発段階におけるコードベースの改善の一環として行われました。主な変更点は二つあります。
tabwriter
インターフェースの変更への対応:tabwriter
は、テキストを整形し、タブ区切りでカラムを揃えるためのユーティリティです。このインターフェースが変更されたため、それを使用しているpretty
パッケージ内のコードも更新する必要がありました。これは、APIの進化に伴う一般的なコードの適応作業です。parser
へのコメント追加:parser
は、Goのソースコードを解析し、抽象構文木(AST)を生成する重要なコンポーネントです。初期のコードベースでは、その動作やインターフェースに関する説明が不足していた可能性があります。コメントを追加することで、コードの可読性と理解しやすさを向上させ、将来のメンテナンスや開発者がコードを理解する手助けとなります。特に、ErrorHandler
やScanner
といったインターフェースの役割、そしてParser
構造体の初期化方法に関する説明が追加されています。
これらの変更は、Go言語のツールチェインの安定性と使いやすさを向上させるための継続的な努力の一部です。
前提知識の解説
このコミットを理解するためには、以下の概念が役立ちます。
- Go言語の
go/printer
パッケージ(旧pretty
パッケージ): Go言語のソースコードを整形(pretty-print)するためのパッケージです。このコミットが対象としているusr/gri/pretty
は、Goの初期段階におけるgo/printer
パッケージの前身、あるいは実験的なバージョンであると考えられます。このパッケージは、Goのソースコードを読みやすく、標準的なフォーマットに沿って出力する役割を担います。 go/scanner
パッケージ: Goのソースコードを字句解析(lexical analysis)し、トークン(識別子、キーワード、演算子など)のストリームを生成するパッケージです。パーサーはこのスキャナーからの出力を入力として受け取ります。go/parser
パッケージ: Goのソースコードを構文解析(syntactic analysis)し、抽象構文木(AST: Abstract Syntax Tree)を生成するパッケージです。ASTは、プログラムの構造を木構造で表現したもので、コンパイラやツールがコードを理解し、操作するための基盤となります。text/tabwriter
パッケージ: Goの標準ライブラリの一部で、テキストをタブ区切りで整形し、カラムを揃えて出力するためのユーティリティです。特に、表形式のデータを整形する際に便利です。このパッケージは、可変幅のテキストを適切に配置し、読みやすい出力を生成するのに役立ちます。- 抽象構文木 (AST): プログラムのソースコードの抽象的な構文構造を、プログラミング言語の具体的な構文要素に依存しない形で表現した木構造のデータ構造です。コンパイラやリンター、コード整形ツールなど、多くの開発ツールで利用されます。
- インターフェース (Go): Go言語におけるインターフェースは、メソッドのシグネチャの集まりを定義する型です。特定のインターフェースを実装する型は、そのインターフェースが定義するすべてのメソッドを提供する必要があります。これにより、異なる具体的な型が共通の振る舞いを共有できるようになり、柔軟な設計が可能になります。
技術的詳細
このコミットは、主に以下の二つの技術的な変更を含んでいます。
-
tabwriter
インターフェースの変更への適応:- 変更前:
tabwriter.New(writer, *tabwidth, 1, padchar, true, html)
- 変更後:
tabwriter.NewWriter(writer, *tabwidth, 1, padchar, flags)
- この変更は、
text/tabwriter
パッケージのAPIが更新されたことを示しています。特に、New
関数がNewWriter
に名前変更され、引数の構成も変更されています。以前はブール値で直接渡されていたhtml
フラグが、uint
型のflags
引数の一部として渡されるようになりました。これにより、将来的に複数のフラグをビットマスクとしてまとめて管理できるようになり、APIの拡張性が向上します。 tabwriter.FilterHTML
という新しいフラグが導入され、HTMLコンテンツをフィルタリングする際の挙動を制御できるようになっています。これは、HTMLタグがタブ整形に影響を与えないようにするためのものです。
- 変更前:
-
parser
へのコメント追加とメソッド名の変更:usr/gri/pretty/parser.go
ファイルに、Parser
パッケージの目的、ErrorHandler
インターフェース、Scanner
インターフェース、そしてParser
構造体に関する詳細なコメントが追加されました。- 特に注目すべきは、
Parser
構造体の初期化メソッドがOpen
からInit
に変更された点です。- 変更前:
func (P *Parser) Open(scanner Scanner, err ErrorHandler, trace bool)
- 変更後:
func (P *Parser) Init(scanner Scanner, err ErrorHandler, trace bool)
- 変更前:
- この変更は、Go言語におけるオブジェクトの初期化に関する命名規則の標準化の一環である可能性があります。
Init
という名前は、一般的に構造体のフィールドを初期化し、使用可能な状態にするためのメソッドに用いられます。これにより、コードの意図がより明確になります。 - 追加されたコメントは、
Parser
がどのように機能し、どのようなインターフェースを期待するかを明確に説明しています。例えば、ErrorHandler
は構文エラーが発生した際に呼び出されること、Scanner
はトークンのストリームを提供すること、そしてParser
はInit
メソッドで初期化される必要があることなどが記述されています。
これらの変更は、Go言語の初期段階におけるAPIの洗練と、コードベースのドキュメント化の重要性を示しています。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルとコードスニペットは以下の通りです。
-
usr/gri/pretty/compilation.go
:--- a/usr/gri/pretty/compilation.go +++ b/usr/gri/pretty/compilation.go @@ -123,7 +123,7 @@ func Compile(src_file string, flags *Flags) (*AST.Program, int) { scanner.Init(src, &err, true); var parser Parser.Parser; - parser.Open(&scanner, &err, flags.Verbose); + parser.Init(&scanner, &err, flags.Verbose); prog := parser.ParseProgram();
Parser
の初期化メソッドの呼び出しがOpen
からInit
に変更されています。 -
usr/gri/pretty/parser.go
:--- a/usr/gri/pretty/parser.go +++ b/usr/gri/pretty/parser.go @@ -2,6 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// A parser for Go source text. The input is a stream of lexical tokens +// provided via the Scanner interface. The output is an abstract syntax +// tree (AST) representing the Go source. +// +// A client may parse the entire program (ParseProgram), only the package +// clause (ParsePackageClause), or the package clause and the import +// declarations (ParseImportDecls). The resulting AST represents the part +// of the program that is parsed. +// package Parser import ( @@ -12,16 +21,29 @@ import ( ) +// An implementation of an ErrorHandler must be provided to the Parser. +// If a syntax error is encountered, Error is called with the exact +// token position (the byte position of the token in the source) and the +// error message. +// type ErrorHandler interface { Error(pos int, msg string); } +// An implementation of a Scanner must be provided to the Parser. +// The parser calls Scan repeatedly to get a sequential stream of +// tokens. The source end is indicated by token.EOF. +// type Scanner interface { Scan() (pos, tok int, lit []byte); } +// A Parser holds the parser's internal state while processing +// a given text. It can be allocated as part of another data +// structure but must be initialized via Init before use. +// type Parser struct { scanner Scanner; err ErrorHandler; @@ -125,7 +147,7 @@ func (P *Parser) next() { } -func (P *Parser) Open(scanner Scanner, err ErrorHandler, trace bool) { +func (P *Parser) Init(scanner Scanner, err ErrorHandler, trace bool) { P.scanner = scanner; P.err = err;
Parser
パッケージの冒頭に詳細なコメントが追加され、Open
メソッドがInit
にリネームされています。 -
usr/gri/pretty/printer.go
:--- a/usr/gri/pretty/printer.go +++ b/usr/gri/pretty/printer.go @@ -1124,7 +1124,11 @@ func Print(writer io.Write, html bool, prog *ast.Program) { if *usetabs { padchar = '\t'; } - text := tabwriter.New(writer, *tabwidth, 1, padchar, true, html); + flags := uint(0); + if html { + flags |= tabwriter.FilterHTML; + } + text := tabwriter.NewWriter(writer, *tabwidth, 1, padchar, flags); P.Init(text, html, prog.Comments); if P.html {
tabwriter.New
の呼び出しがtabwriter.NewWriter
に変更され、引数の渡し方がflags
を使用するように変更されています。 -
usr/gri/pretty/untab.go
:--- a/usr/gri/pretty/untab.go +++ b/usr/gri/pretty/untab.go @@ -40,7 +40,7 @@ func main() { if *usetabs { padchar = '\t'; } - dst := tabwriter.New(os.Stdout, *tabwidth, 1, padchar, true, false); + dst := tabwriter.NewWriter(os.Stdout, *tabwidth, 1, padchar, 0); if flag.NArg() > 0 { for i := 0; i < flag.NArg(); i++ { name := flag.Arg(i);
ここでも
tabwriter.New
の呼び出しがtabwriter.NewWriter
に変更されています。
コアとなるコードの解説
このコミットのコアとなる変更は、Go言語のpretty
パッケージ(現在のgo/printer
パッケージに相当)が依存しているtext/tabwriter
パッケージのAPI変更への適応と、go/parser
パッケージのドキュメンテーションの改善です。
-
tabwriter
のAPI変更:tabwriter.New
関数がtabwriter.NewWriter
にリネームされたことは、GoのAPI設計における命名規則の進化を示唆しています。NewWriter
という名前は、io.Writer
を受け取り、新しいtabwriter
インスタンスを返すという関数の役割をより明確に伝えます。- ブール値の引数
html
がflags
というuint
型の引数に置き換えられ、tabwriter.FilterHTML
というビットフラグが導入されたことは、APIの柔軟性と拡張性を高めるための典型的なパターンです。これにより、将来的に新しい整形オプションが追加された場合でも、既存のAPIシグネチャを変更することなく対応できるようになります。これは、APIの安定性を保ちつつ機能を追加するための良いプラクティスです。
-
parser
のコメント追加とOpen
からInit
へのリネーム:parser.go
に追加されたコメントは、Go言語のコードベースにおけるドキュメンテーションの重要性を強調しています。特に、パッケージの目的、主要なインターフェース(ErrorHandler
,Scanner
)の役割、そして構造体(Parser
)の初期化方法を明確にすることで、他の開発者がこのコードを理解し、正しく使用するための手助けとなります。Parser
構造体の初期化メソッドがOpen
からInit
に変更されたことは、Go言語の慣習に合わせたものです。Goでは、構造体の初期化を行うメソッドにはNew
(新しいインスタンスを返す場合)またはInit
(既存のインスタンスを初期化する場合)という名前がよく使われます。この変更により、コードの意図がより明確になり、Goの標準的なパターンに沿うことで、コードベース全体の一貫性が向上します。
これらの変更は、Go言語の初期段階において、コードの品質、可読性、保守性を向上させるための継続的な取り組みの一環として行われたものです。APIの洗練と適切なドキュメンテーションは、言語とそのエコシステムの成長にとって不可欠な要素です。
関連リンク
- Go言語の
text/tabwriter
パッケージのドキュメント: https://pkg.go.dev/text/tabwriter - Go言語の
go/parser
パッケージのドキュメント: https://pkg.go.dev/go/parser - Go言語の
go/printer
パッケージのドキュメント: https://pkg.go.dev/go/printer
参考にした情報源リンク
- GitHub: golang/go commit 47ba59ddb0dc6405bbe186e9718b1183b3fc6479: https://github.com/golang/go/commit/47ba59ddb0dc6405bbe186e9718b1183b3fc6479
- Go言語の公式ドキュメント (pkg.go.dev)
- Go言語のソースコードリポジトリ (GitHub)
- Go言語の初期開発に関する一般的な情報