feat(joinir): Phase 49-4 multi-target routing with graceful fallback
- Add ArrayExtBox.filter/2 as second JoinIR mainline target - Fix function name arity: print_tokens is /0 (no implicit me in arity) - Construct proper JSON v0 format with defs array for JoinIR Frontend - Add catch_unwind for graceful fallback on unsupported patterns - Add 3 array_filter tests (smoke, fallback, A/B comparison) - All 6 Phase 49 tests passing Dev flags: - HAKO_JOINIR_PRINT_TOKENS_MAIN=1: JsonTokenizer.print_tokens/0 - HAKO_JOINIR_ARRAY_FILTER_MAIN=1: ArrayExtBox.filter/2 Note: Currently all loops fall back to legacy LoopBuilder due to JoinIR Frontend expecting hardcoded variable names (i, acc, n). Full JoinIR integration pending variable scope support in Phase 50+. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
// Phase 49-3.2: JoinIR Frontend Mainline Integration Test
|
||||
// Phase 49: JoinIR Frontend Mainline Integration Test
|
||||
//
|
||||
// このテストは cf_loop の JoinIR Frontend mainline route が
|
||||
// 正常に動作することを確認する。
|
||||
@ -7,8 +7,13 @@
|
||||
// - merge_joinir_mir_blocks() によるブロックマージ
|
||||
// - A/B 比較テスト(Route A vs Route B)
|
||||
//
|
||||
// Phase 49-4 実装済み:
|
||||
// - ArrayExtBox.filter/2 対応
|
||||
// - HAKO_JOINIR_ARRAY_FILTER_MAIN=1 dev フラグ追加
|
||||
//
|
||||
// テスト方法:
|
||||
// HAKO_JOINIR_PRINT_TOKENS_MAIN=1 cargo test --release joinir_mainline_phase49
|
||||
// HAKO_JOINIR_ARRAY_FILTER_MAIN=1 cargo test --release phase49_joinir_array_filter
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::MirCompiler;
|
||||
@ -222,3 +227,201 @@ static box Main {
|
||||
std::env::remove_var("HAKO_PARSER_STAGE3");
|
||||
std::env::remove_var("NYASH_DISABLE_PLUGINS");
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Phase 49-4: ArrayExtBox.filter/2 Tests
|
||||
// =============================================================================
|
||||
|
||||
/// Phase 49-4: JoinIR Frontend mainline パイプラインが
|
||||
/// ArrayExtBox.filter 関数のコンパイル時にクラッシュしないことを確認
|
||||
#[test]
|
||||
fn phase49_joinir_array_filter_smoke() {
|
||||
// Phase 49-4 mainline route は dev フラグで制御
|
||||
std::env::set_var("HAKO_JOINIR_ARRAY_FILTER_MAIN", "1");
|
||||
std::env::set_var("NYASH_JOINIR_MAINLINE_DEBUG", "1");
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_DISABLE_PLUGINS", "1");
|
||||
|
||||
// ArrayExtBox.filter 簡易実装(if-in-loop パターン)
|
||||
// fn パラメータは pred に変更(予約語競合回避)
|
||||
let src = r#"
|
||||
static box ArrayExtBox {
|
||||
filter(arr, pred) {
|
||||
local out = new ArrayBox()
|
||||
local i = 0
|
||||
local n = arr.size()
|
||||
loop(i < n) {
|
||||
local v = arr.get(i)
|
||||
if pred(v) {
|
||||
out.push(v)
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(src)
|
||||
.expect("phase49-4: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let result = mc.compile(ast);
|
||||
|
||||
// パイプラインがクラッシュしないことを確認
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"phase49-4 array_filter mainline compile should not crash: {:?}",
|
||||
result.err()
|
||||
);
|
||||
|
||||
// クリーンアップ
|
||||
std::env::remove_var("HAKO_JOINIR_ARRAY_FILTER_MAIN");
|
||||
std::env::remove_var("NYASH_JOINIR_MAINLINE_DEBUG");
|
||||
std::env::remove_var("NYASH_PARSER_STAGE3");
|
||||
std::env::remove_var("HAKO_PARSER_STAGE3");
|
||||
std::env::remove_var("NYASH_DISABLE_PLUGINS");
|
||||
}
|
||||
|
||||
/// Phase 49-4: dev フラグ OFF 時は従来経路を使用することを確認
|
||||
#[test]
|
||||
fn phase49_joinir_array_filter_fallback() {
|
||||
// dev フラグ OFF
|
||||
std::env::remove_var("HAKO_JOINIR_ARRAY_FILTER_MAIN");
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_DISABLE_PLUGINS", "1");
|
||||
|
||||
let src = r#"
|
||||
static box ArrayExtBox {
|
||||
filter(arr, pred) {
|
||||
local out = new ArrayBox()
|
||||
local i = 0
|
||||
local n = arr.size()
|
||||
loop(i < n) {
|
||||
local v = arr.get(i)
|
||||
if pred(v) {
|
||||
out.push(v)
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let ast: ASTNode = NyashParser::parse_from_string(src)
|
||||
.expect("phase49-4 fallback: parse failed");
|
||||
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let result = mc.compile(ast);
|
||||
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"phase49-4 fallback compile should succeed: {:?}",
|
||||
result.err()
|
||||
);
|
||||
|
||||
// クリーンアップ
|
||||
std::env::remove_var("NYASH_PARSER_STAGE3");
|
||||
std::env::remove_var("HAKO_PARSER_STAGE3");
|
||||
std::env::remove_var("NYASH_DISABLE_PLUGINS");
|
||||
}
|
||||
|
||||
/// Phase 49-4: A/B 比較テスト - Route A (legacy) vs Route B (JoinIR)
|
||||
/// ArrayExtBox.filter版
|
||||
#[test]
|
||||
fn phase49_joinir_array_filter_ab_comparison() {
|
||||
let src = r#"
|
||||
static box ArrayExtBox {
|
||||
filter(arr, pred) {
|
||||
local out = new ArrayBox()
|
||||
local i = 0
|
||||
local n = arr.size()
|
||||
loop(i < n) {
|
||||
local v = arr.get(i)
|
||||
if pred(v) {
|
||||
out.push(v)
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
// Route A: Legacy path (flag OFF)
|
||||
std::env::remove_var("HAKO_JOINIR_ARRAY_FILTER_MAIN");
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_DISABLE_PLUGINS", "1");
|
||||
|
||||
let ast_a: ASTNode = NyashParser::parse_from_string(src)
|
||||
.expect("phase49-4 A/B: parse failed (Route A)");
|
||||
let mut mc_a = MirCompiler::with_options(false);
|
||||
let result_a = mc_a.compile(ast_a);
|
||||
assert!(
|
||||
result_a.is_ok(),
|
||||
"Route A compile should succeed: {:?}",
|
||||
result_a.err()
|
||||
);
|
||||
let module_a = result_a.unwrap().module;
|
||||
let blocks_a: usize = module_a
|
||||
.functions
|
||||
.values()
|
||||
.map(|f| f.blocks.len())
|
||||
.sum();
|
||||
|
||||
// Route B: JoinIR Frontend path (flag ON)
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("HAKO_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_DISABLE_PLUGINS", "1");
|
||||
std::env::set_var("HAKO_JOINIR_ARRAY_FILTER_MAIN", "1");
|
||||
|
||||
let ast_b: ASTNode = NyashParser::parse_from_string(src)
|
||||
.expect("phase49-4 A/B: parse failed (Route B)");
|
||||
let mut mc_b = MirCompiler::with_options(false);
|
||||
let result_b = mc_b.compile(ast_b);
|
||||
assert!(
|
||||
result_b.is_ok(),
|
||||
"Route B compile should succeed: {:?}",
|
||||
result_b.err()
|
||||
);
|
||||
let module_b = result_b.unwrap().module;
|
||||
let blocks_b: usize = module_b
|
||||
.functions
|
||||
.values()
|
||||
.map(|f| f.blocks.len())
|
||||
.sum();
|
||||
|
||||
// Log block counts for debugging
|
||||
eprintln!(
|
||||
"[phase49-4 A/B filter] Route A: {} total blocks, Route B: {} total blocks",
|
||||
blocks_a, blocks_b
|
||||
);
|
||||
|
||||
// クリーンアップ
|
||||
std::env::remove_var("HAKO_JOINIR_ARRAY_FILTER_MAIN");
|
||||
std::env::remove_var("NYASH_PARSER_STAGE3");
|
||||
std::env::remove_var("HAKO_PARSER_STAGE3");
|
||||
std::env::remove_var("NYASH_DISABLE_PLUGINS");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user