Files
hakorune/tests/normalized_joinir_min.rs
nyash-codex 7b0db59100 feat(joinir): Phase 53 - SELFHOST-NORM-DEV-EXPAND implementation
Expanded selfhost dev Normalized target with 2 practical P2/P3 loop variations,
strengthened structural signature axis, and implemented two-stage detection.

Key Changes:

1. Documentation (phase49-selfhost-joinir-depth2-design.md +128 lines):
   - Added Phase 53 section with candidate selection rationale
   - Documented two-stage detector strategy (structural primary + dev-only name guard)
   - Defined structural axis strengthening (carrier count/type, branch patterns)

2. Fixtures (+210 lines):
   - selfhost_args_parse_p2.program.json (60 lines): P2 with String carrier + conditional branching
   - selfhost_stmt_count_p3.program.json (150 lines): P3 with 5 carriers + multi-branch if-else

3. Structured Builders (fixtures.rs +48 lines):
   - build_selfhost_args_parse_p2_structured_for_normalized_dev()
   - build_selfhost_stmt_count_p3_structured_for_normalized_dev()

4. ShapeGuard Two-Stage Detection (shape_guard.rs +80 lines):
   - Added SelfhostArgsParseP2/SelfhostStmtCountP3 to NormalizedDevShape enum
   - Implemented is_selfhost_args_parse_p2(): P2 core family + name guard
   - Implemented is_selfhost_stmt_count_p3(): 2-10 carrier check + name guard
   - Updated capability_for_shape() mappings

5. Bridge Integration (bridge.rs +8 lines, normalized.rs +10 lines):
   - Added shape handlers delegating to existing normalizers
   - Added roundtrip reconstruction handlers

6. Entry Point Registration (ast_lowerer/mod.rs +2 lines):
   - Registered selfhost_args_parse_p2/selfhost_stmt_count_p3 as LoopFrontend routes

7. Dev VM Comparison Tests (normalized_joinir_min.rs +40 lines):
   - normalized_selfhost_args_parse_p2_vm_bridge_direct_matches_structured()
   - normalized_selfhost_stmt_count_p3_vm_bridge_direct_matches_structured()

8. Test Context Fix (dev_env.rs):
   - Added thread-local test context depth counter
   - Fixed deadlock in nested test_ctx() calls via reentrant with_dev_env_if_unset()

Structural Axis Growth:

P2 family:
- Carrier count: 1-3 (unchanged)
- NEW: Type diversity (Integer/String mixed)
- NEW: Conditional branching patterns (Eq-heavy comparisons)

P3 family:
- NEW: Carrier count upper bound: 2-10 (was 2-4)
- NEW: Multi-branch if-else (5+ branches with nested structure)
- NEW: Complex conditional patterns

Test Results:
- normalized_dev: 40/40 PASS (including 2 new tests)
- lib regression: 939 PASS, 56 ignored
- Existing behavior unchanged (normalized_dev feature-gated)

Phase 53 Achievements:
 P2/P3 each gained 1 practical variation (2 total)
 Two-stage detection: structural primary + dev-only name guard
 Structural axis expanded: 4 axes (carrier count/type/Compare/branch patterns)
 All tests PASS, no regressions
 Test context deadlock fixed (0.04s for 29 tests)

Files Modified: 14 files
Lines Added: ~516 lines (net)
Implementation: Pure additive (feature-gated)

Next Phase (54+):
- Accumulate 6+ loops per P2/P3 family
- Achieve 5+ stable structural axes
- Target < 5% false positive rate
- Then shrink/remove name guard scope
2025-12-12 16:40:20 +09:00

963 lines
34 KiB
Rust

