Files
hakorune/docs/development/current/main/phases/phase-286/llvm-modularization-instructions.md
tomoaki 6b64e6415c docs(phase-286): Add complete llvm.rs modularization instructions
Created comprehensive, self-contained instructions for modularizing
llvm.rs (449 lines → 10 boxes + orchestrator), following Phase 33
success pattern.

Contents:
- Background & current problems (12 responsibilities in 1 function)
- Phase 33 success case reference
- Detailed box design (10 boxes with responsibilities/inputs/outputs)
- Step-by-step implementation guide (staged migration)
- Acceptance criteria (build/test requirements)
- Important warnings (PyVM preservation, feature-gated code)

Box breakdown:
1. plugin_init.rs - Plugin initialization
2. using_resolver.rs - Using/prelude handling
3. mir_compiler.rs - AST → MIR compilation
4. method_id_injector.rs - method_id injection
5. joinir_experiment.rs - JoinIR experiment (feature-gated)
6. pyvm_executor.rs - PyVM harness (dev/test, MUST PRESERVE)
7. object_emitter.rs - LLVM object emit
8. harness_executor.rs - LLVM harness execution
9. exit_reporter.rs - Leak report (Phase 285LLVM-0)
10. fallback_executor.rs - Mock/legacy execution

Expected improvements:
- Code quality: 449 lines → 150-200 orchestrator + 10 focused boxes
- Testability: Each box independently testable
- Reusability: Boxes reusable across backends
- Maintainability: Single responsibility per box

CRITICAL: PyVM executor (pyvm_executor.rs) MUST be preserved
- Used by 8 JSON AST smoke tests
- NOT removable legacy code

Ready for handoff to other AI (ChatGPT, etc.) for implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-24 10:08:40 +09:00

29 KiB
Raw Blame History

Phase 286: llvm.rs 箱化モジュール化命令書

Date: 2025-12-24 Target: src/runner/modes/llvm.rs (449行の巨大関数) Goal: Phase 33スタイルの箱化モジュール化で、単一責任・テスト容易性・可読性を達成


📋 背景・目的

現状の問題

ファイル: src/runner/modes/llvm.rs (449行) 問題: execute_llvm_mode() が単一関数で12個の責務を持つ

impl NyashRunner {
    pub(crate) fn execute_llvm_mode(&self, filename: &str) {
        // 1. Plugin初期化 (lines 12-20)
        // 2. Using処理・prelude merge (lines 31-108)
        // 3. Macro expansion (lines 109-111)
        // 4. MIR compilation (lines 113-138)
        // 5. method_id injection (lines 131-137)
        // 6. JoinIR experiment (lines 139-232, 94行, feature-gated)
        // 7. PyVM harness dev/test (lines 234-245, 12行)
        // 8. Object emit (lines 247-325, 79行)
        // 9. LLVM harness execution (lines 327-380, 54行)
        // 10. Inkwell legacy (lines 384-407, 24行)
        // 11. Mock execution (lines 408-445, 38行)
        // 12. Leak report (lines 356-358, 365-366, Phase 285LLVM-0)
    }
}

影響:

  • 単一責任の原則違反12個の責務
  • テスト困難449行の巨大関数
  • 再利用不可他のbackendで使えない
  • 可読性低下(責務の境界が不明確)
  • 変更リスク大1箇所変更で全体影響

目的

Phase 33成功事例を再現:

  • 単一責任の原則各Boxが1つの関心事のみ
  • テスト容易性独立したBoxで単体テスト可能
  • 再利用性他のbackendでも使えるBox
  • 可読性50-80行/Box、責務明確
  • 変更安全性Boxの独立性で影響範囲限定

🎯 Phase 33 成功事例(参考)

ファイル: docs/development/architecture/phase-33-modularization.md

Before: mod.rs 511行の巨大ファイル After: 221行のオーケストレーター + 10個の独立Box

