phase29ao(p44): coreloop v0 composes pattern1

This commit is contained in:
2025-12-30 19:27:45 +09:00
parent ca85514ee3
commit 225a205332
8 changed files with 189 additions and 31 deletions

View File

@ -3,7 +3,7 @@
## Current Focus
- Phase: `docs/development/current/main/phases/phase-29ao/README.md`
- Next: `docs/development/current/main/phases/phase-29ao/P44-CORELOOPCOMPOSER-V0-PATTERN1-MINIMAL-COMPOSITION-INSTRUCTIONS.md`
- Next: TBD (see `docs/development/current/main/phases/phase-29ao/README.md`)
## Gate (SSOT)

View File

@ -5,7 +5,7 @@ Scope: 「次にやる候補」を短く列挙するメモ。入口は `docs/dev
## Active
- CorePlan migration: `docs/development/current/main/phases/phase-29ao/README.md`Next: P44
- CorePlan migration: `docs/development/current/main/phases/phase-29ao/README.md`Next: TBD
## Near-Term Candidates

View File

@ -34,7 +34,7 @@ Related:
## 1.1 Current (active)
- Active phase: `docs/development/current/main/phases/phase-29ao/README.md`
- Next step: `docs/development/current/main/phases/phase-29ao/P44-CORELOOPCOMPOSER-V0-PATTERN1-MINIMAL-COMPOSITION-INSTRUCTIONS.md`
- Next step: TBD
## 2. すでに固めた SSOT再発防止の土台

View File

@ -241,7 +241,11 @@ GateSSOT:
- 指示書: `docs/development/current/main/phases/phase-29ao/P43-CORELOOPCOMPOSER-V0-SCAFFOLD-INSTRUCTIONS.md`
- ねらい: CoreLoopComposer v0 の足場を追加し、合成入口の SSOT を先に固定(未接続, 仕様不変)
## P44: CoreLoopComposer v0 — Pattern1 minimal composition ✅
- 指示書: `docs/development/current/main/phases/phase-29ao/P44-CORELOOPCOMPOSER-V0-PATTERN1-MINIMAL-COMPOSITION-INSTRUCTIONS.md`
- ねらい: Pattern1 skeleton の最小合成を v0 で開始し、Facts→CorePlan の責務を composer 側へ寄せる(仕様不変)
## Nextplanned
- Next: P44CoreLoopComposer v0: Pattern1 minimal
- 指示書: `docs/development/current/main/phases/phase-29ao/P44-CORELOOPCOMPOSER-V0-PATTERN1-MINIMAL-COMPOSITION-INSTRUCTIONS.md`
- Next: TBD

View File

@ -1,12 +1,17 @@
//! Phase 29ao P43: CoreLoopComposer v0 scaffold (unconnected).
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
use crate::mir::builder::control_flow::plan::facts::skeleton_facts::SkeletonKind;
use crate::mir::builder::control_flow::plan::normalize::CanonicalLoopFacts;
use crate::mir::builder::control_flow::plan::normalizer::build_pattern1_coreloop;
use crate::mir::builder::control_flow::plan::CorePlan;
use crate::mir::builder::MirBuilder;
#[allow(dead_code)]
pub(in crate::mir::builder) fn try_compose_core_loop_v0(
builder: &mut MirBuilder,
facts: &CanonicalLoopFacts,
ctx: &LoopPatternContext,
) -> Result<Option<CorePlan>, String> {
if !matches!(facts.skeleton_kind, SkeletonKind::Loop) {
return Ok(None);
@ -14,16 +19,36 @@ pub(in crate::mir::builder) fn try_compose_core_loop_v0(
if facts.value_join_needed {
return Ok(None);
}
Ok(None)
let Some(pattern1) = facts.facts.pattern1_simplewhile.as_ref() else {
return Ok(None);
};
if !facts.exit_kinds_present.is_empty() {
return Ok(None);
}
if !facts.cleanup_kinds_present.is_empty() {
return Ok(None);
}
let loop_plan = build_pattern1_coreloop(
builder,
&pattern1.loop_var,
&pattern1.condition,
&pattern1.loop_increment,
ctx,
)?;
Ok(Some(CorePlan::Loop(loop_plan)))
}
#[cfg(test)]
mod tests {
use super::try_compose_core_loop_v0;
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
use crate::mir::builder::control_flow::plan::facts::feature_facts::{
LoopFeatureFacts, ValueJoinFacts,
ExitKindFacts, ExitMapFacts, ExitUsageFacts, LoopFeatureFacts, ValueJoinFacts,
};
use crate::mir::builder::control_flow::plan::facts::loop_facts::LoopFacts;
use crate::mir::builder::control_flow::plan::facts::pattern1_simplewhile_facts::Pattern1SimpleWhileFacts;
use crate::mir::builder::control_flow::plan::facts::scan_shapes::{
ConditionShape, StepShape,
};
@ -31,6 +56,24 @@ mod tests {
SkeletonFacts, SkeletonKind,
};
use crate::mir::builder::control_flow::plan::normalize::canonicalize_loop_facts;
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
use crate::mir::builder::MirBuilder;
use crate::mir::MirType;
use std::collections::BTreeSet;
fn v(name: &str) -> ASTNode {
ASTNode::Variable {
name: name.to_string(),
span: Span::unknown(),
}
}
fn lit_int(value: i64) -> ASTNode {
ASTNode::Literal {
value: LiteralValue::Integer(value),
span: Span::unknown(),
}
}
fn base_facts(
skeleton_kind: SkeletonKind,
@ -60,7 +103,15 @@ mod tests {
fn coreloop_v0_returns_none_for_non_loop_skeleton() {
let facts = base_facts(SkeletonKind::If2, LoopFeatureFacts::default());
let canonical = canonicalize_loop_facts(facts);
let composed = try_compose_core_loop_v0(&canonical).expect("Ok");
let mut builder = MirBuilder::new();
builder.enter_function_for_test("coreloop_v0_non_loop".to_string());
let condition = ASTNode::Literal {
value: LiteralValue::Bool(true),
span: Span::unknown(),
};
let ctx = LoopPatternContext::new(&condition, &[], "coreloop_v0_non_loop", false, false);
let composed =
try_compose_core_loop_v0(&mut builder, &canonical, &ctx).expect("Ok");
assert!(composed.is_none());
}
@ -72,7 +123,127 @@ mod tests {
};
let facts = base_facts(SkeletonKind::Loop, features);
let canonical = canonicalize_loop_facts(facts);
let composed = try_compose_core_loop_v0(&canonical).expect("Ok");
let mut builder = MirBuilder::new();
builder.enter_function_for_test("coreloop_v0_value_join".to_string());
let condition = ASTNode::Literal {
value: LiteralValue::Bool(true),
span: Span::unknown(),
};
let ctx = LoopPatternContext::new(&condition, &[], "coreloop_v0_value_join", false, false);
let composed =
try_compose_core_loop_v0(&mut builder, &canonical, &ctx).expect("Ok");
assert!(composed.is_none());
}
#[test]
fn coreloop_v0_composes_pattern1_skeleton() {
let condition = ASTNode::BinaryOp {
operator: BinaryOperator::Less,
left: Box::new(v("i")),
right: Box::new(lit_int(3)),
span: Span::unknown(),
};
let loop_increment = ASTNode::BinaryOp {
operator: BinaryOperator::Add,
left: Box::new(v("i")),
right: Box::new(lit_int(1)),
span: Span::unknown(),
};
let facts = LoopFacts {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: SkeletonFacts {
kind: SkeletonKind::Loop,
},
features: LoopFeatureFacts::default(),
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: Some(Pattern1SimpleWhileFacts {
loop_var: "i".to_string(),
condition: condition.clone(),
loop_increment: loop_increment.clone(),
}),
pattern3_ifphi: None,
pattern4_continue: None,
pattern5_infinite_early_exit: None,
pattern8_bool_predicate_scan: None,
pattern9_accum_const_loop: None,
pattern2_break: None,
pattern2_loopbodylocal: None,
};
let canonical = canonicalize_loop_facts(facts);
let mut builder = MirBuilder::new();
builder.enter_function_for_test("coreloop_v0_pattern1".to_string());
let init = builder.alloc_typed(MirType::Integer);
builder
.variable_ctx
.variable_map
.insert("i".to_string(), init);
let ctx = LoopPatternContext::new(&condition, &[], "coreloop_v0_pattern1", false, false);
let composed =
try_compose_core_loop_v0(&mut builder, &canonical, &ctx).expect("Ok");
assert!(matches!(composed, Some(CorePlan::Loop(_))));
}
#[test]
fn coreloop_v0_returns_none_when_exitmap_present() {
let condition = ASTNode::BinaryOp {
operator: BinaryOperator::Less,
left: Box::new(v("i")),
right: Box::new(lit_int(2)),
span: Span::unknown(),
};
let loop_increment = ASTNode::BinaryOp {
operator: BinaryOperator::Add,
left: Box::new(v("i")),
right: Box::new(lit_int(1)),
span: Span::unknown(),
};
let mut kinds_present = BTreeSet::new();
kinds_present.insert(ExitKindFacts::Break);
let features = LoopFeatureFacts {
exit_usage: ExitUsageFacts {
has_break: true,
has_continue: false,
has_return: false,
},
exit_map: Some(ExitMapFacts { kinds_present }),
value_join: None,
cleanup: None,
};
let facts = LoopFacts {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: SkeletonFacts {
kind: SkeletonKind::Loop,
},
features,
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: Some(Pattern1SimpleWhileFacts {
loop_var: "i".to_string(),
condition: condition.clone(),
loop_increment: loop_increment.clone(),
}),
pattern3_ifphi: None,
pattern4_continue: None,
pattern5_infinite_early_exit: None,
pattern8_bool_predicate_scan: None,
pattern9_accum_const_loop: None,
pattern2_break: None,
pattern2_loopbodylocal: None,
};
let canonical = canonicalize_loop_facts(facts);
let mut builder = MirBuilder::new();
builder.enter_function_for_test("coreloop_v0_exitmap".to_string());
let init = builder.alloc_typed(MirType::Integer);
builder
.variable_ctx
.variable_map
.insert("i".to_string(), init);
let ctx = LoopPatternContext::new(&condition, &[], "coreloop_v0_exitmap", false, false);
let composed =
try_compose_core_loop_v0(&mut builder, &canonical, &ctx).expect("Ok");
assert!(composed.is_none());
}
}

View File

@ -37,6 +37,8 @@ use super::{
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
use crate::mir::builder::MirBuilder;
pub(in crate::mir::builder) use pattern1_coreloop_builder::build_pattern1_coreloop;
/// Phase 273 P1: PlanNormalizer - DomainPlan → CorePlan 変換 (SSOT)
pub(in crate::mir::builder) struct PlanNormalizer;

View File

@ -9,7 +9,7 @@ use crate::mir::join_ir::lowering::inline_boundary::JumpArgsLayout;
use crate::mir::MirType;
use std::collections::BTreeMap;
pub(super) fn build_pattern1_coreloop(
pub(in crate::mir::builder) fn build_pattern1_coreloop(
builder: &mut MirBuilder,
loop_var: &str,
condition: &ASTNode,

View File

@ -1,7 +1,6 @@
use super::pattern1_coreloop_builder::build_pattern1_coreloop;
use super::CorePlan;
use crate::mir::builder::control_flow::plan::composer::coreloop_v0::try_compose_core_loop_v0;
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
use crate::mir::builder::control_flow::plan::facts::skeleton_facts::SkeletonKind;
use crate::mir::builder::control_flow::plan::normalize::CanonicalLoopFacts;
use crate::mir::builder::MirBuilder;
@ -11,24 +10,6 @@ impl super::PlanNormalizer {
facts: &CanonicalLoopFacts,
ctx: &LoopPatternContext,
) -> Result<Option<CorePlan>, String> {
if facts.value_join_needed {
return Ok(None);
}
if !matches!(facts.skeleton_kind, SkeletonKind::Loop) {
return Ok(None);
}
let Some(pattern1) = facts.facts.pattern1_simplewhile.as_ref() else {
return Ok(None);
};
let loop_plan = build_pattern1_coreloop(
builder,
&pattern1.loop_var,
&pattern1.condition,
&pattern1.loop_increment,
ctx,
)?;
Ok(Some(CorePlan::Loop(loop_plan)))
try_compose_core_loop_v0(builder, facts, ctx)
}
}