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

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

このコミットは、Go言語の初期開発段階における内部的な変更を記録したものです。gosrcディレクトリ内のコードが再びコンパイルできるようにするための修正と、保留中の変更のチェックインが含まれています。特に、このコードベースは当時のGo言語の既存の仕様とは完全に一致しないものの、大規模なコードベースであり、コンパイル可能であることが強調されています。将来的にはこのコードは廃止される予定であるとも述べられています。

コミット

commit af065a0c7783d33e01e75f43e07db681dadbf21e
Author: Robert Griesemer <gri@golang.org>
Date:   Tue Jan 6 16:26:45 2009 -0800

    - make code in gosrc compile again, check in all pending changes
      (this code doesn't match the existing language at this point,
      but it's a large code base which compiles - will eventually go
      away)
    - enable compilation of it again in run.bash
    
    R=r
    DELTA=1147  (534 added, 311 deleted, 302 changed)
    OCL=22176
    CL=22176

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

https://github.com/golang/go/commit/af065a0c7783d33e01e75f43e07db681dadbf21e

元コミット内容

- make code in gosrc compile again, check in all pending changes
  (this code doesn't match the existing language at this point,
  but it's a large code base which compiles - will eventually go
  away)
- enable compilation of it again in run.bash

変更の背景

このコミットは、Go言語の初期開発フェーズ、具体的には2009年1月に行われたものです。コミットメッセージから、gosrcディレクトリ内のコードが一時的にコンパイルできない状態になっていたことが伺えます。Go言語は2007年後半にGoogleで開発が始まり、2009年11月に一般公開されました。このコミットは、その公開前の内部開発段階におけるスナップショットであり、Robert Griesemer氏(Go言語の主要設計者の一人)によって行われました。

当時のGo言語の仕様はまだ流動的であり、このgosrc内のコードベースは、現在のGo言語とは異なる古い言語仕様に基づいている可能性が高いです。コミットメッセージにある「this code doesn't match the existing language at this point, but it's a large code base which compiles - will eventually go away」という記述は、このコードが一時的なものであり、最終的には新しい言語仕様に合わせたコードに置き換えられる予定であったことを示唆しています。

変更の主な目的は、開発中のコンパイラがこの大規模なコードベースを再びコンパイルできるようにし、開発の継続性を確保することでした。また、run.bashスクリプトでこのgosrcのコンパイルを再度有効にすることで、ビルドプロセスに統合されています。

前提知識の解説

このコミットの変更内容を理解するためには、以下のGo言語(または一般的なコンパイラ)に関する基本的な概念を理解しておく必要があります。

  • AST (Abstract Syntax Tree): 抽象構文木。ソースコードの構文構造を木構造で表現したものです。コンパイラの構文解析フェーズで生成され、その後の意味解析やコード生成の基盤となります。ast.goファイルはこのASTのノード定義を含んでいます。
  • Scanner (Lexer): 字句解析器。ソースコードを読み込み、トークン(予約語、識別子、演算子、リテラルなど)のストリームに変換するコンパイラの最初のフェーズです。
  • Parser (構文解析器): トークンのストリームを読み込み、言語の文法規則に従ってASTを構築するコンパイラのフェーズです。parser.goファイルはこの機能を提供します。
  • Type System: 型システム。プログラミング言語におけるデータ型の定義、型チェックの規則、型推論などを扱うシステムです。type.goglobals.goの一部で定義されています。
  • Object: プログラム内のエンティティ(変数、定数、関数、型など)を表す抽象概念です。object.goglobals.goで定義されています。
  • Scope: スコープ。識別子(変数名など)が有効なプログラムの領域を定義します。スコープはネストすることができ、識別子の解決(どの宣言に対応するかを見つけること)に用いられます。globals.goScope構造体が定義されています。
  • Compilation Unit: コンパイル単位。コンパイラが一度に処理するソースコードの単位です。Go言語では通常、パッケージがこれに該当します。compilation.goはこのコンパイルプロセスを管理します。
  • Export/Import: パッケージ間で定義を共有するメカニズムです。export.goimport.goは、コンパイラがパッケージのインターフェースをエクスポート(外部に公開)およびインポート(取り込み)する方法を扱います。
  • new()make(): Go言語におけるメモリ割り当ての組み込み関数です。new()はゼロ値で初期化された型のポインタを返し、make()はスライス、マップ、チャネルといった組み込み型を初期化して返します。このコミットでは、new(*Type)のような古い形式からnew(Type)のような新しい形式への変更が見られます。これは、Go言語の初期の文法が現在のものと異なっていたことを示唆しています。

技術的詳細

