feat(joinir): Phase 49-3 JoinIR Frontend mainline integration

Implement AST→JSON→JoinIR→MIR pipeline in cf_loop for print_tokens:
- Add cf_loop_joinir_impl() with full pipeline:
  - AST Loop node → Program JSON
  - AstToJoinIrLowerer::lower_program_json() → JoinModule
  - convert_join_module_to_mir_with_meta() → MirModule
  - merge_joinir_mir_blocks() (MVP: logging only)

- Add Phase 49 smoke tests (2 tests):
  - phase49_joinir_mainline_pipeline_smoke
  - phase49_joinir_mainline_fallback_without_flag

- Dev flag: HAKO_JOINIR_PRINT_TOKENS_MAIN=1
- Debug flag: NYASH_JOINIR_MAINLINE_DEBUG=1

MVP limitations:
- Block merge is logging only (Phase 49-3.2 for full impl)
- if-analysis meta is empty (Phase 40+ territory)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-28 19:29:45 +09:00
parent 7cca67a7af
commit a8db5682cb
3 changed files with 268 additions and 14 deletions

View File

@ -0,0 +1,131 @@
// Phase 49-3: JoinIR Frontend Mainline Integration Test
//
// このテストは cf_loop の JoinIR Frontend mainline route が
// 正常に動作することを確認する。
//
// MVP 制限:
// - merge_joinir_mir_blocks() はログ出力のみ
// - 完全な A/B 比較は Phase 49-3.2(ブロックマージ実装)待ち
//
// テスト方法:
// HAKO_JOINIR_PRINT_TOKENS_MAIN=1 cargo test --release joinir_mainline_phase49
use crate::ast::ASTNode;
use crate::mir::MirCompiler;
use crate::parser::NyashParser;
/// Phase 49-3: JoinIR Frontend mainline パイプラインが
/// print_tokens 関数のコンパイル時にクラッシュしないことを確認
#[test]
fn phase49_joinir_mainline_pipeline_smoke() {
// Phase 49 mainline route は dev フラグで制御
std::env::set_var("HAKO_JOINIR_PRINT_TOKENS_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");
// print_tokens を含む最小限の JsonTokenizer 定義
let src = r#"
box JsonTokenizer {
tokens: ArrayBox
errors: ArrayBox
birth() {
me.tokens = new ArrayBox()
me.errors = new ArrayBox()
}
// Phase 49 ターゲット関数
print_tokens() {
local i = 0
loop(i < me.tokens.length()) {
local token = me.tokens.get(i)
print(token)
i = i + 1
}
}
}
static box Main {
main() {
local t = new JsonTokenizer()
t.print_tokens()
return 0
}
}
"#;
let ast: ASTNode = NyashParser::parse_from_string(src)
.expect("phase49: parse failed");
let mut mc = MirCompiler::with_options(false);
let result = mc.compile(ast);
// MVP: パイプラインがクラッシュしないことを確認
// Phase 49-3.2 で実際の A/B 比較を追加
assert!(
result.is_ok(),
"phase49 mainline compile should not crash: {:?}",
result.err()
);
// クリーンアップ
std::env::remove_var("HAKO_JOINIR_PRINT_TOKENS_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-3: dev フラグ OFF 時は従来経路を使用することを確認
#[test]
fn phase49_joinir_mainline_fallback_without_flag() {
// dev フラグ OFF
std::env::remove_var("HAKO_JOINIR_PRINT_TOKENS_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#"
box JsonTokenizer {
tokens: ArrayBox
birth() {
me.tokens = new ArrayBox()
}
print_tokens() {
local i = 0
loop(i < me.tokens.length()) {
i = i + 1
}
}
}
static box Main {
main() {
local t = new JsonTokenizer()
t.print_tokens()
return 0
}
}
"#;
let ast: ASTNode = NyashParser::parse_from_string(src)
.expect("phase49 fallback: parse failed");
let mut mc = MirCompiler::with_options(false);
let result = mc.compile(ast);
assert!(
result.is_ok(),
"phase49 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");
}

View File

@ -3,4 +3,5 @@ pub mod bridge;
pub mod frontend;
pub mod json;
pub mod lowering;
pub mod mainline_phase49; // Phase 49: JoinIR Frontend mainline integration
pub mod runner;