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

[インデックス 12209] ファイルの概要

このコミットは、Go言語の標準ライブラリである go/ast パッケージに、ast.Print および ast.Inspect 関数の使用例を示すテストファイル src/pkg/go/ast/example_test.go を追加するものです。これにより、Goプログラムの抽象構文木(AST)を操作・検査する方法が具体的に示され、開発者がこれらの機能を理解しやすくなります。

コミット

commit 34e60a81d5b9a3c18d634d89acea9384605f4916
Author: Robert Griesemer <gri@golang.org>
Date:   Fri Feb 24 13:44:36 2012 -0800

    go/ast: examples for ast.Print, ast.Inspect
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5700057

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/34e60a81d5b9a3c18d634d89acea9384605f4916

元コミット内容

go/ast: examples for ast.Print, ast.Inspect

このコミットは、go/ast パッケージの ast.Print 関数と ast.Inspect 関数の使用例を追加します。

変更の背景

Go言語の go/ast パッケージは、Goプログラムのソースコードを解析して抽象構文木(AST)を構築し、そのASTを操作するための機能を提供します。しかし、これらの強力な機能は、特に初心者にとっては直感的に理解しにくい場合があります。ast.Print はASTをデバッグ目的で整形して出力するのに役立ち、ast.Inspect はASTを走査して特定のノードを検査するのに使用されます。

このコミットの背景には、これらの重要な関数の使い方を明確に示し、開発者がGoのツールや静的解析ツールを構築する際に go/ast パッケージをより効果的に活用できるようにするという意図があります。具体的な使用例を提供することで、学習曲線が緩和され、パッケージの採用が促進されます。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念と標準ライブラリの知識が必要です。

  1. 抽象構文木 (Abstract Syntax Tree, AST): ASTは、プログラミング言語のソースコードの抽象的な構文構造を木構造で表現したものです。各ノードはソースコードの構成要素(変数、関数、式、文など)を表し、その子ノードはそれらの構成要素の内部構造を示します。コンパイラやリンター、コードフォーマッターなどのツールは、ソースコードをASTに変換し、そのASTを操作することで様々な処理を行います。

  2. go/parser パッケージ: go/parser パッケージは、Go言語のソースコードを解析し、そのASTを生成するための機能を提供します。parser.ParseFile 関数は、指定されたファイルまたは文字列からGoのソースコードを読み込み、*ast.File 型のASTルートノードを返します。

  3. go/token パッケージ: go/token パッケージは、Goソースコード内の位置情報(ファイル名、行番号、列番号など)を管理するための型と関数を提供します。token.FileSet は、複数のファイルにわたる位置情報を一元的に管理するために使用されます。ASTノードは、ソースコード内の対応する位置への参照を token.Pos 型で保持します。

  4. go/ast パッケージ: go/ast パッケージは、GoプログラムのASTを表現する型(ast.Node インターフェースとその実装型)と、ASTを操作するためのユーティリティ関数を提供します。

    • ast.Node: AST内のすべてのノードが実装するインターフェースです。
    • ast.Print(fset *token.FileSet, x interface{}): ASTの構造をデバッグ目的で整形して標準出力に表示する関数です。fset は位置情報を解決するために使用され、x は表示したいASTノード(通常は *ast.File)です。
    • ast.Inspect(node ast.Node, f func(ast.Node) bool): ASTを深さ優先で走査(トラバース)するための関数です。引数 f は、各ノードが訪問されるたびに呼び出されるコールバック関数です。このコールバック関数が false を返すと、そのノードの子孫の走査は停止します。これにより、特定の種類のノードを検索したり、ASTの特定の部分を処理したりすることができます。
  5. Goのテストにおける Example 関数: Goのテストフレームワークでは、Example 関数という特別な形式のテスト関数をサポートしています。これらの関数は、コードの実行例を示すために使用され、その出力はコメントとして // output: の後に記述されます。go test コマンドは、この出力コメントと実際の実行結果を比較し、一致しない場合はテスト失敗とします。これにより、コードのドキュメントとテストを同時に行うことができ、例が常に最新かつ正確であることを保証できます。

