Files
hakorune/tests/normalized_joinir_min.rs

377 lines
13 KiB
Rust
Raw Normal View History

#![cfg(all(feature = "normalized_dev", debug_assertions))]
use nyash_rust::backend::mir_interpreter::MirInterpreter;
use nyash_rust::mir::join_ir::{
normalize_pattern1_minimal, normalize_pattern2_minimal, normalized_pattern1_to_structured,
normalized_pattern2_to_structured, BinOpKind, ConstValue, JoinContId, JoinFuncId,
JoinFunction, JoinInst, JoinIrPhase, JoinModule, MirLikeInst,
};
use nyash_rust::mir::join_ir::normalized::dev_env::NormalizedDevEnvGuard;
use nyash_rust::mir::join_ir::normalized::fixtures::{
build_jsonparser_atoi_structured_for_normalized_dev,
build_jsonparser_skip_ws_structured_for_normalized_dev,
build_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
};
use nyash_rust::mir::join_ir_runner::run_joinir_function;
use nyash_rust::mir::join_ir_ops::JoinValue;
use nyash_rust::mir::join_ir_vm_bridge::run_joinir_via_vm;
use nyash_rust::mir::ValueId;
fn assert_normalized_dev_ready() {
assert!(
nyash_rust::config::env::normalized_dev_enabled(),
"Phase 33: normalized_dev must be enabled for this suite (feature + env)"
);
}
fn run_joinir_runner(
module: &JoinModule,
entry: JoinFuncId,
args: &[JoinValue],
normalized: bool,
) -> JoinValue {
let _guard = NormalizedDevEnvGuard::new(normalized);
if normalized {
assert_normalized_dev_ready();
}
let mut vm = MirInterpreter::new();
run_joinir_function(&mut vm, module, entry, args).expect("JoinIR runner should succeed")
}
fn run_joinir_vm_bridge(
module: &JoinModule,
entry: JoinFuncId,
args: &[JoinValue],
normalized: bool,
) -> JoinValue {
let _guard = NormalizedDevEnvGuard::new(normalized);
if normalized {
assert_normalized_dev_ready();
}
run_joinir_via_vm(module, entry, args).expect("JoinIR→MIR execution should succeed")
}
fn build_structured_pattern1() -> JoinModule {
let mut module = JoinModule::new();
let mut loop_fn = JoinFunction::new(
JoinFuncId::new(1),
"loop_step".to_string(),
vec![ValueId(10)],
);
loop_fn.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: ValueId(11),
value: ConstValue::Integer(0),
}));
loop_fn.body.push(JoinInst::Compute(MirLikeInst::BinOp {
dst: ValueId(12),
op: BinOpKind::Add,
lhs: ValueId(10),
rhs: ValueId(11),
}));
loop_fn.body.push(JoinInst::Jump {
cont: JoinContId(2),
args: vec![ValueId(12)],
cond: None, // 単純経路: 無条件で k_exit に渡して終了
});
let mut k_exit = JoinFunction::new(JoinFuncId::new(2), "k_exit".to_string(), vec![ValueId(12)]);
k_exit.body.push(JoinInst::Ret {
value: Some(ValueId(12)),
});
module.entry = Some(loop_fn.id);
module.add_function(loop_fn);
module.add_function(k_exit);
module
}
#[test]
fn normalized_pattern1_minimal_smoke() {
let structured = build_structured_pattern1();
let normalized = normalize_pattern1_minimal(&structured);
assert_eq!(normalized.phase, JoinIrPhase::Normalized);
assert!(!normalized.env_layouts.is_empty());
assert!(!normalized.functions.is_empty());
// Structured バックアップが保持されていることを確認
let restored = normalized
.to_structured()
.expect("structured backup should exist");
assert!(restored.is_structured());
assert_eq!(restored.functions.len(), structured.functions.len());
}
#[test]
fn normalized_pattern1_roundtrip_structured_equivalent() {
let structured = build_structured_pattern1();
let normalized = normalize_pattern1_minimal(&structured);
let reconstructed = normalized_pattern1_to_structured(&normalized);
assert!(reconstructed.is_structured());
assert_eq!(reconstructed.functions.len(), structured.functions.len());
for (fid, func) in &structured.functions {
let recon = reconstructed
.functions
.get(fid)
.expect("function missing after reconstruction");
assert_eq!(recon.params.len(), func.params.len());
}
}
#[test]
fn normalized_pattern1_exec_matches_structured() {
let structured = build_structured_pattern1();
let normalized = normalize_pattern1_minimal(&structured);
let reconstructed = normalized_pattern1_to_structured(&normalized);
let entry = structured.entry.unwrap_or(JoinFuncId::new(1));
let input = [JoinValue::Int(0)];
let result_structured = run_joinir_vm_bridge(&structured, entry, &input, false);
let result_norm = run_joinir_vm_bridge(&reconstructed, entry, &input, false);
assert_eq!(result_structured, result_norm);
}
#[test]
fn normalized_pattern1_exec_matches_structured_roundtrip_backup() {
let structured = build_structured_pattern1();
let normalized = normalize_pattern1_minimal(&structured);
let reconstructed = normalized_pattern1_to_structured(&normalized);
let restored_backup = normalized
.to_structured()
.expect("structured backup should be present");
let entry = structured.entry.unwrap_or(JoinFuncId::new(1));
let input = [JoinValue::Int(0)];
let base = run_joinir_vm_bridge(&structured, entry, &input, false);
let recon = run_joinir_vm_bridge(&reconstructed, entry, &input, false);
let restored = run_joinir_vm_bridge(&restored_backup, entry, &input, false);
assert_eq!(base, recon);
assert_eq!(base, restored);
}
#[test]
fn normalized_pattern2_roundtrip_structure() {
let structured = build_pattern2_minimal_structured();
let normalized = normalize_pattern2_minimal(&structured);
assert_eq!(normalized.phase, JoinIrPhase::Normalized);
let reconstructed = normalized_pattern2_to_structured(&normalized);
assert!(reconstructed.is_structured());
assert_eq!(reconstructed.functions.len(), structured.functions.len());
for name in ["main", "loop_step", "k_exit"] {
let original_has = structured.functions.values().any(|f| f.name == name);
let reconstructed_has = reconstructed.functions.values().any(|f| f.name == name);
assert!(
original_has && reconstructed_has,
"expected function '{}' to exist in both modules",
name
);
}
}
#[test]
fn normalized_pattern2_exec_matches_structured() {
let structured = build_pattern2_minimal_structured();
let normalized = normalize_pattern2_minimal(&structured);
let reconstructed = normalized_pattern2_to_structured(&normalized);
let entry = structured.entry.unwrap_or(JoinFuncId::new(0));
let input = [JoinValue::Int(0)];
let base = run_joinir_vm_bridge(&structured, entry, &input, false);
let recon = run_joinir_vm_bridge(&reconstructed, entry, &input, false);
assert_eq!(base, recon);
}
#[test]
#[should_panic(expected = "normalize_pattern2_minimal")]
fn normalized_pattern2_rejects_non_pattern2_structured() {
// Pattern1 Structured module should be rejected by Pattern2 normalizer.
let structured = build_structured_pattern1();
let _ = normalize_pattern2_minimal(&structured);
}
#[test]
fn normalized_pattern2_real_loop_roundtrip_structure() {
let structured = build_pattern2_break_fixture_structured();
let normalized = normalize_pattern2_minimal(&structured);
let reconstructed = normalized_pattern2_to_structured(&normalized);
assert!(reconstructed.is_structured());
assert_eq!(structured.functions.len(), reconstructed.functions.len());
assert_eq!(structured.entry, reconstructed.entry);
let original_names: Vec<_> = structured
.functions
.values()
.map(|f| f.name.clone())
.collect();
for name in original_names {
let reconstructed_has = reconstructed.functions.values().any(|f| f.name == name);
assert!(reconstructed_has, "function '{}' missing after roundtrip", name);
}
}
#[test]
fn normalized_pattern2_real_loop_exec_matches_structured() {
let structured = build_pattern2_break_fixture_structured();
let normalized = normalize_pattern2_minimal(&structured);
let reconstructed = normalized_pattern2_to_structured(&normalized);
let entry = structured.entry.expect("structured entry required");
let cases = [0, 1, 3, 5];
for n in cases {
let input = [JoinValue::Int(n)];
let base = run_joinir_vm_bridge(&structured, entry, &input, false);
let recon = run_joinir_vm_bridge(&reconstructed, entry, &input, false);
assert_eq!(base, recon, "mismatch at n={}", n);
let expected_sum = n * (n.saturating_sub(1)) / 2;
assert_eq!(
base,
JoinValue::Int(expected_sum),
"unexpected loop result at n={}",
n
);
}
}
#[test]
fn normalized_pattern1_runner_dev_switch_matches_structured() {
let structured = build_structured_pattern1();
let entry = structured.entry.expect("structured entry required");
let input = [JoinValue::Int(7)];
let base = run_joinir_runner(&structured, entry, &input, false);
let dev = run_joinir_runner(&structured, entry, &input, true);
assert_eq!(base, dev);
assert_eq!(base, JoinValue::Int(7));
}
#[test]
fn normalized_pattern2_runner_dev_switch_matches_structured() {
let structured = build_pattern2_break_fixture_structured();
let entry = structured.entry.expect("structured entry required");
let cases = [0, 1, 3, 5];
for n in cases {
let input = [JoinValue::Int(n)];
let base = run_joinir_runner(&structured, entry, &input, false);
let dev = run_joinir_runner(&structured, entry, &input, true);
assert_eq!(base, dev, "runner mismatch at n={}", n);
let expected_sum = n * (n.saturating_sub(1)) / 2;
assert_eq!(
dev,
JoinValue::Int(expected_sum),
"runner result mismatch at n={}",
n
);
}
}
#[test]
fn normalized_pattern2_jsonparser_runner_dev_switch_matches_structured() {
let structured = build_jsonparser_skip_ws_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let cases = [0, 1, 2, 5];
for len in cases {
let input = [JoinValue::Int(len)];
let base = run_joinir_runner(&structured, entry, &input, false);
let dev = run_joinir_runner(&structured, entry, &input, true);
assert_eq!(base, dev, "runner mismatch at len={}", len);
assert_eq!(dev, JoinValue::Int(len), "unexpected result at len={}", len);
}
}
#[test]
fn normalized_pattern2_vm_bridge_direct_matches_structured() {
let structured = build_pattern2_break_fixture_structured();
let entry = structured.entry.expect("structured entry required");
let cases = [0, 1, 3, 5];
for n in cases {
let input = [JoinValue::Int(n)];
let base = run_joinir_vm_bridge(&structured, entry, &input, false);
let dev = run_joinir_vm_bridge(&structured, entry, &input, true);
assert_eq!(base, dev, "vm bridge mismatch at n={}", n);
let expected_sum = n * (n.saturating_sub(1)) / 2;
assert_eq!(
dev,
JoinValue::Int(expected_sum),
"vm bridge result mismatch at n={}",
n
);
}
}
#[test]
fn normalized_pattern1_vm_bridge_direct_matches_structured() {
let structured = build_structured_pattern1();
let entry = structured.entry.expect("structured entry required");
let cases = [0, 5, 7];
for n in cases {
let input = [JoinValue::Int(n)];
let base = run_joinir_vm_bridge(&structured, entry, &input, false);
let dev = run_joinir_vm_bridge(&structured, entry, &input, true);
assert_eq!(base, dev, "vm bridge mismatch at n={}", n);
assert_eq!(dev, JoinValue::Int(n), "unexpected result at n={}", n);
}
}
#[test]
fn normalized_pattern2_jsonparser_vm_bridge_direct_matches_structured() {
let structured = build_jsonparser_skip_ws_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let cases = [0, 1, 2, 5];
for len in cases {
let input = [JoinValue::Int(len)];
let base = run_joinir_vm_bridge(&structured, entry, &input, false);
let dev = run_joinir_vm_bridge(&structured, entry, &input, true);
assert_eq!(base, dev, "vm bridge mismatch at len={}", len);
assert_eq!(dev, JoinValue::Int(len), "unexpected result at len={}", len);
}
}
#[test]
fn normalized_pattern2_jsonparser_atoi_vm_bridge_direct_matches_structured() {
let structured = build_jsonparser_atoi_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let cases = [
("42", 2, 42),
("123abc", 6, 123),
("007", 3, 7),
("", 0, 0),
];
for (s, len, expected) in cases {
let input = [JoinValue::Str(s.to_string()), JoinValue::Int(len)];
let base = run_joinir_vm_bridge(&structured, entry, &input, false);
let dev = run_joinir_vm_bridge(&structured, entry, &input, true);
assert_eq!(base, dev, "vm bridge mismatch for input '{}'", s);
assert_eq!(
dev,
JoinValue::Int(expected),
"unexpected result for input '{}'",
s
);
}
}