src/mir/builder/control_flow/
├── mod.rs (221行, -57%削減)
├── joinir/
│   ├── loop_patterns/
│   │   ├── pattern1_minimal.rs      # Pattern 1専用
│   │   ├── pattern2_flat_scan.rs     # Pattern 2専用
│   │   ├── pattern3_nested_if.rs     # Pattern 3専用
│   │   └── pattern4_multi_exit.rs    # Pattern 4専用
│   ├── merge/
│   │   ├── exit_line_reconnector.rs  # Exit line再接続Box
│   │   ├── exit_meta_collector.rs    # Exit metadata収集Box
│   │   └── exit_line_orchestrator.rs # Exit line調整オーケストレーター

成功の鍵:

  1. 単一責任: 各Boxが1つの明確な責務のみ
  2. Box境界: 入力・出力・副作用を明確化
  3. 再利用性: 共通処理は別Boxに分離ExitLineReconnectorなど
  4. 段階的移行: 既存コードを動かしながら少しずつ分離

🏗️ llvm.rs 箱化設計

ファイル構成(最終形)

src/runner/modes/llvm/
├── mod.rs (150-200行)           # オーケストレーターexecute_llvm_mode
├── plugin_init.rs               # Plugin初期化Box
├── using_resolver.rs            # Using/prelude処理Box
├── mir_compiler.rs              # MIR compilation Box
├── method_id_injector.rs        # method_id injection Box
├── joinir_experiment.rs         # JoinIR experiment Box (feature-gated)
├── pyvm_executor.rs             # PyVM harness Box (dev/test)
├── object_emitter.rs            # Object emit Box
├── harness_executor.rs          # LLVM harness実行Box
├── exit_reporter.rs             # Leak report Box (Phase 285LLVM-0)
└── fallback_executor.rs         # Mock/legacy実行Box

各Boxの責務と設計

1. plugin_init.rs - Plugin初期化Box

責務: Plugin初期化・診断 入力: なし 出力: Result<(), String> 現在の場所: llvm.rs:12-20

//! Plugin initialization for LLVM mode

pub struct PluginInitBox;

impl PluginInitBox {
    /// Initialize plugins and run diagnostics
    pub fn init() -> Result<(), String> {
        // Phase 15.5: Initialize bid plugins
        crate::runner_plugin_init::init_bid_plugins();

        // Friendly plugin guard (non-strict)
        crate::runner::modes::common_util::plugin_guard::check_and_report(
            false,
            crate::config::env::env_bool("NYASH_JSON_ONLY"),
            "llvm",
        );

        Ok(())
    }
}

2. using_resolver.rs - Using/Prelude処理Box

責務: using 構文の解決とprelude merge 入力: code: &str, filename: &str 出力: Result<(String, Vec<ASTNode>), String> 現在の場所: llvm.rs:31-108

//! Using/prelude resolution for LLVM mode

use nyash_rust::ast::ASTNode;

pub struct UsingResolverBox;

impl UsingResolverBox {
    /// Resolve `using` statements and merge preludes
    pub fn resolve(
        runner: &crate::runner::NyashRunner,
        code: &str,
        filename: &str,
    ) -> Result<(String, Vec<ASTNode>), String> {
        let use_ast = crate::config::env::using_ast_enabled();
        let mut code_ref: &str = code;
        let cleaned_code_owned;
        let mut prelude_asts: Vec<ASTNode> = Vec::new();

        if crate::config::env::enable_using() {
            // Using resolution logic (lines 36-99)
            // ...
        }

        Ok((code_ref.to_string(), prelude_asts))
    }
}

3. mir_compiler.rs - MIR Compilation Box

責務: AST → MIR compilation 入力: ast: ASTNode, filename: Option<&str> 出力: Result<MirModule, String> 現在の場所: llvm.rs:113-138

//! MIR compilation for LLVM mode

use nyash_rust::mir::{MirCompiler, MirModule};
use nyash_rust::ast::ASTNode;

pub struct MirCompilerBox;

