コンテンツにスキップ

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安全性の脱糖:

user?.name?.length
は以下になる:
user != null ? (user.getName() != null ? user.getName().length() : null) : null

並行処理の脱糖:

spawn { doWork() }
は以下になる:
Thread.ofVirtual().start(() -> doWork())

フェーズ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を実行し、動作を検証

開発ワークフロー

新しい言語機能の追加

  1. 設計: 構文と意味論を指定
  2. 字句解析器: 必要に応じて新しいトークンを追加
  3. パーサー: 文法とASTノードを拡張
  4. 型チェッカー: 意味検証を追加
  5. IR: 脱糖変換を定義
  6. コード生成: Java生成を実装
  7. テスト: 包括的なテストケースを追加
  8. ドキュメント: 言語ガイドを更新

このアーキテクチャにより、jvは高性能で保守可能なコンパイラとして、モダンなJava機能を活用しながら優れた開発者体験を提供しています。