技術的詳細

このコミットは、src/pkg/go/ast/example_test.go という新しいファイルを追加することで、go/ast パッケージの ast.Inspectast.Print 関数の具体的な使用方法をデモンストレーションしています。

ExampleInspect() 関数

ExampleInspect() 関数は、GoプログラムのASTを検査する方法を示しています。

  1. ソースコードの準備: src 変数に、検査対象となるGoのソースコード(package p; const c = 1.0; var X = f(3.14)*2 + c;)が文字列リテラルとして定義されています。

  2. ASTの生成: token.NewFileSet() で新しい FileSet が作成され、parser.ParseFile(fset, "src.go", src, 0) を使用して、このソースコードからASTが生成されます。parser.ParseFile は、ソースコードを解析し、その結果として *ast.File 型のASTルートノードを返します。

  3. ASTの検査 (ast.Inspect): ast.Inspect(f, func(n ast.Node) bool { ... }) が呼び出され、生成されたAST f が走査されます。無名関数が各ASTノード n に対して呼び出されます。

    • この無名関数内では、switch x := n.(type) を使用して、現在のノード n の具体的な型をチェックしています。
    • もしノードが *ast.BasicLit(基本的なリテラル、例: 1.0, 2, 3.14)または *ast.Ident(識別子、例: p, c, X, f)であれば、その値または名前が抽出されます。
    • 抽出された値は、fset.Position(n.Pos()) を使ってソースコード内の正確な位置情報(ファイル名、行番号、列番号)と共に fmt.Printf で出力されます。
    • コールバック関数は常に true を返すため、ASTのすべてのノードが再帰的に走査されます。
  4. 期待される出力: // output: コメントブロックには、この例を実行した際に期待される出力が記述されており、go test コマンドによって検証されます。出力は、ソースコード内の各識別子とリテラルの位置と値を示しています。

ExamplePrint() 関数

ExamplePrint() 関数は、デバッグ目的でASTを整形して出力する方法を示しています。

  1. ソースコードの準備: src 変数に、ASTとして出力したいGoのソースコード(package main; func main() { println("Hello, World!") })が定義されています。

  2. ASTの生成: token.NewFileSet()parser.ParseFile(fset, "", src, 0) を使用して、このソースコードからASTが生成されます。

  3. ASTの出力 (ast.Print): ast.Print(fset, f) が呼び出され、生成されたAST fFileSet fset を使って整形され、標準出力に詳細な構造として出力されます。この出力は、ASTの各ノードの型、フィールド、値、そしてソースコード内の位置情報(行番号と列番号)を階層的に示します。

  4. 期待される出力: // output: コメントブロックには、ast.Print によって生成されるASTの構造が詳細に記述されています。これは、ASTの内部構造を理解し、デバッグする上で非常に役立ちます。

これらの例は、go/ast パッケージが提供するAST操作の基本的なパターンを明確に示しており、Goの静的解析やコード生成ツール開発の出発点として機能します。

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

このコミットによって追加されたファイルは src/pkg/go/ast/example_test.go です。

