fix(joinir): Stage-1 string concat BinOp::Or → Add + ArrayBox support

Fixes:
1. BinOp::Or → BinOp::Add for string concatenation in Stage-1 lowering
2. ArrayBox/MapBox support via JoinValue::BoxRef (ChatGPT implementation)

Results:
- n=0: JoinIR → "init"  (VM → "void" PHI bug)
- n=3: JoinIR → "ABC"  (VM → "void" PHI bug)

Stage-1 JoinIR VM Bridge now fully working!

🤖 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-25 13:33:01 +09:00
parent 6d10fc45ba
commit e93727dd37
2 changed files with 39 additions and 29 deletions

View File

@ -12,7 +12,10 @@
// - Phase 30.x: Stage-1 UsingResolver minimal A/B test
use crate::ast::ASTNode;
use crate::backend::VM;
use crate::backend::{VM, VMValue};
use crate::boxes::array::ArrayBox;
use crate::boxes::basic::StringBox;
use crate::boxes::map_box::MapBox;
use crate::mir::join_ir::lowering::stage1_using_resolver::lower_stage1_usingresolver_to_joinir;
use crate::mir::join_ir::JoinFuncId;
use crate::mir::join_ir_ops::JoinValue;
@ -20,6 +23,24 @@ use crate::mir::join_ir_vm_bridge::run_joinir_via_vm;
use crate::mir::MirCompiler;
use crate::parser::NyashParser;
fn join_value_from_box(b: Box<dyn crate::box_trait::NyashBox>) -> JoinValue {
let vm_val = VMValue::from_nyash_box(b);
JoinValue::from_vm_value(&vm_val).expect("box conversion failed")
}
fn make_entries(values: &[&str]) -> JoinValue {
let mut arr = ArrayBox::new();
for v in values {
let _ = arr.push(Box::new(StringBox::new(*v)));
}
join_value_from_box(Box::new(arr))
}
fn make_empty_map() -> JoinValue {
let map = MapBox::new();
join_value_from_box(Box::new(map))
}
/// 実験トグルチェック(モジュール内に閉じ込め)
fn require_experiment_toggle() -> bool {
if std::env::var("NYASH_JOINIR_VM_BRIDGE").ok().as_deref() != Some("1") {
@ -245,28 +266,16 @@ fn joinir_vm_bridge_stage1_usingresolver_route_b_execution() {
eprintln!("[joinir_vm_bridge_test/stage1/route_b] JoinIR module created: {} functions", join_module.functions.len());
// Stage-1 JoinIR の引数:
// resolve_entries(entries, n, modules, seen, prefix_init)
// - entries: ArrayBox (JoinValue 未対応)
// - n: Integer
// - modules: MapBox (JoinValue 未対応)
// - seen: MapBox (JoinValue 未対応)
// - prefix_init: String
//
// n=0 の場合、ループは実行されないので entries/modules/seen にアクセスしない
// → Int(0) で呼び出してみて、何が起こるか確認
eprintln!("[joinir_vm_bridge_test/stage1/route_b] Attempting run_joinir_via_vm with n=0");
eprintln!("[joinir_vm_bridge_test/stage1/route_b] Note: ArrayBox/MapBox args passed as Int(0) placeholder");
eprintln!("[joinir_vm_bridge_test/stage1/route_b] Attempting run_joinir_via_vm with n=0 (Array/Map supported)");
// JoinIR bridge 呼び出し - どこで止まるか観察
let result = run_joinir_via_vm(
&join_module,
JoinFuncId::new(0),
&[
JoinValue::Int(0), // entries placeholder (should not be accessed if n=0)
JoinValue::Int(0), // n = 0 (loop won't execute)
JoinValue::Int(0), // modules placeholder
JoinValue::Int(0), // seen placeholder
make_entries(&[]),
JoinValue::Int(0), // n = 0 (loop won't execute)
make_empty_map(),
make_empty_map(),
JoinValue::Str("init".to_string()), // prefix_init
],
);
@ -275,22 +284,24 @@ fn joinir_vm_bridge_stage1_usingresolver_route_b_execution() {
Ok(value) => {
eprintln!("[joinir_vm_bridge_test/stage1/route_b] ✅ Execution succeeded: {:?}", value);
// n=0 の場合、ループは実行されず prefix_init がそのまま返るはず
match value {
match &value {
JoinValue::Str(s) => {
eprintln!("[joinir_vm_bridge_test/stage1/route_b] Result: {:?}", s);
if s == "init" {
eprintln!("[joinir_vm_bridge_test/stage1/route_b] ✅ JoinIR returned correct 'init'!");
} else {
panic!("expected 'init', got {}", s);
}
}
_ => {
eprintln!("[joinir_vm_bridge_test/stage1/route_b] Unexpected result type: {:?}", value);
panic!("Unexpected result type: {:?}", value);
}
}
}
Err(e) => {
eprintln!("[joinir_vm_bridge_test/stage1/route_b] ❌ Execution failed: {:?}", e);
eprintln!("[joinir_vm_bridge_test/stage1/route_b] This error shows where VM bridge needs extension");
// エラーが出ても panic しない - 何が足りないかの情報を得るため
panic!("JoinIR bridge failed: {:?}", e);
}
}
@ -337,10 +348,10 @@ fn joinir_vm_bridge_stage1_usingresolver_route_b_with_entries() {
&join_module,
JoinFuncId::new(0),
&[
JoinValue::Int(0), // entries - Int(0) では get() 失敗するはず
make_entries(&["A", "B", "C"]),
JoinValue::Int(3), // n = 3 (loop will execute 3 times)
JoinValue::Int(0), // modules placeholder
JoinValue::Int(0), // seen placeholder
make_empty_map(),
make_empty_map(),
JoinValue::Str("".to_string()), // prefix_init = ""
],
);
@ -354,18 +365,17 @@ fn joinir_vm_bridge_stage1_usingresolver_route_b_with_entries() {
if s == "ABC" {
eprintln!("[joinir_vm_bridge_test/stage1/route_b_with_entries] ✅ JoinIR returned correct 'ABC'!");
} else {
eprintln!("[joinir_vm_bridge_test/stage1/route_b_with_entries] ⚠️ Got '{}' (possibly partial or wrong)", s);
panic!("expected 'ABC', got {}", s);
}
}
_ => {
eprintln!("[joinir_vm_bridge_test/stage1/route_b_with_entries] Unexpected result type: {:?}", value);
panic!("[joinir_vm_bridge_test/stage1/route_b_with_entries] Unexpected result type: {:?}", value);
}
}
}
Err(e) => {
eprintln!("[joinir_vm_bridge_test/stage1/route_b_with_entries] ❌ Execution failed: {:?}", e);
eprintln!("[joinir_vm_bridge_test/stage1/route_b_with_entries] This shows ArrayBox/BoxCall needs JoinIR extension");
// エラーを期待通り - ArrayBox サポートが必要なことを確認
panic!("JoinIR bridge failed: {:?}", e);
}
}