#![cfg(all(feature = "normalized_dev", debug_assertions))]
use nyash_rust::backend::{mir_interpreter::MirInterpreter, VMValue};
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::{
normalized_dev_enabled, test_ctx, NormalizedDevEnvGuard, NormalizedTestContext,
};
use nyash_rust::mir::join_ir::normalized::fixtures::{
build_jsonparser_atoi_structured_for_normalized_dev,
build_jsonparser_atoi_real_structured_for_normalized_dev,
build_jsonparser_parse_array_continue_skip_ws_structured_for_normalized_dev,
build_jsonparser_parse_number_real_structured_for_normalized_dev,
build_jsonparser_parse_object_continue_skip_ws_structured_for_normalized_dev,
build_jsonparser_skip_ws_real_structured_for_normalized_dev,
build_jsonparser_skip_ws_structured_for_normalized_dev,
build_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
build_pattern3_if_sum_min_structured_for_normalized_dev,
build_pattern3_if_sum_multi_min_structured_for_normalized_dev,
build_pattern3_json_if_sum_min_structured_for_normalized_dev,
build_pattern4_continue_min_structured_for_normalized_dev,
build_selfhost_args_parse_p2_structured_for_normalized_dev,
build_selfhost_if_sum_p3_ext_structured_for_normalized_dev,
build_selfhost_if_sum_p3_structured_for_normalized_dev,
build_selfhost_stmt_count_p3_structured_for_normalized_dev,
build_selfhost_token_scan_p2_accum_structured_for_normalized_dev,
build_selfhost_token_scan_p2_structured_for_normalized_dev,
};
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::{
convert_join_module_to_mir_with_meta, run_joinir_via_vm,
};
use nyash_rust::mir::ValueId;
use std::collections::BTreeMap;
fn normalized_dev_test_ctx() -> NormalizedTestContext<'static> {
let ctx = test_ctx();
assert!(
normalized_dev_enabled(),
"Phase 40: normalized_dev must be enabled for normalized_* tests (feature + NYASH_JOINIR_NORMALIZED_DEV_RUN=1)"
);
ctx
}
fn assert_normalized_dev_ready() {
assert!(
normalized_dev_enabled(),
"Phase 40: normalized_dev must be enabled for normalized_* tests (feature + NYASH_JOINIR_NORMALIZED_DEV_RUN=1)"
);
}
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 run_joinir_vm_bridge_structured_only(
module: &JoinModule,
entry: JoinFuncId,
args: &[JoinValue],
) -> JoinValue {
let mir =
convert_join_module_to_mir_with_meta(module, &BTreeMap::new()).expect("structured bridge");
let mut vm = MirInterpreter::new();
let entry_name = format!("join_func_{}", entry.0);
let vm_args: Vec<VMValue> = args.iter().cloned().map(|v| v.into_vm_value()).collect();
let result = vm
.execute_function_with_args(&mir, &entry_name, &vm_args)
.expect("VM execution should succeed");
JoinValue::from_vm_value(&result).expect("result conversion")
}
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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_jsonparser_parse_number_real_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_jsonparser_parse_number_real_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let cases = [
("42", 0, "42"),
("123abc", 0, "123"),
("9", 0, "9"),
("abc", 0, ""),
("xx7yy", 2, "7"),
("007", 0, "007"),
];
for (s, pos, expected) in cases {
let input = [JoinValue::Str(s.to_string()), JoinValue::Int(pos)];
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::Str(expected.to_string()),
"unexpected result for input '{}' (pos={}) (expected num_str)",
s,
pos
);
}
}
#[test]
fn normalized_pattern2_exec_matches_structured() {
let _ctx = normalized_dev_test_ctx();
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() {
let _ctx = normalized_dev_test_ctx();
// 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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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 _ctx = normalized_dev_test_ctx();
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_skip_ws_real_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_jsonparser_skip_ws_real_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let cases = [
(" abc", 0, 3),
("abc", 0, 0),
(" \t\nx", 0, 3),
(" \t\nx", 2, 3),
];
for (s, pos, expected) in cases {
let input = [JoinValue::Str(s.to_string()), JoinValue::Int(pos)];
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 '{}' (pos={})",
s,
pos
);
}
}
#[test]
fn normalized_pattern2_jsonparser_atoi_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
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
);
}
}
#[test]
fn normalized_pattern2_jsonparser_atoi_real_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_jsonparser_atoi_real_structured_for_normalized_dev();
if nyash_rust::config::env::joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev/test] structured jsonparser_atoi_real: {:#?}",
structured
);
let normalized = normalize_pattern2_minimal(&structured);
eprintln!(
"[joinir/normalized-dev/test] normalized jsonparser_atoi_real: {:#?}",
normalized
);
}
let entry = structured.entry.expect("structured entry required");
let cases = [
("42", 42),
("123abc", 123),
("007", 7),
("", 0),
("abc", 0),
("-42", -42),
("+7", 7),
("-0", 0),
("-12x", -12),
("+", 0),
("-", 0),
];
for (s, expected) in cases {
let input = [JoinValue::Str(s.to_string())];
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
);
}
}
#[test]
fn normalized_selfhost_token_scan_p2_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_selfhost_token_scan_p2_structured_for_normalized_dev();
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 for n={}", n);
assert_eq!(
dev,
JoinValue::Int(n),
"unexpected result for selfhost_token_scan_p2 n={}",
n
);
}
}
#[test]
fn normalized_selfhost_token_scan_p2_accum_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_selfhost_token_scan_p2_accum_structured_for_normalized_dev();
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 for selfhost_token_scan_p2_accum n={}", n);
}
}
#[test]
fn normalized_pattern3_if_sum_minimal_runner_dev_switch_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_pattern3_if_sum_min_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
// phase212_if_sum_min.hako 相当: sum=2 になることを期待
let input: [JoinValue; 0] = [];
let base = run_joinir_runner(&structured, entry, &input, false);
let dev = run_joinir_runner(&structured, entry, &input, true);
assert_eq!(base, dev, "runner mismatch for P3 minimal if-sum");
assert_eq!(
dev,
JoinValue::Int(2),
"unexpected result for P3 minimal if-sum (expected sum=2)",
);
}
#[test]
fn normalized_pattern3_if_sum_multi_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_pattern3_if_sum_multi_min_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let input = [JoinValue::Int(0)];
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 P3 if-sum multi");
assert_eq!(
dev,
JoinValue::Int(2),
"unexpected result for P3 if-sum multi (expected sum=2)"
);
}
#[test]
fn normalized_pattern3_json_if_sum_min_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_pattern3_json_if_sum_min_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let input = [JoinValue::Int(0)];
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 P3 json if-sum");
assert_eq!(
dev,
JoinValue::Int(10),
"unexpected result for P3 json if-sum (expected sum=10)"
);
}
#[test]
fn normalized_selfhost_if_sum_p3_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_selfhost_if_sum_p3_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let cases = [0, 1, 3, 4];
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 for selfhost_if_sum_p3 n={}", n);
}
}
#[test]
fn normalized_selfhost_if_sum_p3_ext_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_selfhost_if_sum_p3_ext_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let cases = [0, 1, 3, 4];
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 for selfhost_if_sum_p3_ext n={}", n);
}
}
/// Phase 53: selfhost args-parse P2 (practical variation with string carrier)
#[test]
fn normalized_selfhost_args_parse_p2_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_selfhost_args_parse_p2_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
// Test different argc values: 0, 1, 2, 3
let cases = [0, 1, 2, 3];
for argc in cases {
let input = [JoinValue::Int(argc)];
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 selfhost_args_parse_p2 argc={}", argc);
}
}
/// Phase 53: selfhost stmt-count P3 (practical variation with multi-branch if-else)
#[test]
fn normalized_selfhost_stmt_count_p3_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_selfhost_stmt_count_p3_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
// Test different statement counts: 0, 5, 10, 15
let cases = [0, 5, 10, 15];
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 for selfhost_stmt_count_p3 n={}", n);
}
}
#[cfg(feature = "normalized_dev")]
#[test]
fn test_phase46_canonical_set_includes_p2_mid() {
use nyash_rust::mir::join_ir::normalized::shape_guard::{
is_canonical_shape, NormalizedDevShape,
};
// Phase 46: Verify P2-Mid patterns are canonical
assert!(is_canonical_shape(&NormalizedDevShape::JsonparserAtoiReal));
assert!(is_canonical_shape(
&NormalizedDevShape::JsonparserParseNumberReal
));
assert!(is_canonical_shape(
&NormalizedDevShape::Pattern3IfSumMinimal
));
assert!(is_canonical_shape(
&NormalizedDevShape::Pattern3IfSumMulti
));
assert!(is_canonical_shape(
&NormalizedDevShape::Pattern3IfSumJson
));
// Verify P2-Core patterns still canonical
assert!(is_canonical_shape(&NormalizedDevShape::Pattern2Mini));
assert!(is_canonical_shape(&NormalizedDevShape::JsonparserSkipWsMini));
assert!(is_canonical_shape(&NormalizedDevShape::JsonparserSkipWsReal));
assert!(is_canonical_shape(&NormalizedDevShape::JsonparserAtoiMini));
}
/// Phase 47-A: Test P3 minimal normalization
#[test]
fn test_phase47a_pattern3_if_sum_minimal_normalization() {
use nyash_rust::mir::join_ir::normalized::normalize_pattern3_if_sum_minimal;
let module = build_pattern3_if_sum_min_structured_for_normalized_dev();
// Test that normalization succeeds (includes shape detection internally)
let result = normalize_pattern3_if_sum_minimal(&module);
assert!(
result.is_ok(),
"P3 normalization should succeed (shape detection + normalization): {:?}",
result.err()
);
let normalized = result.unwrap();
assert_eq!(
normalized.functions.len(),
module.functions.len(),
"Normalized function count should match Structured"
);
// Verify normalized module has proper phase
assert_eq!(
normalized.phase,
nyash_rust::mir::join_ir::JoinIrPhase::Normalized,
"Normalized module should have Normalized phase"
);
}
/// Phase 47-A: Test P3 VM execution (basic smoke test)
#[test]
fn test_phase47a_pattern3_if_sum_minimal_runner() {
let module = build_pattern3_if_sum_min_structured_for_normalized_dev();
// Basic test: module should be runnable through JoinIR runner
// This test verifies the P3 fixture is valid and generates proper JoinIR
assert_eq!(module.functions.len(), 3, "P3 should have 3 functions");
let entry = module.entry.expect("P3 should have entry function");
assert_eq!(entry.0, 0, "Entry should be function 0");
}
/// Phase 48-A: Test P4 minimal normalization
#[test]
fn test_phase48a_pattern4_continue_minimal_normalization() {
use nyash_rust::mir::join_ir::normalized::normalize_pattern4_continue_minimal;
let module = build_pattern4_continue_min_structured_for_normalized_dev();
// Test that normalization succeeds (includes shape detection internally)
let result = normalize_pattern4_continue_minimal(&module);
assert!(
result.is_ok(),
"P4 normalization should succeed (shape detection + normalization): {:?}",
result.err()
);
let normalized = result.unwrap();
assert_eq!(
normalized.functions.len(),
module.functions.len(),
"Normalized function count should match Structured"
);
// Verify normalized module has proper phase
assert_eq!(
normalized.phase,
nyash_rust::mir::join_ir::JoinIrPhase::Normalized,
"Normalized module should have Normalized phase"
);
}
/// Phase 48-A: Test P4 VM execution (basic smoke test)
#[test]
fn test_phase48a_pattern4_continue_minimal_runner() {
let module = build_pattern4_continue_min_structured_for_normalized_dev();
// Basic test: module should be runnable through JoinIR runner
// This test verifies the P4 fixture is valid and generates proper JoinIR
assert_eq!(module.functions.len(), 3, "P4 should have 3 functions");
let entry = module.entry.expect("P4 should have entry function");
assert_eq!(entry.0, 0, "Entry should be function 0");
}
/// Phase 48-A: Test P4 minimal Runner dev switch matches Structured
#[test]
fn test_normalized_pattern4_continue_minimal_runner_dev_switch_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_pattern4_continue_min_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
// pattern4_continue_min fixture: acc=4 (skipped i==2, so counted 0,1,3,4)
let input = [JoinValue::Int(5)]; // n = 5
let base = run_joinir_runner(&structured, entry, &input, false);
let dev = run_joinir_runner(&structured, entry, &input, true);
assert_eq!(base, dev, "runner mismatch for P4 minimal continue");
assert_eq!(
dev,
JoinValue::Int(4),
"unexpected result for P4 minimal continue (expected acc=4, skipped i==2)",
);
}
/// Phase 48-A: Test P4 minimal VM Bridge direct matches Structured
#[test]
fn test_normalized_pattern4_continue_minimal_vm_bridge_direct_matches_structured() {
let _ctx = normalized_dev_test_ctx();
let structured = build_pattern4_continue_min_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
// pattern4_continue_min fixture: acc=4 (skipped i==2)
let input = [JoinValue::Int(5)]; // n = 5
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 P4 minimal continue");
assert_eq!(
dev,
JoinValue::Int(4),
"unexpected result for P4 minimal continue (expected acc=4)",
);
}
/// Phase 48-C: P4 minimal should use canonical normalized route even without env
#[test]
fn test_normalized_pattern4_continue_minimal_canonical_matches_structured() {
let structured = build_pattern4_continue_min_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let input = [JoinValue::Int(5)];
let structured_res = run_joinir_vm_bridge_structured_only(&structured, entry, &input);
let canonical = run_joinir_vm_bridge(&structured, entry, &input, false);
assert_eq!(
structured_res, canonical,
"canonical P4 minimal result mismatch"
);
assert_eq!(canonical, JoinValue::Int(4));
}
/// Phase 48-B: JsonParser _parse_array continue skip_ws (dev-only) VM Bridge comparison
#[test]
fn test_normalized_pattern4_jsonparser_parse_array_continue_skip_ws_vm_bridge_direct_matches_structured(
) {
let _ctx = normalized_dev_test_ctx();
let structured = build_jsonparser_parse_array_continue_skip_ws_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
// Fixture mirrors pattern4_continue_min: skip i == 2
let cases = [3, 5, 7];
for n in cases {
let args = [JoinValue::Int(n)];
let base = run_joinir_vm_bridge(&structured, entry, &args, false);
let dev = run_joinir_vm_bridge(&structured, entry, &args, true);
assert_eq!(
base, dev,
"vm bridge mismatch for array continue case n={}",
n
);
}
}
/// Phase 48-C: JsonParser _parse_array continue skip_ws canonical route should match Structured
#[test]
fn test_normalized_pattern4_jsonparser_parse_array_continue_skip_ws_canonical_matches_structured()
{
let structured = build_jsonparser_parse_array_continue_skip_ws_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let cases = [3, 5, 7];
for n in cases {
let args = [JoinValue::Int(n)];
let structured_res = run_joinir_vm_bridge_structured_only(&structured, entry, &args);
let canonical = run_joinir_vm_bridge(&structured, entry, &args, false);
assert_eq!(
structured_res, canonical,
"canonical array continue mismatch n={}",
n
);
}
}
/// Phase 48-B: JsonParser _parse_object continue skip_ws (dev-only) VM Bridge comparison
#[test]
fn test_normalized_pattern4_jsonparser_parse_object_continue_skip_ws_vm_bridge_direct_matches_structured(
) {
let _ctx = normalized_dev_test_ctx();
let structured = build_jsonparser_parse_object_continue_skip_ws_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
// Fixture mirrors pattern4_continue_min: skip i == 2
let cases = [4, 6, 8];
for n in cases {
let args = [JoinValue::Int(n)];
let base = run_joinir_vm_bridge(&structured, entry, &args, false);
let dev = run_joinir_vm_bridge(&structured, entry, &args, true);
assert_eq!(
base, dev,
"vm bridge mismatch for object continue case n={}",
n
);
}
}
/// Phase 48-C: JsonParser _parse_object continue skip_ws canonical route should match Structured
#[test]
fn test_normalized_pattern4_jsonparser_parse_object_continue_skip_ws_canonical_matches_structured()
{
let structured = build_jsonparser_parse_object_continue_skip_ws_structured_for_normalized_dev();
let entry = structured.entry.expect("structured entry required");
let cases = [4, 6, 8];
for n in cases {
let args = [JoinValue::Int(n)];
let structured_res = run_joinir_vm_bridge_structured_only(&structured, entry, &args);
let canonical = run_joinir_vm_bridge(&structured, entry, &args, false);
assert_eq!(
structured_res, canonical,
"canonical object continue mismatch n={}",
n
);
}
}