--- /dev/null
+++ b/src/pkg/go/ast/example_test.go
@@ -0,0 +1,136 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+)
+
+// This example demonstrates how to inspect the AST of a Go program.
+func ExampleInspect() {
+	// src is the input for which we want to inspect the AST.
+	src := `
+package p
+const c = 1.0
+var X = f(3.14)*2 + c
+`
+
+	// Create the AST by parsing src.
+	fset := token.NewFileSet() // positions are relative to fset
+	f, err := parser.ParseFile(fset, "src.go", src, 0)
+	if err != nil {
+		panic(err)
+	}
+
+	// Inspect the AST and print all identifiers and literals.
+	ast.Inspect(f, func(n ast.Node) bool {
+		var s string
+		switch x := n.(type) {
+		case *ast.BasicLit:
+			s = x.Value
+		case *ast.Ident:
+			s = x.Name
+		}
+		if s != "" {
+			fmt.Printf("%s:\t%s\n", fset.Position(n.Pos()), s)
+		}
+		return true
+	})
+
+	// output:
+	// src.go:2:9:	p
+	// src.go:3:7:	c
+	// src.go:3:11:	1.0
+	// src.go:4:5:	X
+	// src.go:4:9:	f
+	// src.go:4:11:	3.14
+	// src.go:4:17:	2
+	// src.go:4:21:	c
+}
+
+// This example shows what an AST looks like when printed for debugging.
+func ExamplePrint() {
+	// src is the input for which we want to print the AST.
+	src := `
+package main
+func main() {
+	println("Hello, World!")
+}
+`
+
+	// Create the AST by parsing src.
+	fset := token.NewFileSet() // positions are relative to fset
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		panic(err)
+	}
+
+	// Print the AST.
+	ast.Print(fset, f)
+
+	// output:
+	//      0  *ast.File {
+	//      1  .  Package: 2:1
+	//      2  .  Name: *ast.Ident {
+	//      3  .  .  NamePos: 2:9
+	//      4  .  .  Name: "main"
+	//      5  .  }
+	//      6  .  Decls: []ast.Decl (len = 1) {
+	//      7  .  .  0: *ast.FuncDecl {
+	//      8  .  .  .  Name: *ast.Ident {
+	//      9  .  .  .  .  NamePos: 3:6
+	//     10  .  .  .  .  Name: "main"
+	//     11  .  .  .  .  Obj: *ast.Object {
+	//     12  .  .  .  .  .  Kind: func
+	//     13  .  .  .  .  .  Name: "main"
+	//     14  .  .  .  .  .  Decl: *(obj @ 7)
+	//     15  .  .  .  .  }
+	//     16  .  .  .  }
+	//     17  .  .  .  Type: *ast.FuncType {
+	//     18  .  .  .  .  Func: 3:1
+	//     19  .  .  .  .  Params: *ast.FieldList {
+	//     20  .  .  .  .  .  Opening: 3:10
+	//     21  .  .  .  .  .  Closing: 3:11
+	//     22  .  .  .  .  }
+	//     23  .  .  .  }
+	//     24  .  .  .  Body: *ast.BlockStmt {
+	//     25  .  .  .  .  Lbrace: 3:13
+	//     26  .  .  .  .  List: []ast.Stmt (len = 1) {
+	//     27  .  .  .  .  .  0: *ast.ExprStmt {
+	//     28  .  .  .  .  .  .  X: *ast.CallExpr {
+	//     29  .  .  .  .  .  .  .  Fun: *ast.Ident {
+	//     30  .  .  .  .  .  .  .  .  NamePos: 4:2
+	//     31  .  .  .  .  .  .  .  .  Name: "println"
+	//     32  .  .  .  .  .  .  .  }
+	//     33  .  .  .  .  .  .  .  Lparen: 4:9
+	//     34  .  .  .  .  .  .  .  Args: []ast.Expr (len = 1) {
+	//     35  .  .  .  .  .  .  .  .  0: *ast.BasicLit {
+	//     36  .  .  .  .  .  .  .  .  .  ValuePos: 4:10
+	//     37  .  .  .  .  .  .  .  .  .  Kind: STRING
+	//     38  .  .  .  .  .  .  .  .  .  Value: "\"Hello, World!\""\n
+	//     39  .  .  .  .  .  .  .  .  }\n
+	//     40  .  .  .  .  .  .  .  }\n
+	//     41  .  .  .  .  .  .  .  Ellipsis: -\n
+	//     42  .  .  .  .  .  .  .  Rparen: 4:25\n
+	//     43  .  .  .  .  .  .  }\n
+	//     44  .  .  .  .  .  }\n
+	//     45  .  .  .  .  }\n
+	//     46  .  .  .  .  Rbrace: 5:1\n
+	//     47  .  .  .  }\n
+	//     48  .  .  }\n
+	//     49  .  }\n
+	//     50  .  Scope: *ast.Scope {\n
+	//     51  .  .  Objects: map[string]*ast.Object (len = 1) {\n
+	//     52  .  .  .  "main": *(obj @ 11)\n+	//     53  .  .  }\n+	//     54  .  }\n+	//     55  .  Unresolved: []*ast.Ident (len = 1) {\n+	//     56  .  .  0: *(obj @ 29)\n+	//     57  .  }\n+	//     58  }\n+}