このコミットは、Go言語のコンパイラ(gosrc)の複数のコンポーネントにわたる広範な変更を含んでいます。主な変更点は以下の通りです。

  1. ASTノードの拡張と統一:

    • usr/gri/gosrc/ast.go: Literal, Object, Deref, Selector, Call, Tupleといった新しいASTノードが導入され、それぞれにop()メソッドが追加されています。これにより、ASTノードの種類を識別するための統一的なメカニズムが提供されます。特にTupleノードの導入は、複数の戻り値を扱うGo言語の特性をASTレベルで表現するための重要な変更です。
    • new(*Type)のようなポインタ型を返すnewの呼び出しがnew(Type)のように値型を返すように変更されています。これはGo言語の初期の文法が現在のものと異なっていたことを示唆しており、より現代的なGoのnewの振る舞いに近づけるための変更と考えられます。
  2. エラー報告の改善:

    • usr/gri/gosrc/compilation.go: LineCol関数が追加され、ソースコード内の位置(行と列)を正確に特定できるようになりました。また、Error関数が大幅に改善され、エラーメッセージにファイル名、行番号、列番号を含めるようになりました。これにより、コンパイルエラーのデバッグが容易になります。エラー報告の頻度を制限するロジック(errdistnerrors)も導入されています。
  3. 型システムとオブジェクト定義の更新:

    • usr/gri/gosrc/globals.go: Type構造体のフィールド名が変更されています(例: len_からlenauxからkey)。これは、型システムが進化し、より明確なセマンティクスを持つようになったことを示しています。Object構造体にはBUILTIN(組み込み関数)のkindが追加され、Exprインターフェースにop()メソッドが追加されています。
    • usr/gri/gosrc/object.go: BUILTINという新しいオブジェクトの種類が追加され、組み込み関数を識別できるようになりました。
  4. パーサーロジックの修正とセマンティックチェックの分離:

    • usr/gri/gosrc/parser.go:
      • パーサーの内部状態を保持するフィールド名が変更されています(例: SからscannerCからtokchan)。
      • semantic_checksフラグが削除され、パーサーが構文解析に専念し、セマンティックチェックのロジックがexpr.goのような別のモジュールに分離されたことを示唆しています。これにより、コンパイラの各フェーズの責任がより明確になります。
      • 関数シグネチャの解析ロジックが変更され、レシーバーの有無に応じたFUNCTIONMETHODの区別がより明確になりました。また、複数の戻り値を扱うためのTuple型が導入されています。
      • ParseQualifiedIdentParseVarTypeParseTypeNameParsePointerTypeなどの関数で、セマンティックチェックのロジックが削除または簡略化されています。
      • ParseOperandからNIL, IOTA, TRUE, FALSE, NEWといったリテラルやキーワードの直接的なASTノード生成が削除され、より汎用的なExprパッケージの関数を呼び出すように変更されています。
      • ParseSelectorOrTypeAssertion, ParseIndexOrSlice, ParseCall, ParseUnaryExpr, ParseBinaryExprといった式解析の関数が、新しく導入されたExprパッケージの関数を呼び出すように変更されています。これにより、式に関するセマンティックな処理がExprパッケージに集約され、パーサーは構文解析に集中できるようになります。
      • ParseSimpleStatにおける変数宣言(:=)と代入(=)の処理が改善され、複数の変数と式の対応関係がより厳密にチェックされるようになりました。
  5. 新しいexpr.goファイルの導入:

    • usr/gri/gosrc/expr.goが新規に作成されています。このファイルは、式のセマンティックな処理(型チェック、デリファレンス、セレクタ、インデックス、スライス、関数呼び出しなど)をカプセル化する役割を担っています。これにより、コンパイラの設計がモジュール化され、保守性が向上しています。
  6. run.bashの変更:

    • src/run.bashで、usr/gri/gosrcディレクトリのコンパイルをコメントアウトしていた部分が解除され、再びコンパイルが有効になっています。

