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

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

このコミットは、Goコンパイラ(cmd/gc)におけるスライス構文の変更に関するものです。具体的には、x[i:j:k] および x[:j:k] という3インデックススライス構文が、Go 1.2のリリースで利用可能になるように、コンパイラのパーサー部分を修正しています。

コミット

commit 8cd6341cf8c3179966f708b267fc8cee4afa774f
Author: Russ Cox <rsc@golang.org>
Date:   Wed Sep 11 14:55:46 2013 -0400

    cmd/gc: allow x[i:j:k] (and x[:j:k]) into the release
    
    R=ken2
    CC=golang-dev
    https://golang.org/cl/13512053

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

https://github.com/golang/go/commit/8cd6341cf8c3179966f708b267fc8cee4afa774f

元コミット内容

cmd/gc: allow x[i:j:k] (and x[:j:k]) into the release

このコミットの目的は、Goコンパイラが3インデックススライス構文(x[i:j:k] および x[:j:k])をGo 1.2リリースで正式にサポートするようにすることです。以前は、この機能は実験的なものとして扱われ、リリース版ではコンパイルエラーとなるように制限されていました。

変更の背景

Go言語では、スライスは配列をラップする動的なビューであり、a[low:high] の形式で作成されます。Go 1.2より前は、この2インデックス形式のみがサポートされていました。しかし、スライスの「容量(capacity)」を明示的に制御したいというニーズがありました。

3インデックススライス構文 a[low:high:max] は、この容量制御のニーズに応えるために導入されました。ここで、low は新しいスライスの開始インデックス、high は新しいスライスの長さの終端インデックス(排他的)、そして max は新しいスライスの容量の終端インデックス(排他的)を意味します。これにより、新しいスライスの長さは high - low、容量は max - low となります。

この機能は、Go 1.2のリリースに向けて開発が進められていましたが、安定性や互換性の問題がないことを確認するため、一時的にリリース版での使用が制限されていました。このコミットは、その制限を解除し、3インデックススライス構文をGo 1.2の正式機能として組み込むためのものです。

前提知識の解説

Go言語のスライス

Go言語のスライスは、配列の上に構築された軽量なデータ構造です。スライスは、基になる配列の一部を参照し、その長さ(len)と容量(cap)を持ちます。

  • 長さ (Length): スライスに含まれる要素の数。len(s) で取得できます。
  • 容量 (Capacity): スライスの最初の要素から基になる配列の末尾までの要素の数。cap(s) で取得できます。

スライスは、make([]T, length, capacity) または既存の配列やスライスから array[low:high] の形式で作成できます。

2インデックススライス a[low:high]

これはGo言語で最も一般的なスライス構文です。

  • low: 新しいスライスの開始インデックス(包含)。省略された場合は 0 とみなされます。
  • high: 新しいスライスの終了インデックス(排他)。省略された場合は基になる配列/スライスの長さとみなされます。 新しいスライスの長さは high - low となり、容量は基になる配列/スライスの cap(array) - low となります。

3インデックススライス a[low:high:max]

Go 1.2で導入されたこの構文は、新しいスライスの容量を明示的に制限することを可能にします。

  • low: 新しいスライスの開始インデックス(包含)。
  • high: 新しいスライスの長さの終了インデックス(排他)。新しいスライスの長さは high - low
  • max: 新しいスライスの容量の終了インデックス(排他)。新しいスライスの容量は max - low

この max インデックスは、low <= high <= max <= cap(array) の関係を満たす必要があります。 3インデックススライスを使用する主な利点は、新しいスライスの容量を制限することで、append 操作が予期せぬ副作用(基になる配列の変更)を引き起こすのを防ぐことができる点です。容量が制限されているスライスに要素を追加しようとすると、容量が足りない場合は新しい基になる配列が割り当てられ、元の配列への影響がなくなります。

Bison (Yacc)

Goコンパイラの一部である cmd/gc は、Go言語のソースコードを解析するためにパーサーを使用しています。このパーサーは、Bison(GNU Parser Generator)によって生成されたものです。Bisonは、文法定義ファイル(通常は .y 拡張子を持つ)をC言語のソースコード(通常は y.tab.cy.tab.h)に変換します。このC言語のコードが、入力ストリーム(Goのソースコード)を解析し、構文木を構築する役割を担います。

  • go.y: Go言語の文法規則を定義するBisonの入力ファイル。
  • y.tab.c: go.y からBisonによって生成されるC言語のパーサー実装ファイル。
  • y.tab.h: go.y からBisonによって生成されるヘッダーファイルで、トークン定義などが含まれる。

技術的詳細

このコミットの技術的な核心は、Goコンパイラのパーサーが3インデックススライス構文を認識し、それに対するコンパイル時の制限を解除することにあります。

変更前は、src/cmd/gc/go.y ファイル内で、3インデックススライス構文 (pexpr '[' oexpr ':' oexpr ':' oexpr ']') が解析された際に、以下のようなコードブロックが存在していました。

// Make sure we don't accidentally release this experimental feature.
// http://golang.org/s/go12slice.
if(isrelease < 0)
	isrelease = strstr(getgoversion(), "release") != nil;
if(isrelease)
	yyerror("3-index slice not available in release");

このコードは、コンパイラが「リリース版」としてビルドされているかどうかを getgoversion() の結果から判断し、もしリリース版であれば「3インデックススライスはリリース版では利用できません」というエラーを発生させていました。isrelease という静的変数が、このチェックを一度だけ行うためのフラグとして使用されていました。