コアとなるコードの解説

追加された example_test.go ファイルは、go/ast パッケージの機能を実演するための2つの Example 関数を含んでいます。

  1. ExampleInspect(): この関数は、ast.Inspect を使用してGoコードのASTを走査し、特定のノード(識別子と基本的なリテラル)を抽出してその位置と値を出力する方法を示しています。

    • parser.ParseFile でソースコードからASTを生成します。
    • ast.Inspect のコールバック関数内で、型アサーション n.(type) を使ってノードの型を *ast.BasicLit または *ast.Ident に絞り込みます。
    • fset.Position(n.Pos()) を使って、ノードがソースコードのどの位置にあるかを正確に取得し、出力に含めます。
    • これにより、Goコード内の個々の要素がAST上でどのように表現され、どのようにアクセスできるかが視覚的に理解できます。
  2. ExamplePrint(): この関数は、ast.Print を使用してGoコードのASTをデバッグ目的で整形して出力する方法を示しています。

    • 同様に parser.ParseFile でASTを生成します。
    • ast.Print(fset, f) を呼び出すだけで、ASTの完全な階層構造と各ノードの詳細情報(型、フィールド、値、ソースコード上の位置)が標準出力に表示されます。
    • この出力は、ASTの内部構造を深く理解したい場合や、特定のASTノードが期待通りに構築されているかを確認したい場合に非常に有用です。

これらの例は、go/ast パッケージの基本的なAPIを効果的に使用するための実践的なガイドラインを提供し、Goの静的解析ツールやコード生成ツールを開発する際の出発点となります。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (go/ast, go/parser, go/token パッケージ)
  • Go言語のテストに関するドキュメント (Example関数について)
  • 抽象構文木 (AST) に関する一般的な情報
  • Go Gerrit Code Review (コミットメッセージ内の golang.org/cl リンク)

[インデックス 12209] ファイルの概要

このコミットは、Go言語の標準ライブラリである go/ast パッケージに、ast.Print および ast.Inspect 関数の使用例を示すテストファイル src/pkg/go/ast/example_test.go を追加するものです。これにより、Goプログラムの抽象構文木(AST)を操作・検査する方法が具体的に示され、開発者がこれらの機能を理解しやすくなります。

コミット

commit 34e60a81d5b9a3c18d634d89acea9384605f4916
Author: Robert Griesemer <gri@golang.org>
Date:   Fri Feb 24 13:44:36 2012 -0800

    go/ast: examples for ast.Print, ast.Inspect
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5700057

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/34e60a81d5b9a3c18d634d89acea9384605f4916

元コミット内容

go/ast: examples for ast.Print, ast.Inspect

このコミットは、go/ast パッケージの ast.Print 関数と ast.Inspect 関数の使用例を追加します。

変更の背景

Go言語の go/ast パッケージは、Goプログラムのソースコードを解析して抽象構文木(AST)を構築し、そのASTを操作するための機能を提供します。しかし、これらの強力な機能は、特に初心者にとっては直感的に理解しにくい場合があります。ast.Print はASTをデバッグ目的で整形して出力するのに役立ち、ast.Inspect はASTを走査して特定のノードを検査するのに使用されます。