impl MirCompilerBox {
    /// Compile AST to MIR
    pub fn compile(ast: ASTNode, filename: Option<&str>) -> Result<MirModule, String> {
        let mut mir_compiler = MirCompiler::new();

        let compile_result = crate::runner::modes::common_util::source_hint::compile_with_source_hint(
            &mut mir_compiler,
            ast,
            filename,
        ).map_err(|e| format!("MIR compilation error: {}", e))?;

        crate::console_println!("📊 MIR Module compiled successfully!");
        crate::console_println!("📊 Functions: {}", compile_result.module.functions.len());

        Ok(compile_result.module)
    }
}

4. method_id_injector.rs - Method ID Injection Box

責務: BoxCall/PluginInvokeにmethod_id注入 入力: &mut MirModule 出力: usize (注入箇所数) 現在の場所: llvm.rs:131-137

//! Method ID injection for LLVM mode

use nyash_rust::mir::MirModule;
use nyash_rust::mir::passes::method_id_inject::inject_method_ids;

pub struct MethodIdInjectorBox;

impl MethodIdInjectorBox {
    /// Inject method_id for BoxCall/PluginInvoke
    pub fn inject(module: &mut MirModule) -> usize {
        let injected = inject_method_ids(module);
        if injected > 0 {
            crate::cli_v!("[LLVM] method_id injected: {} places", injected);
        }
        injected
    }
}

5. joinir_experiment.rs - JoinIR Experiment Box

責務: JoinIR経路の実験的処理feature-gated 入力: MirModule 出力: MirModule (変換後、失敗時は元のまま) 現在の場所: llvm.rs:139-232 (94行)

//! JoinIR experiment for LLVM mode (Phase 32 L-4.3a)

#[cfg(feature = "llvm-harness")]
use nyash_rust::mir::MirModule;

pub struct JoinIrExperimentBox;

impl JoinIrExperimentBox {
    /// Apply JoinIR experiment if enabled
    #[cfg(feature = "llvm-harness")]
    pub fn apply(module: MirModule) -> MirModule {
        if !crate::config::env::joinir_experiment_enabled()
            || !crate::config::env::joinir_llvm_experiment_enabled()
            || !crate::config::env::llvm_use_harness()
        {
            return module;
        }

        use nyash_rust::mir::join_ir::lower_skip_ws_to_joinir;
        use nyash_rust::mir::join_ir_vm_bridge::bridge_joinir_to_mir;

        crate::runtime::get_global_ring0()
            .log
            .debug("[joinir/llvm] Attempting JoinIR path for LLVM execution");

        // JoinIR conversion logic (lines 156-223)
        // ...

        module
    }

    #[cfg(not(feature = "llvm-harness"))]
    pub fn apply(module: MirModule) -> MirModule {
        module
    }
}

6. pyvm_executor.rs - PyVM Harness Box

責務: PyVM harness経由での実行dev/test用 入力: &MirModule 出力: Option<i32> (実行した場合のみexit code) 現在の場所: llvm.rs:234-245 (12行) 重要: 削除不可8個のJSON ASTスモークテストで使用中

//! PyVM harness executor (dev/test helper)

use nyash_rust::mir::MirModule;

pub struct PyVmExecutorBox;

impl PyVmExecutorBox {
    /// Execute via PyVM harness if requested
    pub fn try_execute(module: &MirModule) -> Option<i32> {
        if std::env::var("SMOKES_USE_PYVM").ok().as_deref() != Some("1") {
            return None;
        }

        match super::super::common_util::pyvm::run_pyvm_harness_lib(module, "llvm-ast") {
            Ok(code) => Some(code),
            Err(e) => {
                crate::console_println!("❌ PyVM harness error: {}", e);
                Some(1)
            }
        }
    }
}

7. object_emitter.rs - Object Emit Box

責務: LLVM object file生成 入力: &MirModule, out_path: &str 出力: Result<(), String> 現在の場所: llvm.rs:247-325 (79行)

//! Object file emitter for LLVM mode

use nyash_rust::mir::MirModule;