これらの変更は、Go言語のコンパイラが初期の実験的な段階から、より構造化され、堅牢な設計へと移行していく過程を示しています。特に、ASTの統一、エラー報告の改善、セマンティックチェックの分離、そしてexpr.goのような新しいモジュールによる機能の集約は、コンパイラの品質と保守性を高める上で重要なステップです。

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

  • src/run.bash:
    • L52-L57: usr/gri/gosrcのコンパイルを有効化。
  • usr/gri/gosrc/ast.go:
    • L14-L20: 新しい定数LITERAL, OBJECT, DEREF, SELECT, CALL, TUPLEの定義。
    • L28, L40, L55, L79, L94, L110: 各ASTノードにop()メソッドを追加。
    • L38, L53, L77: new(*Type)からnew(Type)への変更。
    • L67-L74: Deref構造体とNewDeref関数の追加。
    • L89-L96: Call構造体とNewCall関数の追加。
    • L104-L128: Tuple構造体とNewTuple関数の追加。
  • usr/gri/gosrc/compilation.go:
    • L22-L44: LineCol関数と改善されたError関数の追加。
    • L133-L134: comp.src_filecomp.srcの初期化。
    • L137-L138, L143-L144: new(*Scanner.Scanner)からnew(Scanner.Scanner)new(*Parser.Parser)からnew(Parser.Parser)への変更。
    • L140: make(chan *Scanner.Token, 100)への変更。
    • L148-L149: エラーチェックの変更。
  • usr/gri/gosrc/export.go:
    • L174-L175: Type.VOIDケースの追加。
    • L179-L180: Type.ALIAS, Type.MAPtyp.auxからtyp.keyへの変更。
    • L183: Type.TUPLEケースの追加。
    • L186: typ.len_からtyp.lenへの変更。
    • L189: typ.flagsからtyp.auxへの変更。
    • L192: Type.FUNCTIONType.METHODを追加し、typ.flagsからtyp.lenへの変更。
    • L200: Type.REFERENCEの削除。
    • L270: Universe.types.len_からUniverse.types.lenへの変更。
  • usr/gri/gosrc/expr.go:
    • L1-L164: 新規ファイル。Deref, Select, AssertType, Index, Slice, Call, UnaryExpr, BinaryExprといった式のセマンティック処理を行う関数群を定義。
  • usr/gri/gosrc/globals.go:
    • L31-L32: Type構造体のフィールド名変更 (flags削除, len_からlen, auxからkey, eltのコメント変更)。
    • L54: List構造体のlen_からlenへの変更。
    • L69-L73: Flags構造体からscan, parse, ast, depsフラグの削除。
    • L77: Environment構造体のErrorフィールドの型変更。
    • L84-L88: Compilation構造体にsrc_file, src, nerrors, errposフィールドの追加。
    • L91: Exprインターフェースにop()メソッドの追加。
    • L114: Elem構造体のtypeからexport typeへの変更。
    • L119, L124, L129, L134, L139: new(*Type)からnew(Type)への変更。
    • L191: Listlen_からlenへの変更。
    • L196: Listlen_からlenへの変更。
    • L200: new(*Elem)からnew(Elem)への変更。
    • L242-L244: ExprAt関数の追加。
    • L294-L296: Add関数の追加。
  • usr/gri/gosrc/go.go:
    • L20-L25: PrintHelpから古いフラグの説明を削除。
    • L49, L81, L88: new(*Type)からnew(Type)への変更。
    • L69-L74: コマンドライン引数処理から古いフラグの処理を削除。
    • L83: env.Error = &Compilation.Error;の追加。
  • usr/gri/gosrc/import.go:
    • L200-L202: Type.VOIDケースの追加。
    • L204-L205: Type.TUPLEケースの追加。
    • L207-L208: typ.auxからtyp.keyへの変更。
    • L211: typ.len_からtyp.lenへの変更。
    • L214: typ.flagsからtyp.auxへの変更。
    • L217: Type.FUNCTIONType.METHODを追加し、typ.flagsからtyp.lenへの変更。
    • L225: Type.REFERENCEの削除。
  • usr/gri/gosrc/object.go:
    • L9-L10: BUILTIN定数の追加。
    • L27: BUILTINの文字列表現を追加。
  • usr/gri/gosrc/parser.go:
    • L12: import Expr "expr"の追加。
    • L15-L16: semantic_checksフィールドの削除。
    • L18-L19: SからscannerCからtokchanへのフィールド名変更。
    • L52, L65: indentのインクリメント/デクリメントロジックの変更。
    • L70, L72: P.S.Scan()からP.scanner.Scan()<- P.Cから<- P.tokchanへの変更。
    • L89-L90: SからscannerCからtokchanへの引数名変更。
    • L95: P.S.ErrorからP.scanner.Errorへの変更。
    • L137-L139: semantic_checks関連のコード削除。
    • L157-L160: MakeFunctionTypeの引数とロジック変更(check_recv削除、p0のチェック強化)。
    • L164-L165: typ.flagsからtyp.lenへの変更。
    • L168-L173: 戻り値の型処理の変更(Tupleの導入)。
    • L189-L190: typ.flags & Type.RECVからtyp.form == Type.METHODへの変更。
    • L213: エラーメッセージの変更。
    • L313-L349: ParseQualifiedIdentからsemantic_checks関連のコード削除。
    • L376-L390: ParseVarTypeからsemantic_checks関連のコード削除。
    • L399-L413: ParseTypeNameからsemantic_checks関連のコード削除。
    • L427: typ.len_からtyp.lenへのコメント変更。
    • L445, L448, L452: typ.flagsからtyp.auxへの変更。
    • L479-L494: TryResultからParseResultへの変更とロジック修正。
    • L499-L530: ParseAnonymousSignatureからParseSignatureへの変更とロジック修正。
    • L579, L590, L609: sig.entries.len_からsig.entries.lenへの変更。
    • L668: typ.auxからtyp.keyへの変更。
    • L707-L879: ParsePointerTypeからsemantic_checks関連のコード削除と、暗黙的な前方宣言のロジック修正。
    • L892-L915: ParseNew関数の削除。
    • L989-L1000: ParseOperandからsemantic_checks関連のコード削除と、AST.NewObjectの呼び出し。
    • L1010-L1024: NIL, IOTA, TRUE, FALSE, NEWの処理を削除。
    • L1071-L1094: ParseSelectorOrTypeAssertionからsemantic_checks関連のコード削除と、Expr.Select, Expr.AssertTypeの呼び出し。
    • L1115-L1140: ParseIndexOrSliceからsemantic_checks関連のコード削除と、Expr.Slice, Expr.Indexの呼び出し。
    • L1164-L1167: ParseCallからsemantic_checks関連のコード削除と、Expr.Callの呼び出し。
    • L1221-L1228: ParseUnaryExprのロジック修正。
    • L1261-L1270: ParseBinaryExprからAST.BinaryExprの直接生成を削除し、Expr.BinaryExprの呼び出し。
    • L1309-L1317: ConvertToExprListのロジック修正。
    • L1327-L1328: ParseIdentOrExprのロジック修正。
    • L1368-L1384: ListArity関数の追加。
    • L1389-L1400: ParseSimpleStatにおけるラベル宣言のロジック修正。
    • L1403-L1419: ParseSimpleStatにおける変数宣言(:=)のロジック修正。
    • L1422-L1439: ParseSimpleStatにおける代入(=)のロジック修正。
    • L1739-L1757: ParseImportSpecからsemantic_checks関連のコード削除と、pkg.obj.pnolevのリセット。
    • L1831-L1832: typ.auxからtyp.keyへの変更。
    • L2012-L2014: ResolveForwardTypesからsemantic_checks関連のコード削除。