このコミットの背景には、これらの重要な関数の使い方を明確に示し、開発者がGoのツールや静的解析ツールを構築する際に go/ast パッケージをより効果的に活用できるようにするという意図があります。具体的な使用例を提供することで、学習曲線が緩和され、パッケージの採用が促進されます。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念と標準ライブラリの知識が必要です。

  1. 抽象構文木 (Abstract Syntax Tree, AST): ASTは、プログラミング言語のソースコードの抽象的な構文構造を木構造で表現したものです。各ノードはソースコードの構成要素(変数、関数、式、文など)を表し、その子ノードはそれらの構成要素の内部構造を示します。コンパイラやリンター、コードフォーマッターなどのツールは、ソースコードをASTに変換し、そのASTを操作することで様々な処理を行います。

  2. go/parser パッケージ: go/parser パッケージは、Go言語のソースコードを解析し、そのASTを生成するための機能を提供します。parser.ParseFile 関数は、指定されたファイルまたは文字列からGoのソースコードを読み込み、*ast.File 型のASTルートノードを返します。

  3. go/token パッケージ: go/token パッケージは、Goソースコード内の位置情報(ファイル名、行番号、列番号など)を管理するための型と関数を提供します。token.FileSet は、複数のファイルにわたる位置情報を一元的に管理するために使用されます。ASTノードは、ソースコード内の対応する位置への参照を token.Pos 型で保持します。

  4. go/ast パッケージ: go/ast パッケージは、GoプログラムのASTを表現する型(ast.Node インターフェースとその実装型)と、ASTを操作するためのユーティリティ関数を提供します。

    • ast.Node: AST内のすべてのノードが実装するインターフェースです。
    • ast.Print(fset *token.FileSet, x interface{}): ASTの構造をデバッグ目的で整形して標準出力に表示する関数です。fset は位置情報を解決するために使用され、x は表示したいASTノード(通常は *ast.File)です。
    • ast.Inspect(node ast.Node, f func(ast.Node) bool): ASTを深さ優先で走査(トラバース)するための関数です。引数 f は、各ノードが訪問されるたびに呼び出されるコールバック関数です。このコールバック関数が false を返すと、そのノードの子孫の走査は停止します。これにより、特定の種類のノードを検索したり、ASTの特定の部分を処理したりすることができます。
  5. Goのテストにおける Example 関数: Goのテストフレームワークでは、Example 関数という特別な形式のテスト関数をサポートしています。これらの関数は、コードの実行例を示すために使用され、その出力はコメントとして // output: の後に記述されます。go test コマンドは、この出力コメントと実際の実行結果を比較し、一致しない場合はテスト失敗とします。これにより、コードのドキュメントとテストを同時に行うことができ、例が常に最新かつ正確であることを保証できます。

技術的詳細

このコミットは、src/pkg/go/ast/example_test.go という新しいファイルを追加することで、go/ast パッケージの ast.Inspectast.Print 関数の具体的な使用方法をデモンストレーションしています。

ExampleInspect() 関数

ExampleInspect() 関数は、GoプログラムのASTを検査する方法を示しています。

  1. ソースコードの準備: src 変数に、検査対象となるGoのソースコード(package p; const c = 1.0; var X = f(3.14)*2 + c;)が文字列リテラルとして定義されています。

  2. ASTの生成: token.NewFileSet() で新しい FileSet が作成され、parser.ParseFile(fset, "src.go", src, 0) を使用して、このソースコードからASTが生成されます。parser.ParseFile は、ソースコードを解析し、その結果として *ast.File 型のASTルートノードを返します。

  3. ASTの検査 (ast.Inspect): ast.Inspect(f, func(n ast.Node) bool { ... }) が呼び出され、生成されたAST f が走査されます。無名関数が各ASTノード n に対して呼び出されます。

    • この無名関数内では、switch x := n.(type) を使用して、現在のノード n の具体的な型をチェックしています。
    • もしノードが *ast.BasicLit(基本的なリテラル、例: 1.0, 2, 3.14)または *ast.Ident(識別子、例: p, c, X, f)であれば、その値または名前が抽出されます。
    • 抽出された値は、fset.Position(n.Pos()) を使ってソースコード内の正確な位置情報(ファイル名、行番号、列番号)と共に fmt.Printf で出力されます。
    • コールバック関数は常に true を返すため、ASTのすべてのノードが再帰的に走査されます。
  4. 期待される出力: // output: コメントブロックには、この例を実行した際に期待される出力が記述されており、go test コマンドによって検証されます。出力は、ソースコード内の各識別子とリテラルの位置と値を示しています。

ExamplePrint() 関数