pub struct ObjectEmitterBox;

impl ObjectEmitterBox {
    /// Emit LLVM object file if requested
    #[cfg(feature = "llvm-harness")]
    pub fn try_emit(module: &MirModule) -> Result<bool, String> {
        let out_path = match std::env::var("NYASH_LLVM_OBJ_OUT") {
            Ok(p) => p,
            Err(_) => return Ok(false), // Not requested
        };

        if crate::config::env::llvm_use_harness() {
            crate::runner::modes::common_util::exec::llvmlite_emit_object(
                module, &out_path, 20_000
            )?;

            // Verify object file
            Self::verify_object(&out_path)?;
            return Ok(true);
        }

        Ok(false)
    }

    #[cfg(feature = "llvm-harness")]
    fn verify_object(path: &str) -> Result<(), String> {
        match std::fs::metadata(path) {
            Ok(meta) if meta.len() > 0 => {
                if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
                    crate::console_println!(
                        "[LLVM] object emitted: {} ({} bytes)",
                        path, meta.len()
                    );
                }
                Ok(())
            }
            Ok(_) => Err(format!("harness object is empty: {}", path)),
            Err(e) => Err(format!("harness output not found: {} ({})", path, e)),
        }
    }
}

8. harness_executor.rs - LLVM Harness実行Box

責務: LLVM harness経由でnative executable生成・実行 入力: &MirModule 出力: Option<i32> (実行した場合のみexit code) 現在の場所: llvm.rs:327-380 (54行)

//! LLVM harness executor (native executable generation and execution)

use nyash_rust::mir::MirModule;

pub struct HarnessExecutorBox;

impl HarnessExecutorBox {
    /// Execute via LLVM harness if available
    #[cfg(feature = "llvm-harness")]
    pub fn try_execute(module: &MirModule) -> Option<i32> {
        if !crate::config::env::llvm_use_harness() {
            return None;
        }

        // Prefer producing a native executable via ny-llvmc, then execute it
        let exe_out = "tmp/nyash_llvm_run";
        let libs = std::env::var("NYASH_LLVM_EXE_LIBS").ok();

        match crate::runner::modes::common_util::exec::ny_llvmc_emit_exe_lib(
            module,
            exe_out,
            None,
            libs.as_deref(),
        ) {
            Ok(()) => {
                match crate::runner::modes::common_util::exec::run_executable(
                    exe_out,
                    &[],
                    20_000,
                ) {
                    Ok((code, _timed_out, stdout_text)) => {
                        // Forward program stdout for parity tests
                        if !stdout_text.is_empty() {
                            print!("{}", stdout_text);
                        }
                        crate::console_println!(
                            "✅ LLVM (harness) execution completed (exit={})",
                            code
                        );

                        Some(code)
                    }
                    Err(e) => {
                        crate::console_println!("❌ run executable error: {}", e);
                        Some(1)
                    }
                }
            }
            Err(e) => {
                crate::console_println!("❌ ny-llvmc emit-exe error: {}", e);
                crate::console_println!(
                    "   Hint: build ny-llvmc: cargo build -p nyash-llvm-compiler --release"
                );
                Some(1)
            }
        }
    }

    #[cfg(not(feature = "llvm-harness"))]
    pub fn try_execute(_module: &MirModule) -> Option<i32> {
        None
    }
}

9. exit_reporter.rs - Leak Report Box

責務: Phase 285LLVM-0のleak report出力 入力: なし 出力: なし(副作用のみ) 現在の場所: llvm.rs:356-358, 365-366

//! Exit reporter for LLVM mode (Phase 285LLVM-0)

pub struct ExitReporterBox;

impl ExitReporterBox {
    /// Emit leak report before exit
    pub fn emit_and_exit(code: i32) -> ! {
        // Phase 285LLVM-0: Emit Rust-side leak report before exit (if enabled)
        // Note: Only reports Rust VM-side roots (modules, host_handles, plugin_boxes).
        crate::runtime::leak_tracker::emit_leak_report();

        std::process::exit(code);
    }
}

