[インデックス 1008] ファイルの概要
このコミットは、Go言語のコンパイラ(gc
)の文法定義ファイルである src/cmd/gc/go.y
に対する変更です。具体的には、構造体における埋め込み型(embedded types)に「アノテーション(annotations)」を付与できるようにするための構文解析規則の追加・修正が行われています。これにより、埋め込み型に対して追加のメタデータや属性を関連付けることが可能になります。
コミット
- コミットインデックス: 1008
- コミットハッシュ:
f2b1536328b2135cd18c515d057d8ead25496322
- Author: Russ Cox rsc@golang.org
- Date: Thu Oct 30 15:29:55 2008 -0700
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f2b1536328b2135cd18c515d057d8ead25496322
元コミット内容
annotations on embedded types
R=ken
OCL=18179
CL=18179
変更の背景
Go言語は、その設計初期段階からシンプルさと効率性を重視していました。構造体の埋め込み型は、Goのユニークな特徴の一つであり、他の言語における継承に似た機能を提供しつつ、よりシンプルなコンポジション(合成)のメカニズムを実現します。
このコミットが行われた2008年10月は、Go言語がまだ一般に公開される前の非常に初期の段階でした。この時期のGoコンパイラは、gc
(Go Compiler)という名称で開発されており、その構文解析はYacc/Bisonによって生成されたパーサーが担っていました。
「annotations on embedded types」というコミットメッセージは、埋め込み型に対して何らかの追加情報(アノテーション)を付与する機能の必要性を示唆しています。これは、例えば構造体タグ(struct tags)のような機能の初期実装、あるいはそれに類するメタデータ付与メカニズムの導入を意図していた可能性があります。構造体タグは、Go言語においてフィールドにJSONエンコーディングやデータベースマッピングなどの情報を付与するために広く利用されており、このコミットはそのような機能の基礎を築くものだったと考えられます。
前提知識の解説
1. Go言語の構造体と埋め込み型 (Embedded Types)
Go言語の構造体は、異なる型のフィールドをまとめるための複合データ型です。埋め込み型は、Goの構造体が持つ特徴的な機能で、ある構造体の中に別の構造体(またはポインタ)をフィールド名なしで宣言することで、その埋め込まれた構造体のフィールドやメソッドを、外側の構造体が直接持っているかのようにアクセスできるようにするものです。これは、他のオブジェクト指向言語における継承に似ていますが、Goでは「コンポジション(合成)による再利用」を推奨する設計思想に基づいています。
例:
type Base struct {
ID int
Name string
}
type User struct {
Base // Base型を埋め込み
Email string
}
func main() {
u := User{Base: Base{ID: 1, Name: "Alice"}, Email: "alice@example.com"}
fmt.Println(u.Name) // Alice (Baseのフィールドに直接アクセス)
}
2. Yacc/Bison と go.y
go.y
ファイルは、Go言語のコンパイラ gc
における構文解析器の定義ファイルです。.y
拡張子はYacc(Yet Another Compiler Compiler)またはBison(YaccのGNU版)の入力ファイルであることを示します。Yacc/Bisonは、BNF(Backus-Naur Form)に似た文法規則を記述することで、プログラミング言語の構文解析器を自動生成するツールです。
go.y
には、Go言語のキーワード、演算子、識別子、文、式などの構文規則が定義されており、コンパイラはこれらの規則に基づいてソースコードを解析し、抽象構文木(AST)を構築します。
- 規則の形式:
非終端記号: 規則本体 { アクション }
非終端記号
: 構文の構成要素(例:structdcl
は構造体宣言)。規則本体
: その非終端記号がどのように構成されるかを示す終端記号(トークン)や非終端記号の並び。アクション
: 規則がマッチしたときに実行されるC言語のコード。通常、ASTノードの構築などが行われます。$$
は現在の規則のセマンティック値、$1
,$2
などは規則本体の各要素のセマンティック値を参照します。
3. アノテーション (Annotations)
プログラミングにおけるアノテーションは、コード自体には直接的な影響を与えないが、コンパイラ、ツール、フレームワークなどが利用するためのメタデータ(付加情報)をコード要素(クラス、メソッド、フィールドなど)に付与する仕組みです。Go言語では、構造体フィールドに付与される「構造体タグ(struct tags)」がこれに該当します。構造体タグは、リフレクションAPIを通じて実行時にアクセスでき、JSONエンコーディング/デコーディング、ORMマッピング、バリデーションなどに利用されます。
このコミットの時点では、Goの構造体タグが現在の形になる前の、より一般的な「アノテーション」の概念を埋め込み型に適用しようとしていた可能性があります。
技術的詳細
このコミットの目的は、Go言語の構造体定義において、埋め込み型に続く形で追加の「アノテーション」を記述できるように、コンパイラの構文解析規則を拡張することです。
変更前は、埋め込み型は単に型名(またはポインタ型)を記述するだけでした。しかし、この変更により、埋め込み型名の後に oliteral
(おそらく「optional literal」の略で、文字列リテラルなどのアノテーションを表す)を記述できるようになります。
具体的には、structdcl
(構造体宣言)および hidden_structdcl
(内部的な構造体宣言)の規則が修正されています。
-
embed
規則の変更:- 変更前:
embed
または* embed
の形式で埋め込み型を認識していました。 - 変更後:
embed oliteral
または* embed oliteral
の形式を認識するように拡張されました。これにより、埋め込み型の後にoliteral
が続く構文が有効になります。
- 変更前:
-
hidden_type
規則の変更:- 変更前:
? hidden_type
の形式で内部的な型を認識していました。 - 変更後:
? hidden_type oliteral
の形式を認識するように拡張されました。これも同様に、内部的な型定義にアノテーションを付与する可能性を示唆しています。
- 変更前:
これらの変更は、Go言語の構文解析器が、埋め込み型宣言の直後に続く文字列リテラルなどの情報を、その埋め込み型に関連するメタデータとして解釈し、抽象構文木(AST)の対応するノード($$
)の val
フィールドに格納するように指示しています。val
フィールドは、Goのコンパイラ内部で、リテラル値やその他の付加情報を保持するために使用されることが多いです。
この機能は、現在のGo言語における構造体タグの原型、あるいはそれに近い機能の導入に向けた初期ステップであったと推測されます。構造体タグは、フィールド名の後にバッククォートで囲まれた文字列リテラルとして記述されますが、このコミットでは埋め込み型に対して同様のメカニズムを導入しようとしていたと考えられます。
コアとなるコードの変更箇所
変更は src/cmd/gc/go.y
ファイルに集中しています。
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -1395,11 +1395,16 @@ structdcl:
$$->type = $2;
$$->val = $3;
}
-| embed
-| '*' embed
- {
- $$ = $1;
- $$->type = ptrto($$->type);
-+ embed oliteral
-+ {
-+ $$ = $1;
-+ $$->val = $2;
-+ }
-+| '*' embed oliteral
- {
- $$ = $2;
- $$->type = ptrto($$->type);
-+ $$->val = $3;
- }
-
embed:
@@ -1898,13 +1903,14 @@ hidden_structdcl:
$$->type = $2;
$$->val = $3;
}
-| '?' hidden_type
- {
- if(isptr[$2->etype]) {
- $$ = embedded($2->type->sym);
- $$->type = ptrto($$->type);
- } else
- $$ = embedded($2->sym);
-+ '?' hidden_type oliteral
- {
- if(isptr[$2->etype]) {
- $$ = embedded($2->type->sym);
- $$->type = ptrto($$->type);
- } else
- $$ = embedded($2->sym);
-+ $$->val = $3;
- }
-
hidden_interfacedcl:
コアとなるコードの解説
structdcl
規則の変更
structdcl
は構造体フィールドの宣言を扱う規則です。
変更前:
structdcl:
// ... 既存のフィールド宣言規則 ...
| embed
| '*' embed
{
$$ = $1; // embed のセマンティック値をそのまま使う
$$->type = ptrto($$->type); // ポインタ埋め込みの場合、型をポインタ型に変換
}
この部分では、embed
(埋め込み型)または * embed
(埋め込み型へのポインタ)という構文を認識していました。$$
には埋め込み型の情報が格納されます。
変更後:
structdcl:
// ... 既存のフィールド宣言規則 ...
| embed oliteral
{
$$ = $1; // embed のセマンティック値をそのまま使う
$$->val = $2; // oliteral のセマンティック値を $$->val に格納
}
| '*' embed oliteral
{
$$ = $2; // embed のセマンティック値をそのまま使う
$$->type = ptrto($$->type); // ポインタ埋め込みの場合、型をポインタ型に変換
$$->val = $3; // oliteral のセマンティック値を $$->val に格納
}
この変更により、embed
または * embed
の後に oliteral
(おそらく文字列リテラルなどのアノテーション)が続く構文が追加されました。
embed oliteral
: 埋め込み型$1
の後にアノテーション$2
が続く場合。$2
の値が$$->val
に設定されます。'*' embed oliteral
: 埋め込み型へのポインタ$2
の後にアノテーション$3
が続く場合。同様に$3
の値が$$->val
に設定されます。
これにより、コンパイラは埋め込み型だけでなく、それに付随するアノテーション情報もASTに含めることができるようになります。
hidden_structdcl
規則の変更
hidden_structdcl
は、Go言語の内部的な構造体宣言(例えば、インターフェースのメソッドシグネチャの内部表現など)を扱う規則です。
変更前:
hidden_structdcl:
// ... 既存の規則 ...
| '?' hidden_type
{
if(isptr[$2->etype]) {
$$ = embedded($2->type->sym);
$$->type = ptrto($$->type);
} else
$$ = embedded($2->sym);
}
この部分では、? hidden_type
という構文を認識していました。これは、内部的な型が埋め込み型として扱われる場合の処理です。
変更後:
hidden_structdcl:
// ... 既存の規則 ...
| '?' hidden_type oliteral
{
if(isptr[$2->etype]) {
$$ = embedded($2->type->sym);
$$->type = ptrto($$->type);
} else
$$ = embedded($2->sym);
$$->val = $3; // oliteral のセマンティック値を $$->val に格納
}
同様に、'?' hidden_type
の後に oliteral
が続く構文が追加されました。$3
の値が $$->val
に設定されます。これは、内部的な型定義においてもアノテーションのようなメタデータを付与する可能性を考慮した変更と考えられます。
これらの変更は、Go言語のコンパイラが、埋め込み型や内部的な型定義に付随する追加のメタデータを構文解析時に捕捉し、後続のコンパイルフェーズで利用できるようにするための基盤を構築するものです。
関連リンク
参考にした情報源リンク
- Go言語の公式ドキュメント (構造体、埋め込み型、構造体タグに関する情報)
- Yacc/Bison のドキュメント (構文解析器の仕組みに関する情報)
- Go言語の初期開発に関するブログ記事やメーリングリストのアーカイブ (2008年頃のGo言語の状況に関する情報)
- Go言語のソースコード (特に
src/cmd/gc
ディレクトリ内のファイル) - Go言語の構造体タグについて (例: JSON)
- Go言語の埋め込み型について
- Yacc/Bison のチュートリアル
- Go言語の歴史に関する情報