ExamplePrint() 関数は、デバッグ目的でASTを整形して出力する方法を示しています。

  1. ソースコードの準備: src 変数に、ASTとして出力したいGoのソースコード(package main; func main() { println("Hello, World!") })が定義されています。

  2. ASTの生成: token.NewFileSet()parser.ParseFile(fset, "", src, 0) を使用して、このソースコードからASTが生成されます。

  3. ASTの出力 (ast.Print): ast.Print(fset, f) が呼び出され、生成されたAST fFileSet fset を使って整形され、標準出力に詳細な構造として出力されます。この出力は、ASTの各ノードの型、フィールド、値、そしてソースコード内の位置情報(行番号と列番号)を階層的に示します。

  4. 期待される出力: // output: コメントブロックには、ast.Print によって生成されるASTの構造が詳細に記述されています。これは、ASTの内部構造を理解し、デバッグする上で非常に役立ちます。

これらの例は、go/ast パッケージが提供するAST操作の基本的なパターンを明確に示しており、Goの静的解析やコード生成ツール開発の出発点として機能します。

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

このコミットによって追加されたファイルは src/pkg/go/ast/example_test.go です。

--- /dev/null
+++ b/src/pkg/go/ast/example_test.go
@@ -0,0 +1,136 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+)
+
+// This example demonstrates how to inspect the AST of a Go program.
+func ExampleInspect() {
+	// src is the input for which we want to inspect the AST.
+	src := `
+package p
+const c = 1.0
+var X = f(3.14)*2 + c
+`
+
+	// Create the AST by parsing src.
+	fset := token.NewFileSet() // positions are relative to fset
+	f, err := parser.ParseFile(fset, "src.go", src, 0)
+	if err != nil {
+		panic(err)
+	}
+
+	// Inspect the AST and print all identifiers and literals.
+	ast.Inspect(f, func(n ast.Node) bool {
+		var s string
+		switch x := n.(type) {
+		case *ast.BasicLit:
+			s = x.Value
+		case *ast.Ident:
+			s = x.Name
+		}
+		if s != "" {
+			fmt.Printf("%s:\t%s\n", fset.Position(n.Pos()), s)
+		}
+		return true
+	})
+
+	// output:
+	// src.go:2:9:	p
+	// src.go:3:7:	c
+	// src.go:3:11:	1.0
+	// src.go:4:5:	X
+	// src.go:4:9:	f
+	// src.go:4:11:	3.14
+	// src.go:4:17:	2
+	// src.go:4:21:	c
+}
+
+// This example shows what an AST looks like when printed for debugging.
+func ExamplePrint() {
+	// src is the input for which we want to print the AST.
+	src := `
+package main
+func main() {
+	println("Hello, World!")
+}
+`
+
+	// Create the AST by parsing src.
+	fset := token.NewFileSet() // positions are relative to fset
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		panic(err)
+	}
+
+	// Print the AST.
+	ast.Print(fset, f)
+
+	// output:
+	//      0  *ast.File {
+	//      1  .  Package: 2:1
+	//      2  .  Name: *ast.Ident {
+	//      3  .  .  NamePos: 2:9
+	//      4  .  .  Name: "main"
+	//      5  .  }
+	//      6  .  Decls: []ast.Decl (len = 1) {
+	//      7  .  .  0: *ast.FuncDecl {
+	//      8  .  .  .  Name: *ast.Ident {
+	//      9  .  .  .  .  NamePos: 3:6
+	//     10  .  .  .  .  Name: "main"
+	//     11  .  .  .  .  Obj: *ast.Object {
+	//     12  .  .  .  .  .  Kind: func
+	//     13  .  .  .  .  .  Name: "main"
+	//     14  .  .  .  .  .  Decl: *(obj @ 7)
+	//     15  .  .  .  .  }
+	//     16  .  .  .  }
+	//     17  .  .  .  Type: *ast.FuncType {
+	//     18  .  .  .  .  Func: 3:1
+	//     19  .  .  .  .  Params: *ast.FieldList {
+	//     20  .  .  .  .  .  Opening: 3:10
+	//     21  .  .  .  .  .  Closing: 3:11
+	//     22  .  .  .  .  }
+	//     23  .  .  .  }
+	//     24  .  .  .  Body: *ast.BlockStmt {
+	//     25  .  .  .  .  Lbrace: 3:13
+	//     26  .  .  .  .  List: []ast.Stmt (len = 1) {
+	//     27  .  .  .  .  .  0: *ast.ExprStmt {
+	//     28  .  .  .  .  .  .  X: *ast.CallExpr {
+	//     29  .  .  .  .  .  .  .  Fun: *ast.Ident {
+	//     30  .  .  .  .  .  .  .  .  NamePos: 4:2
+	//     31  .  .  .  .  .  .  .  .  Name: "println"
+	//     32  .  .  .  .  .  .  .  }
+	//     33  .  .  .  .  .  .  .  Lparen: 4:9
+	//     34  .  .  .  .  .  .  .  Args: []ast.Expr (len = 1) {
+	//     35  .  .  .  .  .  .  .  .  0: *ast.BasicLit {
+	//     36  .  .  .  .  .  .  .  .  .  ValuePos: 4:10
+	//     37  .  .  .  .  .  .  .  .  .  Kind: STRING
+	//     38  .  .  .  .  .  .  .  .  .  Value: "\"Hello, World!\""\n
+	//     39  .  .  .  .  .  .  .  .  }\n
+	//     40  .  .  .  .  .  .  .  }\n
+	//     41  .  .  .  .  .  .  .  Ellipsis: -\n
+	//     42  .  .  .  .  .  .  .  Rparen: 4:25\n
+	//     43  .  .  .  .  .  .  }\n
+	//     44  .  .  .  .  .  }\n
+	//     45  .  .  .  .  }\n
+	//     46  .  .  .  .  Rbrace: 5:1\n
+	//     47  .  .  .  }\n
+	//     48  .  .  }\n
+	//     49  .  }\n
+	//     50  .  Scope: *ast.Scope {\n
+	//     51  .  .  Objects: map[string]*ast.Object (len = 1) {\n
+	//     52  .  .  .  "main": *(obj @ 11)\n+	//     53  .  .  }\n+	//     54  .  }\n+	//     55  .  Unresolved: []*ast.Ident (len = 1) {\n+	//     56  .  .  0: *(obj @ 29)\n+	//     57  .  }\n+	//     58  }\n+}