このコミットでは、この制限を解除するために、上記のコードブロックが go.y から完全に削除されています。これにより、パーサーは3インデックススライス構文を通常の有効な構文として扱い、エラーを発生させなくなります。

また、src/cmd/gc/y.tab.csrc/cmd/gc/y.tab.h にも大量の変更が見られますが、これは主にBisonのバージョンアップ(2.5から2.3へのダウングレード、または生成されたコードの変更)によるものです。コミットメッセージの「cmd/gc: allow x[i:j:k] (and x[:j:k]) into the release」という説明から、この変更の主目的は go.y からの実験的機能の制限解除であり、y.tab.cy.tab.h の変更は、go.y の変更に伴うBisonの再生成の結果であると考えられます。特に、y.tab.c の変更は、Bisonが生成するコードの内部構造やコメント、マクロ定義などの変更を反映している可能性が高いです。

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

src/cmd/gc/go.y

--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -23,8 +23,6 @@
 #include <libc.h>\n #include "go.h"\n \n-static int isrelease = -1;\n-\n static void fixlbrace(int);\n %}\n %union\t{\n@@ -957,13 +955,6 @@ pexpr_no_paren:\n \t}\n |\tpexpr '[' oexpr ':' oexpr ':' oexpr ']'\n \t{\n-\t\t// Make sure we don't accidentally release this experimental feature.\n-\t\t// http://golang.org/s/go12slice.\n-\t\tif(isrelease < 0)\n-\t\t\tisrelease = strstr(getgoversion(), "release") != nil;\n-\t\tif(isrelease)\n-\t\t\tyyerror("3-index slice not available in release");\n-\n \t\tif($5 == N)\n \t\t\tyyerror("middle index required in 3-index slice");\n \t\tif($7 == N)\n```

### `src/cmd/gc/y.tab.c` および `src/cmd/gc/y.tab.h`

これらのファイルはBisonによって生成されるため、`go.y` の変更に伴い、全体的に大幅な変更(挿入と削除)が行われています。特に、`y.tab.c` では1875行の追加と1276行の削除があり、これはBisonのバージョンや生成オプションの変更、または`go.y`の変更が生成コードに大きく影響したことを示しています。具体的な変更内容は、Bisonの内部実装に関するものであり、Go言語の構文解析ロジックそのものというよりは、パーサーの基盤部分の更新が主です。

## コアとなるコードの解説

`src/cmd/gc/go.y` の変更がこのコミットの核心です。

1.  **`static int isrelease = -1;` の削除**:
    この変数は、コンパイラがリリース版であるかどうかを一度だけチェックし、その結果をキャッシュするために使用されていました。この変数の削除は、もはやリリース版かどうかをチェックする必要がないことを意味します。

2.  **3インデックススライス構文の制限コードの削除**:
    `pexpr '[' oexpr ':' oexpr ':' oexpr ']'` という文法規則に対応するアクションブロックから、以下のコードが削除されました。

    ```go
    // Make sure we don't accidentally release this experimental feature.
    // http://golang.org/s/go12slice.
    if(isrelease < 0)
    	isrelease = strstr(getgoversion(), "release") != nil;
    if(isrelease)
    	yyerror("3-index slice not available in release");
    ```
    このコードは、Goコンパイラがリリース版としてビルドされている場合に、3インデックススライス構文が使用されるとコンパイルエラーを発生させる役割を担っていました。この削除により、3インデックススライスはGo 1.2の正式な機能として、リリース版でもエラーなく使用できるようになりました。

残りのエラーチェック(`$5 == N` や `$7 == N`)は、3インデックススライス構文における中間インデックスと最終インデックスが必須であるという文法的な制約に関するものであり、これは引き続き有効です。

`y.tab.c` と `y.tab.h` の変更は、`go.y` の変更を反映してBisonがパーサーコードを再生成した結果です。これらのファイルは自動生成されるため、手動で編集されることは稀です。変更の大部分は、Bisonのバージョンアップ(またはダウングレード)や、生成されるコードのテンプレートの変更によるものと考えられます。

## 関連リンク

*   Go 1.2 Release Notes: [https://go.dev/doc/go1.2](https://go.dev/doc/go1.2) (3-index slices are mentioned under "Language changes")
*   Go Slices: usage and internals: [https://go.dev/blog/slices](https://go.dev/blog/slices) (公式ブログ記事でスライスの詳細が解説されています)

## 参考にした情報源リンク

*   [https://github.com/golang/go/commit/8cd6341cf8c3179966f708b267fc8cee4afa774f](https://github.com/golang/go/commit/8cd6341cf8c31779966f708b267fc8cee4afa774f)
*   Web search results for "Go 3-index slice history experimental release" (Google Search)
    *   [https://ardanlabs.com/blog/2013/09/go-slices-usage-and-internals.html](https://ardanlabs.com/blog/2013/09/go-slices-usage-and-internals.html)
    *   [https://stackoverflow.com/questions/28749900/what-is-the-purpose-of-the-third-index-in-go-slices](https://stackoverflow.com/questions/28749900/what-is-the-purpose-of-the-third-index-in-go-slices)
    *   [https://go.dev/doc/go1.2](https://go.dev/doc/go1.2)
    *   [https://go.dev/blog/slices](https://go.dev/blog/slices)