10. fallback_executor.rs - Fallback/Mock実行Box

責務: feature無効時のfallback実行mock含む 入力: &MirModule 出力: i32 (exit code) 現在の場所: llvm.rs:408-445 (38行)

//! Fallback executor for LLVM mode (mock/legacy)

use nyash_rust::mir::{MirModule, MirInstruction};

pub struct FallbackExecutorBox;

impl FallbackExecutorBox {
    /// Execute fallback path (feature check + mock)
    pub fn execute(module: &MirModule) -> i32 {
        // Fail-fast: if the user explicitly requested the llvmlite harness
        // but this binary was built without the `llvm-harness` feature,
        // do not silently fall back to mock.
        if crate::config::env::env_bool("NYASH_LLVM_USE_HARNESS") {
            crate::console_println!(
                "❌ LLVM harness requested (NYASH_LLVM_USE_HARNESS=1), but this binary was built without `--features llvm` (llvm-harness)."
            );
            crate::console_println!(
                "   Fix: cargo build --release --features llvm"
            );
            return 1;
        }

        crate::console_println!("🔧 Mock LLVM Backend Execution:");
        crate::console_println!("   Build with --features llvm for real backend.");

        // NamingBox SSOT: Select entry (arity-aware, Main.main → main fallback)
        let entry = crate::runner::modes::common_util::entry_selection::select_entry_function(module);

        if let Some(main_func) = module.functions.get(&entry) {
            for (_bid, block) in &main_func.blocks {
                for inst in &block.instructions {
                    match inst {
                        MirInstruction::Return { value: Some(_) } => {
                            crate::console_println!("✅ Mock exit code: 42");
                            return 42;
                        }
                        MirInstruction::Return { value: None } => {
                            crate::console_println!("✅ Mock exit code: 0");
                            return 0;
                        }
                        _ => {}
                    }
                }
            }
        }

        crate::console_println!("✅ Mock exit code: 0");
        0
    }
}

オーケストレーターmod.rs

責務: 各Boxを適切な順序で呼び出し、全体フロー制御 サイズ: 150-200行元の449行から55-60%削減)

//! LLVM mode executor (modularized)
//!
//! Phase 286: Modularization following Phase 33 success pattern
//! - Single responsibility per box
//! - Testability through isolated boxes
//! - Reusability across backends

use super::super::NyashRunner;
use nyash_rust::{mir::MirModule, parser::NyashParser};
use std::{fs, process};

mod plugin_init;
mod using_resolver;
mod mir_compiler;
mod method_id_injector;
mod joinir_experiment;
mod pyvm_executor;
mod object_emitter;
mod harness_executor;
mod exit_reporter;
mod fallback_executor;

use plugin_init::PluginInitBox;
use using_resolver::UsingResolverBox;
use mir_compiler::MirCompilerBox;
use method_id_injector::MethodIdInjectorBox;
use joinir_experiment::JoinIrExperimentBox;
use pyvm_executor::PyVmExecutorBox;
use object_emitter::ObjectEmitterBox;
use harness_executor::HarnessExecutorBox;
use exit_reporter::ExitReporterBox;
use fallback_executor::FallbackExecutorBox;