コアとなるコードの解説

追加された example_test.go ファイルは、go/ast パッケージの機能を実演するための2つの Example 関数を含んでいます。

  1. ExampleInspect(): この関数は、ast.Inspect を使用してGoコードのASTを走査し、特定のノード(識別子と基本的なリテラル)を抽出してその位置と値を出力する方法を示しています。

    • parser.ParseFile でソースコードからASTを生成します。
    • ast.Inspect のコールバック関数内で、型アサーション n.(type) を使ってノードの型を *ast.BasicLit または *ast.Ident に絞り込みます。
    • fset.Position(n.Pos()) を使って、ノードがソースコードのどの位置にあるかを正確に取得し、出力に含めます。
    • これにより、Goコード内の個々の要素がAST上でどのように表現され、どのようにアクセスできるかが視覚的に理解できます。
  2. ExamplePrint(): この関数は、ast.Print を使用してGoコードのASTをデバッグ目的で整形して出力する方法を示しています。

    • 同様に parser.ParseFile でASTを生成します。
    • ast.Print(fset, f) を呼び出すだけで、ASTの完全な階層構造と各ノードの詳細情報(型、フィールド、値、ソースコード上の位置)が標準出力に表示されます。
    • この出力は、ASTの内部構造を深く理解したい場合や、特定のASTノードが期待通りに構築されているかを確認したい場合に非常に有用です。

これらの例は、go/ast パッケージの基本的なAPIを効果的に使用するための実践的なガイドラインを提供し、Goの静的解析ツールやコード生成ツールを開発する際の出発点となります。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (go/ast, go/parser, go/token パッケージ)
  • Go言語のテストに関するドキュメント (Example関数について)
  • 抽象構文木 (AST) に関する一般的な情報
  • Go Gerrit Code Review (コミットメッセージ内の golang.org/cl リンク)