コアとなるコードの解説

このコミットの核心は、Go言語コンパイラの内部構造をよりモジュール化し、セマンティック解析の責任を明確に分離することにあります。

  1. ASTの統一と拡張: ast.goにおけるop()メソッドの導入と新しいASTノード(特にTuple)の追加は、コンパイラがGo言語の構文要素をより一貫した方法で表現し、処理できるようにするための基盤を築いています。Tupleの導入は、Goの多値戻り値や多重代入といった特徴をASTレベルでサポートするために不可欠です。また、new(*Type)からnew(Type)への変更は、Go言語の初期の文法が現在のものと異なっていたことを示唆しており、より現代的なGoのnewの振る舞いに近づけるための変更と考えられます。

  2. expr.goの導入によるセマンティック解析の分離: 最も重要な変更の一つは、usr/gri/gosrc/expr.goという新しいファイルが導入されたことです。このファイルは、式のデリファレンス、セレクタ(フィールドアクセスやメソッド呼び出し)、インデックス、スライス、関数呼び出しといった、式のセマンティックな側面を処理する関数群をカプセル化しています。これにより、parser.goは純粋な構文解析に集中できるようになり、コンパイラの各フェーズの責任が明確に分離されました。これは、コンパイラの設計原則における「関心の分離」を具現化したものであり、コードの可読性、保守性、拡張性を大幅に向上させます。

  3. パーサーの簡素化: parser.goからsemantic_checksフラグが削除され、多くのセマンティックチェックロジックがexpr.goに移動したことで、パーサーのコードが大幅に簡素化されました。これにより、パーサーはトークンストリームからASTを構築するという本来の役割に集中できるようになります。例えば、以前はパーサー内で直接行われていた型チェックやオブジェクト解決の一部が、Exprパッケージの関数を呼び出す形に変更されています。

  4. エラー報告の改善: compilation.goにおけるLineCol関数と改善されたError関数は、コンパイルエラーの診断能力を飛躍的に向上させます。正確な行番号と列番号、そしてエラーメッセージの表示は、開発者が問題を迅速に特定し、修正するために不可欠です。

これらの変更は、Go言語のコンパイラが初期のプロトタイプ段階から、より洗練された実用的なツールへと進化していく過程における重要なマイルストーンを示しています。モジュール化された設計は、将来の機能追加や言語仕様の変更にも柔軟に対応できる基盤を提供します。

関連リンク

参考にした情報源リンク

  • Web検索結果 (Google Search): "golang gosrc compiler 2009 Robert Griesemer af065a0c7783d33e01e75f43e07db681dadbf21e"
    • このコミットハッシュは公開されているGoリポジトリの履歴には見つかりませんでしたが、Robert Griesemer氏がGo言語の主要設計者の一人であり、2007年後半から開発が始まったGo言語の初期段階の内部コミットである可能性が高いことが示唆されました。
  • Go言語の歴史に関するWikipedia記事など、Go言語の初期開発に関する一般的な情報源。