[インデックス 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言語の初期開発に関する一般的な情報