impl NyashRunner {
    /// Execute LLVM mode (modularized orchestrator)
    pub(crate) fn execute_llvm_mode(&self, filename: &str) {
        // Step 1: Plugin initialization
        if let Err(e) = PluginInitBox::init() {
            crate::console_println!("❌ Plugin init error: {}", e);
            ExitReporterBox::emit_and_exit(1);
        }

        // Step 2: Read file
        let code = match fs::read_to_string(filename) {
            Ok(content) => content,
            Err(e) => {
                crate::console_println!("❌ Error reading file {}: {}", filename, e);
                ExitReporterBox::emit_and_exit(1);
            }
        };

        // Step 3: Using resolution and prelude merge
        let (clean_code, prelude_asts) = match UsingResolverBox::resolve(self, &code, filename) {
            Ok(result) => result,
            Err(e) => {
                crate::console_println!("❌ Using resolution error: {}", e);
                ExitReporterBox::emit_and_exit(1);
            }
        };

        // Step 4: Parse to AST
        let mut parser = NyashParser::new(&clean_code);
        let main_ast = match parser.parse_entry() {
            Ok(ast) => ast,
            Err(e) => {
                crate::console_println!("❌ Parse error: {}", e);
                ExitReporterBox::emit_and_exit(1);
            }
        };

        // Step 5: Merge preludes with main AST
        let ast = if !prelude_asts.is_empty() {
            crate::runner::modes::common_util::resolve::merge_prelude_asts_with_main(
                prelude_asts,
                &main_ast,
            )
        } else {
            main_ast
        };

        // Step 6: Macro expansion
        let ast = crate::r#macro::maybe_expand_and_dump(&ast, false);
        let ast = crate::runner::modes::macro_child::normalize_core_pass(&ast);

        // Step 7: MIR compilation
        let mut module = match MirCompilerBox::compile(ast, Some(filename)) {
            Ok(m) => m,
            Err(e) => {
                crate::console_println!("❌ {}", e);
                ExitReporterBox::emit_and_exit(1);
            }
        };

        // Step 8: Method ID injection
        MethodIdInjectorBox::inject(&mut module);

        // Step 9: JoinIR experiment (optional, feature-gated)
        let module = JoinIrExperimentBox::apply(module);

        // Step 10: PyVM harness (dev/test helper)
        if let Some(code) = PyVmExecutorBox::try_execute(&module) {
            ExitReporterBox::emit_and_exit(code);
        }

        // Step 11: Object emit (if requested)
        #[cfg(feature = "llvm-harness")]
        if let Ok(true) = ObjectEmitterBox::try_emit(&module) {
            return; // Object emit only, no execution
        }

        // Step 12: LLVM harness execution (preferred)
        if let Some(code) = HarnessExecutorBox::try_execute(&module) {
            ExitReporterBox::emit_and_exit(code);
        }

        // Step 13: Fallback execution (mock/legacy)
        let code = FallbackExecutorBox::execute(&module);
        ExitReporterBox::emit_and_exit(code);
    }
}

🚀 実装手順(段階的移行)

Phase 1: 準備30分

  1. ディレクトリ作成

    mkdir -p src/runner/modes/llvm
    
  2. mod.rs作成

    • 現在の llvm.rsllvm/mod.rs にコピー
    • Git履歴保持: git mv src/runner/modes/llvm.rs src/runner/modes/llvm/mod.rs
  3. 親モジュール更新

    • src/runner/modes/mod.rsmod llvm; を確認

Phase 2: Box分離各30-60分、順次実行

順序: 依存関係の少ないBoxから分離

