feat(joinir): Phase 27.1 - FuncScanner.trim JoinIR変換実装完了
目的: - minimal_ssa_skip_ws に続き、FuncScannerBox.trim/1 ループを JoinIR 変換対象に追加 - Phase 27.0 の実用化拡張(より簡単なループで動作確認) 実装内容: 1. lower_funcscanner_trim_to_joinir() 関数追加 (src/mir/join_ir.rs:515-770) - trim_main + loop_step の2関数生成 - 固定 ValueId 割り当て (5000-5018, 6000-6018) - OR 条件の chain 処理 (ch == " " || "\t" || "\n" || "\r") 2. BinOpKind 拡張 (src/mir/join_ir.rs:147-154) - Or/And variant 追加(論理演算対応) - Phase 27.1 実験的拡張として最小限の変更 3. テストインフラ追加 (src/tests/mir_joinir_funcscanner_trim.rs) - auto_lowering テスト: #[ignore] + NYASH_JOINIR_EXPERIMENT=1 トグル - type_sanity テスト: 常時実行の軽量テスト 4. ドキュメント完備 (docs/private/roadmap2/phases/phase-27.1-joinir/) - IMPLEMENTATION_LOG.md: 技術メモ + BinOpKind 拡張決定の記録 - TASKS.md: 実装ステップ進捗管理 検証結果: - ✅ ビルド成功 (リリースビルド 55.75s) - ✅ type_sanity テスト PASS - ✅ 既存 JoinIR テスト全て PASS (mir_joinir_min, mir_joinir_skip_ws) - ✅ トグル OFF で本線影響なし確認済み トグル制御: - NYASH_JOINIR_EXPERIMENT=1 で JoinIR 変換有効化 - デフォルトは従来の MIR/LoopForm 維持 次のステップ: - C-2: トグル ON での動作確認 - D-1: ベースライン緑度確認 - E-1: README 更新 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
100
src/tests/mir_joinir_funcscanner_trim.rs
Normal file
100
src/tests/mir_joinir_funcscanner_trim.rs
Normal file
@ -0,0 +1,100 @@
|
||||
// mir_joinir_funcscanner_trim.rs
|
||||
// Phase 27.1: FuncScannerBox.trim JoinIR変換テスト
|
||||
//
|
||||
// 目的:
|
||||
// - FuncScannerBox.trim/1 の MIR → JoinIR 自動変換の動作確認
|
||||
// - trailing whitespace 除去ループの JoinIR 表現検証
|
||||
// - Phase 27.0 skip_ws に続く実用ループ変換(より簡単なケース)
|
||||
//
|
||||
// 実行条件:
|
||||
// - デフォルトでは #[ignore] にしておいて手動実行用にする
|
||||
// - 環境変数 NYASH_JOINIR_EXPERIMENT=1 で実験モード有効化
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::join_ir::*;
|
||||
use crate::mir::{MirCompiler, ValueId};
|
||||
use crate::parser::NyashParser;
|
||||
|
||||
#[test]
|
||||
#[ignore] // 手動実行用(Phase 27.1 実験段階)
|
||||
fn mir_joinir_funcscanner_trim_auto_lowering() {
|
||||
// Phase 27.1: FuncScannerBox.trim の MIR → JoinIR 自動変換
|
||||
|
||||
// 環境変数トグルチェック
|
||||
if std::env::var("NYASH_JOINIR_EXPERIMENT").ok().as_deref() != Some("1") {
|
||||
eprintln!("[joinir/trim] NYASH_JOINIR_EXPERIMENT=1 not set, skipping auto-lowering test");
|
||||
return;
|
||||
}
|
||||
|
||||
// Stage-3 parser を有効化(local キーワード対応)
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_ENABLE_USING", "1");
|
||||
std::env::set_var("HAKO_ENABLE_USING", "1");
|
||||
|
||||
// Step 1: MIR までコンパイル
|
||||
// FuncScanner 本体と最小テストを結合
|
||||
let test_file = "lang/src/compiler/tests/funcscanner_trim_min.hako";
|
||||
let func_scanner_src = include_str!("../../lang/src/compiler/entry/func_scanner.hako");
|
||||
let test_src = std::fs::read_to_string(test_file)
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}", test_file));
|
||||
let src = format!("{func_scanner_src}\n\n{test_src}");
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(&src)
|
||||
.expect("trim: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let compiled = mc.compile(ast).expect("trim: MIR compile failed");
|
||||
|
||||
eprintln!(
|
||||
"[joinir/trim] MIR module compiled, {} functions",
|
||||
compiled.module.functions.len()
|
||||
);
|
||||
|
||||
// Step 2: MIR → JoinIR 自動変換
|
||||
let join_module = lower_funcscanner_trim_to_joinir(&compiled.module)
|
||||
.expect("lower_funcscanner_trim_to_joinir failed");
|
||||
|
||||
eprintln!("[joinir/trim] JoinIR module generated:");
|
||||
eprintln!("{:#?}", join_module);
|
||||
|
||||
// Step 3: 妥当性検証
|
||||
assert_eq!(join_module.functions.len(), 2, "Expected 2 functions (trim_main + loop_step)");
|
||||
|
||||
let trim_main_id = JoinFuncId::new(0);
|
||||
let loop_step_id = JoinFuncId::new(1);
|
||||
|
||||
// trim_main 関数の検証
|
||||
let trim_main_func = join_module.functions.get(&trim_main_id)
|
||||
.expect("trim_main function not found");
|
||||
assert_eq!(trim_main_func.name, "trim_main");
|
||||
assert_eq!(trim_main_func.params.len(), 1, "trim_main has 1 parameter (s)");
|
||||
assert!(trim_main_func.body.len() >= 5, "trim_main should have at least 5 instructions");
|
||||
|
||||
// loop_step 関数の検証
|
||||
let loop_step_func = join_module.functions.get(&loop_step_id)
|
||||
.expect("loop_step function not found");
|
||||
assert_eq!(loop_step_func.name, "loop_step");
|
||||
assert_eq!(loop_step_func.params.len(), 3, "loop_step has 3 parameters (str, b, e)");
|
||||
assert!(loop_step_func.body.len() >= 10, "loop_step should have multiple instructions");
|
||||
|
||||
eprintln!("[joinir/trim] ✅ 自動変換成功(Phase 27.1)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mir_joinir_funcscanner_trim_type_sanity() {
|
||||
// Phase 27.1: 型定義の基本的なサニティチェック(常時実行)
|
||||
// trim 用の JoinFunction が作成できることを確認
|
||||
|
||||
let trim_main_id = JoinFuncId::new(10);
|
||||
let trim_main_func = JoinFunction::new(
|
||||
trim_main_id,
|
||||
"trim_main_test".to_string(),
|
||||
vec![ValueId(1)],
|
||||
);
|
||||
|
||||
assert_eq!(trim_main_func.id, trim_main_id);
|
||||
assert_eq!(trim_main_func.name, "trim_main_test");
|
||||
assert_eq!(trim_main_func.params.len(), 1);
|
||||
assert_eq!(trim_main_func.body.len(), 0);
|
||||
}
|
||||
@ -12,7 +12,8 @@ pub mod mir_funcscanner_parse_params_trim_min;
|
||||
pub mod mir_funcscanner_trim_min;
|
||||
pub mod mir_funcscanner_ssa;
|
||||
pub mod mir_joinir_min; // Phase 26-H: JoinIR型定義妥当性確認
|
||||
pub mod mir_joinir_skip_ws; // Phase 27.1: minimal_ssa_skip_ws JoinIR変換
|
||||
pub mod mir_joinir_skip_ws; // Phase 27.0: minimal_ssa_skip_ws JoinIR変換
|
||||
pub mod mir_joinir_funcscanner_trim; // Phase 27.1: FuncScannerBox.trim JoinIR変換
|
||||
pub mod mir_locals_ssa;
|
||||
pub mod mir_loopform_conditional_reassign;
|
||||
pub mod mir_loopform_exit_phi;
|
||||
|
||||
Reference in New Issue
Block a user