feat(joinir): Phase 248 - Normalized JoinIR infrastructure
Major refactoring of JoinIR normalization pipeline: Key changes: - Structured→Normalized→MIR(direct) pipeline established - ShapeGuard enhanced with Pattern2 loop validation - dev_env.rs: New development fixtures and env control - fixtures.rs: jsonparser_parse_number_real fixture - normalized_bridge/direct.rs: Direct MIR generation from Normalized - pattern2_step_schedule.rs: Extracted step scheduling logic Files changed: - normalized.rs: Enhanced NormalizedJoinModule with DevEnv support - shape_guard.rs: Pattern2-specific validation (+300 lines) - normalized_bridge.rs: Unified bridge with direct path - loop_with_break_minimal.rs: Integrated step scheduling - Deleted: step_schedule.rs (moved to pattern2_step_schedule.rs) New files: - param_guess.rs: Loop parameter inference - pattern2_step_schedule.rs: Step scheduling for Pattern2 - phase43-norm-canon-p2-mid.md: Design doc Tests: 937/937 PASS (+6 from baseline 931) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -6,9 +6,14 @@ use nyash_rust::mir::join_ir::{
|
||||
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::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_number_real_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,
|
||||
};
|
||||
@ -16,10 +21,19 @@ 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 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!(
|
||||
nyash_rust::config::env::normalized_dev_enabled(),
|
||||
"Phase 33: normalized_dev must be enabled for this suite (feature + env)"
|
||||
normalized_dev_enabled(),
|
||||
"Phase 40: normalized_dev must be enabled for normalized_* tests (feature + NYASH_JOINIR_NORMALIZED_DEV_RUN=1)"
|
||||
);
|
||||
}
|
||||
|
||||
@ -87,6 +101,7 @@ fn build_structured_pattern1() -> JoinModule {
|
||||
|
||||
#[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);
|
||||
@ -103,6 +118,7 @@ fn normalized_pattern1_minimal_smoke() {
|
||||
|
||||
#[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);
|
||||
@ -121,6 +137,7 @@ fn normalized_pattern1_roundtrip_structured_equivalent() {
|
||||
|
||||
#[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);
|
||||
@ -136,6 +153,7 @@ fn normalized_pattern1_exec_matches_structured() {
|
||||
|
||||
#[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);
|
||||
@ -156,6 +174,7 @@ fn normalized_pattern1_exec_matches_structured_roundtrip_backup() {
|
||||
|
||||
#[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);
|
||||
@ -175,8 +194,39 @@ fn normalized_pattern2_roundtrip_structure() {
|
||||
}
|
||||
}
|
||||
|
||||
#[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);
|
||||
@ -193,6 +243,7 @@ fn normalized_pattern2_exec_matches_structured() {
|
||||
#[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);
|
||||
@ -200,6 +251,7 @@ fn normalized_pattern2_rejects_non_pattern2_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);
|
||||
@ -221,6 +273,7 @@ fn normalized_pattern2_real_loop_roundtrip_structure() {
|
||||
|
||||
#[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);
|
||||
@ -246,6 +299,7 @@ fn normalized_pattern2_real_loop_exec_matches_structured() {
|
||||
|
||||
#[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)];
|
||||
@ -259,6 +313,7 @@ fn normalized_pattern1_runner_dev_switch_matches_structured() {
|
||||
|
||||
#[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];
|
||||
@ -281,6 +336,7 @@ fn normalized_pattern2_runner_dev_switch_matches_structured() {
|
||||
|
||||
#[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];
|
||||
@ -297,6 +353,7 @@ fn normalized_pattern2_jsonparser_runner_dev_switch_matches_structured() {
|
||||
|
||||
#[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];
|
||||
@ -319,6 +376,7 @@ fn normalized_pattern2_vm_bridge_direct_matches_structured() {
|
||||
|
||||
#[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];
|
||||
@ -335,6 +393,7 @@ fn normalized_pattern1_vm_bridge_direct_matches_structured() {
|
||||
|
||||
#[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];
|
||||
@ -349,8 +408,37 @@ fn normalized_pattern2_jsonparser_vm_bridge_direct_matches_structured() {
|
||||
}
|
||||
}
|
||||
|
||||
#[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 = [
|
||||
@ -374,3 +462,48 @@ fn normalized_pattern2_jsonparser_atoi_vm_bridge_direct_matches_structured() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user