Step 1: plugin_init.rs 分離

  • Lines 12-20 を抽出
  • PluginInitBox::init() 実装
  • mod.rs から呼び出し
  • テスト実行(cargo build --release
  • Commit

Step 2: exit_reporter.rs 分離

  • Lines 356-358, 365-366 を抽出
  • ExitReporterBox::emit_and_exit() 実装
  • 全ての process::exit() を置き換え
  • テスト実行
  • Commit

Step 3: method_id_injector.rs 分離

  • Lines 131-137 を抽出
  • MethodIdInjectorBox::inject() 実装
  • テスト実行
  • Commit

Step 4: using_resolver.rs 分離

  • Lines 31-108 を抽出
  • UsingResolverBox::resolve() 実装
  • テスト実行
  • Commit

Step 5: mir_compiler.rs 分離

  • Lines 113-130 を抽出
  • MirCompilerBox::compile() 実装
  • テスト実行
  • Commit

Step 6: pyvm_executor.rs 分離

  • Lines 234-245 を抽出
  • PyVmExecutorBox::try_execute() 実装
  • 重要: JSON ASTスモークテスト実行確認
  • Commit

Step 7: joinir_experiment.rs 分離

  • Lines 139-232 を抽出
  • JoinIrExperimentBox::apply() 実装
  • feature-gated コンパイル確認
  • テスト実行
  • Commit

Step 8: object_emitter.rs 分離

  • Lines 247-325 を抽出
  • ObjectEmitterBox::try_emit() 実装
  • feature-gated コンパイル確認
  • テスト実行
  • Commit

Step 9: harness_executor.rs 分離

  • Lines 327-380 を抽出
  • HarnessExecutorBox::try_execute() 実装
  • feature-gated コンパイル確認
  • テスト実行
  • Commit

Step 10: fallback_executor.rs 分離

  • Lines 408-445 を抽出
  • FallbackExecutorBox::execute() 実装
  • テスト実行
  • Commit

Phase 3: オーケストレーター整理1時間

  1. mod.rs簡素化

    • 各Boxのuse文追加
    • execute_llvm_mode() を12ステップのオーケストレーターに書き換え
    • 古いコード削除
  2. 最終テスト

    # ビルド確認
    cargo build --release
    cargo build --release --features llvm
    
    # スモークテスト(重要!)
    tools/smokes/v2/run.sh --profile quick --filter "json_*_ast"  # PyVM確認
    tools/smokes/v2/run.sh --profile quick --filter "llvm"         # LLVM確認
    
  3. Commit

    git add src/runner/modes/llvm/
    git commit -m "refactor(llvm): Phase 286 - Modularize llvm.rs into 10 boxes
    
    Following Phase 33 success pattern:
    - Single responsibility per box
    - Testability through isolated boxes
    - Reusability across backends
    
    Before: 449 lines monolithic function
    After: 150-200 line orchestrator + 10 focused boxes
    
    Boxes created:
    - plugin_init.rs (plugin initialization)
    - using_resolver.rs (using/prelude handling)
    - mir_compiler.rs (AST → MIR compilation)
    - method_id_injector.rs (method_id injection)
    - joinir_experiment.rs (JoinIR experiment, feature-gated)
    - pyvm_executor.rs (PyVM harness, dev/test)
    - object_emitter.rs (LLVM object emit)
    - harness_executor.rs (LLVM harness execution)
    - exit_reporter.rs (leak report, Phase 285LLVM-0)
    - fallback_executor.rs (mock/legacy execution)
    
    Test Results:
    - ✅ cargo build --release
    - ✅ cargo build --release --features llvm
    - ✅ JSON AST smoke tests (PyVM確認)
    - ✅ LLVM smoke tests
    - ✅ No regressions
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
    

Acceptance Criteria

必須条件

  • ビルド成功: cargo build --release エラー0
  • ビルド成功LLVM: cargo build --release --features llvm エラー0
  • PyVMスモークテスト: 8個のJSON ASTテスト全てPASS
    tools/smokes/v2/run.sh --profile quick --filter "json_errors_ast"
    tools/smokes/v2/run.sh --profile quick --filter "json_large_array_ast"
    tools/smokes/v2/run.sh --profile quick --filter "json_deep_nesting_ast"
    tools/smokes/v2/run.sh --profile quick --filter "json_error_messages_ast"
    tools/smokes/v2/run.sh --profile quick --filter "json_unicode_basic_ast"
    tools/smokes/v2/run.sh --profile quick --filter "json_roundtrip_ast"
    tools/smokes/v2/run.sh --profile quick --filter "json_long_string_ast"
    tools/smokes/v2/run.sh --profile quick --filter "json_nested_ast"
    
  • LLVMスモークテスト: Phase 285LLVM-0テスト含めてPASS
    tools/smokes/v2/run.sh --profile quick --filter "phase285_leak_report_llvm"
    
  • 回帰なし: 既知FAIL以外増えない

品質条件

  • 単一責任: 各Boxが1つの明確な責務のみ
  • サイズ: 各Box 50-120行オーケストレーター除く
  • 可読性: 責務・入力・出力がコメントで明示
  • 再利用性: Boxが独立して使える設計
  • テスト容易性: 各Boxが単体テスト可能な設計

ドキュメント条件

  • 各Boxにドキュメントコメント: //! でモジュール説明
  • 各関数にドキュメントコメント: /// で関数説明
  • Phase 286記録: docs/development/current/main/phases/phase-286/README.md 作成

⚠️ 重要な注意点

1. PyVM削除禁止

理由: 8個のJSON ASTスモークテストで使用中 対象: pyvm_executor.rs は保持必須 確認: 実装後に必ずJSON ASTテスト実行

2. Feature-gated コード

対象:

  • joinir_experiment.rs (#[cfg(feature = "llvm-harness")])
  • object_emitter.rs (#[cfg(feature = "llvm-harness")])
  • harness_executor.rs (#[cfg(feature = "llvm-harness")])

確認: 両方のfeature組み合わせでビルド

cargo build --release                    # llvm-harness無効
cargo build --release --features llvm    # llvm-harness有効

3. Leak Report統合

Phase 285LLVM-0: exit_reporter.rs で統一 全ての process::exit()ExitReporterBox::emit_and_exit() に置き換え

4. 段階的移行

一度に全部やらない:

  • 1 Boxずつ分離
  • 各ステップでビルド・テスト確認
  • 問題があれば即座に戻せる

5. Git履歴保持

git mv 使用:

git mv src/runner/modes/llvm.rs src/runner/modes/llvm/mod.rs

📚 参考資料

Phase 33 成功事例

  • ドキュメント: docs/development/architecture/phase-33-modularization.md
  • 実装: src/mir/builder/control_flow/
  • Commit: 2d5607930 など5個のcommit

関連Phase

  • Phase 285LLVM-0: Leak Report実装exit_reporter.rs の基礎)
  • Phase 15: Rust VM + LLVM 2本柱体制

コーディング規約

  • Fail-Fast原則: エラーは早期に明示的に失敗
  • Box-First原則: 箱化・モジュール化で足場を積む
  • SSOT原則: 単一真実の源(ドキュメント・実装の整合性)

🎯 期待効果

コード品質

項目 Before After 改善
ファイル数 1 11 +10
最大行数/ファイル 449行 150-200行 -55%
平均行数/Box N/A 50-80行 可読性↑
責務数/関数 12 1 単一責任↑

開発効率

  • テスト容易性: 各Box独立テスト可能
  • 変更安全性: Box境界で影響範囲限定
  • 再利用性: 他backendでBox再利用可能
  • 可読性: 責務明確で理解しやすい

保守性

  • バグ修正: Box単位で修正可能
  • 機能追加: 新Boxとして追加可能
  • リファクタリング: Box単位で実施可能

🤖 AI実装者への追加指示

実装スタイル

  1. 段階的に実装: 一度に全部やらない
  2. 各ステップでテスト: ビルド・スモークテスト確認
  3. Commitは小さく: 1 Box分離ごとにcommit
  4. エラーメッセージ保持: 既存のエラーメッセージを変更しない
  5. コメント充実: 各Boxの責務・入力・出力を明記

デバッグ時の確認事項

ビルドエラー時:

  1. use文の追加忘れチェック
  2. feature-gated コードの #[cfg] 確認
  3. モジュール宣言の追加確認

実行時エラー時:

  1. PyVMスモークテスト確認SMOKES_USE_PYVM=1
  2. Leak report出力確認NYASH_LEAK_LOG=2
  3. LLVM harness実行確認NYASH_LLVM_USE_HARNESS=1

質問・不明点があれば

  • Phase 33実装 (src/mir/builder/control_flow/) を参照
  • 既存コードの動作を変更しない
  • 疑問があれば実装前に質問

この命令書は完全自己完結型です。他のAIChatGPT等に渡して実装可能です。

実装完了後、Phase 285LLVM-0と合わせてコミットしてください。