jv コンパイラーアーキテクチャ¶
English | 日本語
このドキュメントでは、コンパイルパイプライン、コアコンポーネント、設計決定を含むjvコンパイラーの内部アーキテクチャについて説明します。
ハイレベルアーキテクチャ¶
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ .jvファイル │ -> │ 字句解析 │ -> │ 構文解析 │ -> │ AST │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ .classファイル│ <- │ javac │ <- │ Javaソース │ <- │ IR │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
コンパイルパイプライン¶
フェーズ1: 字句解析 (jv_lexer)¶
目的: 生のjvソーステキストをトークンに変換する。
入力: 生のソースコード文字列 出力: トークンストリーム
主要コンポーネント:
- Lexer構造体: メイントークナイザー
- Token列挙型: すべてのjvトークンタイプ
- Span構造体: ソース位置追跡
トークンタイプ:
pub enum Token {
// リテラル
StringLiteral(String),
IntegerLiteral(i64),
FloatLiteral(f64),
BooleanLiteral(bool),
// キーワード
Val, Var, Fun, Class, Data, When, If, Else,
Null, True, False, Return, Import,
// 演算子
Plus, Minus, Star, Slash, Percent,
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual,
// null安全
Question, QuestionDot, QuestionColon,
// 区切り文字
LeftParen, RightParen, LeftBrace, RightBrace,
LeftBracket, RightBracket, Comma, Semicolon,
// 特別
Identifier(String),
StringInterpolation(Vec<StringPart>),
Eof,
}
エラー処理: - 正確なソース位置を持つ字句エラー - 不正なトークンの回復メカニズム - 識別子と文字列のUnicodeサポート
フェーズ2: 構文解析 (jv_parser)¶
目的: トークンを抽象構文木(AST)に解析する。
入力: 字句解析器からのトークンストリーム 出力: プログラム構造を表すAST
パーサー実装:
- chumskyパーサーコンビネーターライブラリーベース
- 演算子の優先順位を持つ再帰下降パーサー
- 部分解析のエラー回復
主要機能: - 式解析: 優先順位と結合性を処理 - 文解析: すべてのjv文タイプ - 型注釈解析: オプショナルとnull可能型 - パターンマッチング: 複雑なパターン構文 - 文字列補間: 文字列内の埋め込み式
フェーズ3: 意味解析 (jv_ast + jv_checker)¶
目的: 意味を検証し、型チェックを実行する。
コンポーネント:
型推論 (jv_ast):
- Hindley-Milnerスタイルの型推論
- ジェネリクスと制約のサポート
- null可能型の処理
静的解析 (jv_checker):
- 変数スコープの検証
- 型互換性チェック
- null安全性の強制
- デッドコード検出
- パフォーマンスのアンチパターン検出
フェーズ4: IR変換 (jv_ir)¶
目的: 高レベルのjv構文をJava生成に適したより単純な形式に変換する。
主要変換:
シンタックスシュガーの除去:
- 型推論付きval/var → 明示的型
- when式 → Java switch文
- 拡張関数 → 静的メソッド呼び出し
- 文字列補間 → String.format()呼び出し
- デフォルトパラメータ → メソッドオーバーロード
- トップレベル関数 → ユーティリティクラスメソッド
null安全性の脱糖:
は以下になる:並行処理の脱糖:
は以下になる:フェーズ5: Javaコード生成 (jv_codegen_java)¶
目的: IRから読みやすい、慣用的なJava 25ソースコードを生成する。
コード生成戦略: - 読みやすい出力: 生成されたJavaは手書きのように見える - Java 25機能: records、パターンマッチング、仮想スレッドを活用 - パフォーマンス: 効率的なJavaコードを生成 - デバッグ: ソース位置情報を維持
Java 25機能の使用:
Records(不変データクラス用):
public record Point(double x, double y) {
public Point translate(double dx, double dy) {
return new Point(x + dx, y + dy);
}
}
パターンマッチング(when式用):
public static String describe(Object obj) {
return switch (obj) {
case String s -> "String: " + s;
case Integer i when i > 0 -> "Positive: " + i;
case Integer i -> "Non-positive: " + i;
case null -> "null value";
default -> "Unknown type";
};
}
仮想スレッド(spawnブロック用):
public void processAsync() {
Thread.ofVirtual().name("worker").start(() -> {
// バックグラウンド作業
processData();
});
}
設計決定¶
なぜ実装にRustを使うのか?¶
パフォーマンス: Rustは高速コンパイルのためにC並みのパフォーマンスを提供 メモリ安全性: バッファオーバーフローなどの一般的なコンパイラバグを防止 並行性: 並列コンパイルの優れたサポート エコシステム: パーサーコンビネーター、CLIツールを含む豊富なエコシステム
なぜJava 25をターゲットにするのか?¶
モダン機能: records、パターンマッチング、仮想スレッド パフォーマンス: 最新のJVM最適化と機能 互換性: 古いJavaとの後方互換性を維持 将来志向: 今後のJava機能に対してjvを位置づけ
AST vs IR設計¶
AST(抽象構文木): - jv構文の直接的な表現 - ツール用の元の構造を保持 - フォーマット、リファクタリング、LSPに使用
IR(中間表現): - コード生成に適した簡略化された形式 - シュガー構文を除去 - 最適化を適用可能
パフォーマンス特性¶
コンパイル速度¶
シングルスレッド: モダンハードウェアで約10,000行/秒 マルチスレッド: CPUコアに対して線形にスケール インクリメンタル: 変更されたファイルと依存関係のみを再コンパイル
メモリ使用量¶
字句解析器: O(n)(nはソースファイルサイズ) パーサー: AST格納でO(n) IR: ASTサイズと類似のO(n) コード生成: 一時的な文字列バッファでO(n)
生成コード品質¶
ランタイムパフォーマンス: 手書きJavaに匹敵 バイナリサイズ: 追加ランタイム依存関係なし メモリ効率: Javaのメモリモデルを直接使用
テスト戦略¶
単体テスト¶
各コンポーネントには包括的な単体テストがあります: - 字句解析器: トークン生成とエラーケース - パーサー: すべての構文形式のAST生成 - IR: 変換の正確性 - コード生成: Java出力の検証
統合テスト¶
エンドツーエンドのコンパイルテスト: - ゴールデンテスト: 生成されたJavaを期待される出力と比較 - コンパイルテスト: 生成されたJavaが正しくコンパイルされることを確認 - ランタイムテスト: 生成されたJavaを実行し、動作を検証
開発ワークフロー¶
新しい言語機能の追加¶
- 設計: 構文と意味論を指定
- 字句解析器: 必要に応じて新しいトークンを追加
- パーサー: 文法とASTノードを拡張
- 型チェッカー: 意味検証を追加
- IR: 脱糖変換を定義
- コード生成: Java生成を実装
- テスト: 包括的なテストケースを追加
- ドキュメント: 言語ガイドを更新
このアーキテクチャにより、jvは高性能で保守可能なコンパイラとして、モダンなJava機能を活用しながら優れた開発者体験を提供しています。