Files
hakorune/src/mir/join_ir/normalized/fixtures.rs
nyash-codex 11e68203c8 feat(joinir): Phase 76 - promoted_bindings map (dev-only)
Phase 76 introduces type-safe promotion tracking via promoted_bindings
(BindingId→BindingId map). Replaces fragile string matching hacks with
compiler-checked identity mapping.

Changes:
- carrier_info.rs: Added promoted_bindings field and resolution methods
- pattern4_carrier_analyzer.rs: Updated for BindingId integration
- pattern_pipeline.rs: Carrier resolution via promoted_bindings
- loop_with_break_minimal/tests.rs: Added promoted_bindings tests
- normalized/fixtures.rs: Extended with Phase 76 fixtures

Tests: 5/5 new unit tests PASS (record/resolve/merge/default/overwrite)
Tests: lib 958/958 PASS, normalized_dev 54/54 PASS (no regressions)

Design: Dual-path (BindingId OR name) enables gradual Phase 77+ transition.

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-13 05:35:14 +09:00

820 lines
28 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#![cfg(feature = "normalized_dev")]
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
use crate::mir::join_ir::frontend::AstToJoinIrLowerer;
use crate::mir::join_ir::lowering::condition_env::ConditionEnv;
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
use crate::mir::join_ir::lowering::loop_update_analyzer::UpdateExpr;
use crate::mir::join_ir::lowering::loop_with_break_minimal::lower_loop_with_break_minimal;
use crate::mir::join_ir::lowering::loop_with_if_phi_if_sum::lower_if_sum_pattern;
use crate::mir::join_ir::{
BinOpKind, CompareOp, ConstValue, JoinFuncId, JoinFunction, JoinInst, JoinModule, MirLikeInst,
UnaryOp,
};
use crate::mir::{BasicBlockId, ValueId};
use crate::{config::env::joinir_dev_enabled, config::env::joinir_test_debug_enabled};
use std::collections::{BTreeMap, BTreeSet};
fn const_i64(func: &mut JoinFunction, dst: ValueId, value: i64) {
func.body.push(JoinInst::Compute(MirLikeInst::Const {
dst,
value: ConstValue::Integer(value),
}));
}
fn compare(func: &mut JoinFunction, dst: ValueId, op: CompareOp, lhs: ValueId, rhs: ValueId) {
func.body.push(JoinInst::Compute(MirLikeInst::Compare { dst, op, lhs, rhs }));
}
fn unary_not(func: &mut JoinFunction, dst: ValueId, operand: ValueId) {
func.body.push(JoinInst::Compute(MirLikeInst::UnaryOp {
dst,
op: UnaryOp::Not,
operand,
}));
}
fn bin_add(func: &mut JoinFunction, dst: ValueId, lhs: ValueId, rhs: ValueId) {
func.body.push(JoinInst::Compute(MirLikeInst::BinOp {
dst,
op: BinOpKind::Add,
lhs,
rhs,
}));
}
fn select(func: &mut JoinFunction, dst: ValueId, cond: ValueId, then_val: ValueId, else_val: ValueId) {
func.body.push(JoinInst::Compute(MirLikeInst::Select {
dst,
cond,
then_val,
else_val,
}));
}
/// Structured Pattern2 (joinir_min_loop 相当) をテスト用に生成するヘルパー。
pub fn build_pattern2_minimal_structured() -> JoinModule {
let loop_cond = ASTNode::BinaryOp {
operator: BinaryOperator::Less,
left: Box::new(ASTNode::Variable {
name: "i".to_string(),
span: Span::unknown(),
}),
right: Box::new(ASTNode::Literal {
value: LiteralValue::Integer(3),
span: Span::unknown(),
}),
span: Span::unknown(),
};
let break_cond = ASTNode::BinaryOp {
operator: BinaryOperator::GreaterEqual,
left: Box::new(ASTNode::Variable {
name: "i".to_string(),
span: Span::unknown(),
}),
right: Box::new(ASTNode::Literal {
value: LiteralValue::Integer(2),
span: Span::unknown(),
}),
span: Span::unknown(),
};
let mut scope = LoopScopeShape {
header: BasicBlockId(0),
body: BasicBlockId(1),
latch: BasicBlockId(2),
exit: BasicBlockId(3),
pinned: BTreeSet::new(),
carriers: BTreeSet::new(),
body_locals: BTreeSet::new(),
exit_live: BTreeSet::new(),
progress_carrier: None,
variable_definitions: BTreeMap::new(),
};
scope.pinned.insert("i".to_string());
let mut condition_env = ConditionEnv::new();
condition_env.insert("i".to_string(), ValueId(100));
let carrier_info = crate::mir::join_ir::lowering::carrier_info::CarrierInfo {
loop_var_name: "i".to_string(),
loop_var_id: ValueId(1),
carriers: vec![],
trim_helper: None,
promoted_loopbodylocals: vec![],
#[cfg(feature = "normalized_dev")]
promoted_bindings: std::collections::BTreeMap::new(),
};
let carrier_updates: BTreeMap<String, UpdateExpr> = BTreeMap::new();
let mut join_value_space = JoinValueSpace::new();
let (module, _) = lower_loop_with_break_minimal(
scope,
&loop_cond,
&break_cond,
&condition_env,
&carrier_info,
&carrier_updates,
&[],
None,
&mut join_value_space,
)
.expect("pattern2 minimal lowering should succeed");
module
}
/// Pattern2 ブレークループfixture ベース)を Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/phase-34-joinir-frontend/fixtures/loop_frontend_break.program.json
pub fn build_pattern2_break_fixture_structured() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/phase-34-joinir-frontend/fixtures/loop_frontend_break.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("fixture JSON should be valid");
let mut lowerer = AstToJoinIrLowerer::new();
lowerer.lower_program_json(&program_json)
}
/// JsonParser 由来のミニ P2 ループ(空白スキップ相当)を Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_skip_ws_mini.program.json
pub fn build_jsonparser_skip_ws_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_skip_ws_mini.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("jsonparser skip_ws fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
lowerer.lower_program_json(&program_json)
}
/// JsonParser _skip_whitespace 本体相当の P2 ループを Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_skip_ws_real.program.json
pub fn build_jsonparser_skip_ws_real_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_skip_ws_real.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("jsonparser skip_ws real fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] jsonparser_skip_ws_real structured module: {:#?}",
module
);
}
module
}
/// JsonParser _parse_number 本体相当の P2 ループを Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_parse_number_real.program.json
pub fn build_jsonparser_parse_number_real_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_parse_number_real.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("jsonparser parse_number real fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] jsonparser_parse_number_real structured module: {:#?}",
module
);
}
module
}
/// selfhost token-scan 系の P2 ループを Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_token_scan_p2.program.json
pub fn build_selfhost_token_scan_p2_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_token_scan_p2.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("selfhost token_scan P2 fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] selfhost_token_scan_p2 structured module: {:#?}",
module
);
}
module
}
/// selfhost token-scan 系の P2 ループaccum 拡張)を Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_token_scan_p2_accum.program.json
pub fn build_selfhost_token_scan_p2_accum_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_token_scan_p2_accum.program.json"
);
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("selfhost token_scan P2 accum fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] selfhost_token_scan_p2_accum structured module: {:#?}",
module
);
}
module
}
/// Phase 47-B: Pattern3 if-sum (multi carrier) を Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/pattern3_if_sum_multi_min.program.json
pub fn build_pattern3_if_sum_multi_min_structured_for_normalized_dev() -> JoinModule {
// 手書き JoinIRi/sum/count の 3 キャリア)
let mut module = JoinModule::new();
let mut next_id = 0u32;
let mut alloc = || {
let id = ValueId(next_id);
next_id += 1;
id
};
let main_id = JoinFuncId::new(0);
let loop_id = JoinFuncId::new(1);
let exit_id = JoinFuncId::new(2);
// main: init i/sum/count = 0 → tail call loop_step
let i0 = alloc();
let sum0 = alloc();
let count0 = alloc();
let mut main = JoinFunction::new(main_id, "main".to_string(), vec![]);
const_i64(&mut main, i0, 0);
const_i64(&mut main, sum0, 0);
const_i64(&mut main, count0, 0);
main.body.push(JoinInst::Call {
func: loop_id,
args: vec![i0, sum0, count0],
k_next: None,
dst: None,
});
module.add_function(main);
// loop_step params: i, sum, count
let i_param = alloc();
let sum_param = alloc();
let count_param = alloc();
let mut loop_step = JoinFunction::new(
loop_id,
"loop_step".to_string(),
vec![i_param, sum_param, count_param],
);
// loop condition: i < 3
let limit_const = alloc();
let cmp_loop = alloc();
let exit_cond = alloc();
const_i64(&mut loop_step, limit_const, 3);
compare(
&mut loop_step,
cmp_loop,
CompareOp::Lt,
i_param,
limit_const,
);
unary_not(&mut loop_step, exit_cond, cmp_loop);
loop_step.body.push(JoinInst::Jump {
cont: exit_id.as_cont(),
args: vec![sum_param, count_param],
cond: Some(exit_cond),
});
// if condition: i > 0
let cond_cmp = alloc();
let zero_const = alloc();
const_i64(&mut loop_step, zero_const, 0);
compare(
&mut loop_step,
cond_cmp,
CompareOp::Gt,
i_param,
zero_const,
);
// then: sum = sum + 1, count = count + 1
let one_const = alloc();
let sum_then = alloc();
let count_then = alloc();
const_i64(&mut loop_step, one_const, 1);
bin_add(&mut loop_step, sum_then, sum_param, one_const);
bin_add(&mut loop_step, count_then, count_param, one_const);
// else: identity
let sum_else = alloc();
let count_else = alloc();
bin_add(&mut loop_step, sum_else, sum_param, zero_const);
bin_add(&mut loop_step, count_else, count_param, zero_const);
// select
let sum_new = alloc();
let count_new = alloc();
select(&mut loop_step, sum_new, cond_cmp, sum_then, sum_else);
select(&mut loop_step, count_new, cond_cmp, count_then, count_else);
// counter update: i = i + 1
let one_const2 = alloc();
let i_next = alloc();
const_i64(&mut loop_step, one_const2, 1);
bin_add(&mut loop_step, i_next, i_param, one_const2);
loop_step.body.push(JoinInst::Call {
func: loop_id,
args: vec![i_next, sum_new, count_new],
k_next: None,
dst: None,
});
module.add_function(loop_step);
// k_exit(sum, count)
let sum_final = alloc();
let count_final = alloc();
let mut k_exit = JoinFunction::new(exit_id, "k_exit".to_string(), vec![sum_final, count_final]);
k_exit.body.push(JoinInst::Ret {
value: Some(sum_final),
});
module.add_function(k_exit);
module.entry = Some(main_id);
module.phase = crate::mir::join_ir::JoinIrPhase::Structured;
module
}
/// Phase 47-B: JsonParser if-sum mini を Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_if_sum_min.program.json
pub fn build_pattern3_json_if_sum_min_structured_for_normalized_dev() -> JoinModule {
// 手書き JoinIRi/sum の 2 キャリア、JsonParser 由来の簡約 if-sum
let mut module = JoinModule::new();
let mut next_id = 0u32;
let mut alloc = || {
let id = ValueId(next_id);
next_id += 1;
id
};
let main_id = JoinFuncId::new(0);
let loop_id = JoinFuncId::new(1);
let exit_id = JoinFuncId::new(2);
// main: init i/sum = 0 → tail call loop_step
let i0 = alloc();
let sum0 = alloc();
let mut main = JoinFunction::new(main_id, "main".to_string(), vec![]);
main.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: i0,
value: ConstValue::Integer(0),
}));
main.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: sum0,
value: ConstValue::Integer(0),
}));
main.body.push(JoinInst::Call {
func: loop_id,
args: vec![i0, sum0],
k_next: None,
dst: None,
});
module.add_function(main);
// loop_step params: i, sum
let i_param = alloc();
let sum_param = alloc();
let mut loop_step = JoinFunction::new(loop_id, "loop_step".to_string(), vec![i_param, sum_param]);
// loop condition: i < 5
let limit_const = alloc();
let cmp_loop = alloc();
let exit_cond = alloc();
loop_step
.body
.push(JoinInst::Compute(MirLikeInst::Const {
dst: limit_const,
value: ConstValue::Integer(5),
}));
compare(
&mut loop_step,
cmp_loop,
CompareOp::Lt,
i_param,
limit_const,
);
unary_not(&mut loop_step, exit_cond, cmp_loop);
loop_step.body.push(JoinInst::Jump {
cont: exit_id.as_cont(),
args: vec![sum_param],
cond: Some(exit_cond),
});
// if condition: i > 0
let cond_cmp = alloc();
let zero_const = alloc();
const_i64(&mut loop_step, zero_const, 0);
compare(
&mut loop_step,
cond_cmp,
CompareOp::Gt,
i_param,
zero_const,
);
// then: sum = sum + i
let sum_then = alloc();
bin_add(&mut loop_step, sum_then, sum_param, i_param);
// else: identity sum
let sum_else = alloc();
bin_add(&mut loop_step, sum_else, sum_param, zero_const);
// select
let sum_new = alloc();
select(&mut loop_step, sum_new, cond_cmp, sum_then, sum_else);
// counter update: i = i + 1
let one_const = alloc();
let i_next = alloc();
const_i64(&mut loop_step, one_const, 1);
bin_add(&mut loop_step, i_next, i_param, one_const);
loop_step.body.push(JoinInst::Call {
func: loop_id,
args: vec![i_next, sum_new],
k_next: None,
dst: None,
});
module.add_function(loop_step);
// k_exit(sum)
let sum_final = alloc();
let mut k_exit = JoinFunction::new(exit_id, "k_exit".to_string(), vec![sum_final]);
k_exit.body.push(JoinInst::Ret {
value: Some(sum_final),
});
module.add_function(k_exit);
module.entry = Some(main_id);
module.phase = crate::mir::join_ir::JoinIrPhase::Structured;
module
}
/// selfhost if-sum P3 を Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_if_sum_p3.program.json
pub fn build_selfhost_if_sum_p3_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_if_sum_p3.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("selfhost if_sum P3 fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] selfhost_if_sum_p3 structured module: {:#?}",
module
);
}
module
}
/// selfhost if-sum P3ext 拡張)を Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_if_sum_p3_ext.program.json
pub fn build_selfhost_if_sum_p3_ext_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_if_sum_p3_ext.program.json"
);
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("selfhost if_sum P3 ext fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] selfhost_if_sum_p3_ext structured module: {:#?}",
module
);
}
module
}
/// selfhost args-parse P2Phase 53を Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_args_parse_p2.program.json
pub fn build_selfhost_args_parse_p2_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_args_parse_p2.program.json"
);
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("selfhost args_parse P2 fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] selfhost_args_parse_p2 structured module: {:#?}",
module
);
}
module
}
/// selfhost stmt-count P3Phase 53を Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_stmt_count_p3.program.json
pub fn build_selfhost_stmt_count_p3_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/selfhost_stmt_count_p3.program.json"
);
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("selfhost stmt_count P3 fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] selfhost_stmt_count_p3 structured module: {:#?}",
module
);
}
module
}
/// JsonParser _atoi 相当のミニ P2 ループを Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_atoi_mini.program.json
pub fn build_jsonparser_atoi_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_atoi_mini.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("jsonparser atoi fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] jsonparser_atoi_mini structured module: {:#?}",
module
);
}
module
}
/// JsonParser _atoi 本体相当の P2 ループを Structured で組み立てるヘルパー。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_atoi_real.program.json
pub fn build_jsonparser_atoi_real_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_atoi_real.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("jsonparser atoi real fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] jsonparser_atoi_real structured module: {:#?}",
module
);
}
module
}
/// Pattern3 if-sum minimal ループphase212_if_sum_min.hako 相当)を Structured で組み立てるヘルパー。
///
/// Phase 47-A: P3 Normalized の最小ケース検証用dev-only
pub fn build_pattern3_if_sum_min_structured_for_normalized_dev() -> JoinModule {
fn var(name: &str) -> ASTNode {
ASTNode::Variable {
name: name.to_string(),
span: Span::unknown(),
}
}
fn int_lit(value: i64) -> ASTNode {
ASTNode::Literal {
value: LiteralValue::Integer(value),
span: Span::unknown(),
}
}
fn bin(op: BinaryOperator, left: ASTNode, right: ASTNode) -> ASTNode {
ASTNode::BinaryOp {
operator: op,
left: Box::new(left),
right: Box::new(right),
span: Span::unknown(),
}
}
fn assignment(target: ASTNode, value: ASTNode) -> ASTNode {
ASTNode::Assignment {
target: Box::new(target),
value: Box::new(value),
span: Span::unknown(),
}
}
// Minimal if-sum pattern:
// loop(i < 3) {
// if (i > 0) { sum = sum + 1 } else { sum = sum + 0 }
// i = i + 1
// }
let loop_condition = bin(BinaryOperator::Less, var("i"), int_lit(3));
let if_condition = bin(BinaryOperator::Greater, var("i"), int_lit(0));
let then_update = assignment(
var("sum"),
bin(BinaryOperator::Add, var("sum"), int_lit(1)),
);
let else_update = assignment(
var("sum"),
bin(BinaryOperator::Add, var("sum"), int_lit(0)),
);
let counter_update = assignment(
var("i"),
bin(BinaryOperator::Add, var("i"), int_lit(1)),
);
let if_stmt = ASTNode::If {
condition: Box::new(if_condition),
then_body: vec![then_update],
else_body: Some(vec![else_update]),
span: Span::unknown(),
};
let body = vec![if_stmt.clone(), counter_update];
let mut join_value_space = JoinValueSpace::new();
let mut cond_env = ConditionEnv::new();
// Phase 220-D: ConditionEnv には少なくともループ変数 i を登録しておく。
let i_id = join_value_space.alloc_param();
cond_env.insert("i".to_string(), i_id);
let (module, _meta) =
lower_if_sum_pattern(&loop_condition, &if_stmt, &body, &cond_env, &mut join_value_space)
.expect("if-sum lowering should succeed for minimal pattern3");
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] pattern3_if_sum_min structured module: {:#?}",
module
);
}
module
}
/// Pattern4 continue minimal ループpattern4_continue_min 相当)を Structured で組み立てるヘルパー。
///
/// Phase 48-A: P4 Normalized の最小ケース検証用dev-only
/// 単純な continue パターンi == 2 でスキップ)。
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/pattern4_continue_min.program.json
pub fn build_pattern4_continue_min_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/pattern4_continue_min.program.json"
);
let program_json: serde_json::Value =
serde_json::from_str(FIXTURE).expect("pattern4_continue_min fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] pattern4_continue_min structured module: {:#?}",
module
);
}
module
}
/// JsonParser _parse_array の whitespace continue ループを Structured で組み立てるヘルパーdev-only
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_parse_array_continue_skip_ws.program.json
pub fn build_jsonparser_parse_array_continue_skip_ws_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_parse_array_continue_skip_ws.program.json"
);
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("jsonparser_parse_array_continue_skip_ws fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] jsonparser_parse_array_continue_skip_ws structured module: {:#?}",
module
);
}
module
}
/// JsonParser _parse_object の whitespace continue ループを Structured で組み立てるヘルパーdev-only
///
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_parse_object_continue_skip_ws.program.json
pub fn build_jsonparser_parse_object_continue_skip_ws_structured_for_normalized_dev() -> JoinModule {
const FIXTURE: &str = include_str!(
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_parse_object_continue_skip_ws.program.json"
);
let program_json: serde_json::Value = serde_json::from_str(FIXTURE)
.expect("jsonparser_parse_object_continue_skip_ws fixture should be valid JSON");
let mut lowerer = AstToJoinIrLowerer::new();
let module = lowerer.lower_program_json(&program_json);
if joinir_dev_enabled() && joinir_test_debug_enabled() {
eprintln!(
"[joinir/normalized-dev] jsonparser_parse_object_continue_skip_ws structured module: {:#?}",
module
);
}
module
}
/// まとめて import したいとき用のプレリュード。
pub mod prelude {
pub use super::{
build_jsonparser_atoi_real_structured_for_normalized_dev,
build_jsonparser_atoi_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_if_sum_p3_ext_structured_for_normalized_dev,
build_selfhost_if_sum_p3_structured_for_normalized_dev,
build_selfhost_token_scan_p2_accum_structured_for_normalized_dev,
build_selfhost_token_scan_p2_structured_for_normalized_dev,
};
}