feat(joinir): Phase 47-A prep - P3 fixture and test stub

Preparation for Phase 47-A (P3 Normalized minimal implementation).
Added fixture and test stub for pattern3_if_sum_minimal.

Changes:
- fixtures.rs: Added pattern3_if_sum_minimal fixture
  - Source: phase212_if_sum_min.hako
  - Pattern: Single carrier (sum), simple condition (i > 0)
  - Dev-only fixture for P3 Normalized development

- normalized_joinir_min.rs: Added test stub
  - test_normalized_pattern3_if_sum_minimal_runner
  - Currently returns early (implementation pending)
  - Feature-gated: #[cfg(feature = "normalized_dev")]

- Documentation updates:
  - CURRENT_TASK.md: Phase 47-A status
  - PHASE_43_245B_NORMALIZED_COMPLETION.md: P3 forward reference
  - joinir-architecture-overview.md: Minor formatting
  - phase47-norm-p3-design.md: Implementation notes

Next steps (Phase 47-A implementation):
1. Rename pattern2_step_schedule.rs → step_schedule.rs
2. Add P3 StepKind (IfCond, ThenUpdates, ElseUpdates)
3. Implement Normalized→MIR(direct) for P3
4. Complete test implementation

Tests: 937/937 PASS (no behavioral changes yet)
This commit is contained in:
nyash-codex
2025-12-12 05:07:01 +09:00
parent 23ebb86e6e
commit 42ecd7a7e7
6 changed files with 162 additions and 18 deletions

View File

@ -167,11 +167,11 @@
1. ~~Phase 245Bコード~~: ✅ 完了Phase 43/245B の一部) 1. ~~Phase 245Bコード~~: ✅ 完了Phase 43/245B の一部)
2. ~~Phase 246-EXコード~~: ✅ 完了Phase 43/245B の一部) 2. ~~Phase 246-EXコード~~: ✅ 完了Phase 43/245B の一部)
3. **Phase 47-NORM-P3設計完了✅ 2025-12-12**: Pattern3 Normalized 設計 3. **Phase 47-NORM-P3設計完了最小dev実装✅ 2025-12-12**: Pattern3 Normalized 設計
- 設計詳細: [phase47-norm-p3-design.md](docs/development/current/main/phase47-norm-p3-design.md) - 設計詳細: [phase47-norm-p3-design.md](docs/development/current/main/phase47-norm-p3-design.md)
- P3 if-sum を Normalized JoinIR に載せる設計。P2 と同じ ConditionEnv/CarrierInfo/ExitLine インフラを再利用。 - P3 if-sum を Normalized JoinIR に載せる設計。P2 と同じ ConditionEnv/CarrierInfo/ExitLine インフラを再利用。
- Phase 47-A: Minimal sum_count (dev-only), Phase 47-B: array_filter, Phase 47-C: Canonical promotion - Phase 47-A: Minimal sum_countdev-only 第1ステップとして、`phase212_if_sum_min.hako` 相当の最小 if-sum ループを AST ベース lowerer + Structured→Normalized→Structured roundtripRunner 経路)で検証済み
- 実装は未着手(設計のみ完了) - Phase 47-B 以降: StepScheduleBox 拡張・direct Normalized→MIR ブリッジ・canonical 昇格は今後の実装フェーズで扱う
4. **Phase 48-NORM-P4-DESIGN候補**: Pattern4 Normalized 設計 4. **Phase 48-NORM-P4-DESIGN候補**: Pattern4 Normalized 設計
- `_parse_array` / `_parse_object` / continue 混在ループを棚卸しし、P4 をどの順番で Normalized に載せるかを整理。 - `_parse_array` / `_parse_object` / continue 混在ループを棚卸しし、P4 をどの順番で Normalized に載せるかを整理。
- continue を TailCallFn でどう表現するか、EnvLayout との対応を設計メモに落とす。 - continue を TailCallFn でどう表現するか、EnvLayout との対応を設計メモに落とす。

View File

@ -257,6 +257,45 @@ loop(p < s.length()) {
--- ---
## Documentation MapNormalized JoinIR ライン)
Normalized JoinIR 関連ドキュメントが増えてきたので、このフェーズを SSOT として、他ドキュメントの位置付けを整理しておくよ。
- **SSOT / 現役**
- `joinir-architecture-overview.md`
- JoinIR 全体のアーキテクチャと、Structured / Normalized / Bridge の役割をまとめたトップレベル設計図。
- 3.13.3 で Normalized 層JoinIR→JoinIR 正規化)のゴールと P1〜P4 との関係を定義。
- `PHASE_43_245B_NORMALIZED_COMPLETION.md`(このファイル)
- Phase 2645 にかけて整備した Normalized インフラP1/P2 + JsonParser P2-Core/P2-Mid全体の完了サマリ。
- 実装ファイル・テスト・今後の Expansion を一覧できる SSOT。
- `phase44-shape-capabilities-design.md`
- ShapeCapabilityKind / capability_for_shape など、Normalized ルート選択の基盤設計。
- `phase45-norm-mode-design.md`
- JoinIrMode と current_joinir_mode() によるルーティング統一の設計メモ。
- **部分設計 / 詳細メモ(参照推奨)**
- `phase245-jsonparser-parse-number-joinir-integration.md`
- `phase245b-num_str-carrier-design.md`
- `phase245c-function-param-capture-summary.md`
- `phase246-jsonparser-atoi-joinir-integration.md`
- `phase247-digitpos-dual-value-design.md`
- JsonParser `_parse_number` / `_atoi` / DigitPos / num_str / Function param capture など、P2-Mid の詳細設計。
- 必要に応じてここから構造や前提を掘る想定だよ。
- **Historical実装済み・設計の足跡として残す**
- `phase26-HC-normalized-pattern1-bridge.md`
- `phase26-HC-normalized-pattern1-bridge` から派生した Phase 26-H.* / 33-16 / 33-17 系の Normalized 初期メモ
- Pattern1 単体の Normalized 試走とブリッジ検証の指示書。実装は本サマリと joinir-architecture-overview に吸収済み。
- 新しく Normalized を読むときは、まず本ファイルと overview を見てから、必要に応じて Historical を辿る運用にする。
今後 Normalized の設計や実装を進めるときは:
1. 入口として `joinir-architecture-overview.md` とこの `PHASE_43_245B_NORMALIZED_COMPLETION.md` を読む。
2. JsonParser / DigitPos / num_str などテーマ別の詳細が必要になったら、対応する Phase 24x/25x ドキュメントを参照する。
3. 初期フェーズの試行錯誤に興味があれば、Historical とラベル付けされた Phase 26-H.* / 33-* メモを読む。
---
## Completed Phases ## Completed Phases
### Phase 26-42: Foundation ### Phase 26-42: Foundation

View File

@ -1359,7 +1359,7 @@ JsonParser _skip_whitespace / _atoi / _parse_number が**すべて canonical Nor
**テスト**: 937/937 PASS **テスト**: 937/937 PASS
### 3.24 Phase 47-NORM-P3 Normalized P3 (If-Sum) Support 🏗️ DESIGN (2025-12-12) ### 3.24 Phase 47-NORM-P3 Normalized P3 (If-Sum) Support 🏗️ DESIGN + MINIMAL DEV (2025-12-12)
**設計詳細**: [phase47-norm-p3-design.md](./phase47-norm-p3-design.md) **設計詳細**: [phase47-norm-p3-design.md](./phase47-norm-p3-design.md)
@ -1369,11 +1369,11 @@ Pattern3 (if-sum) ループを Normalized JoinIR に対応させる。P2 と同
**Key difference**: P3 は **conditional carrier updates**if 内でのみキャリア更新vs P2 の unconditional updates before break **Key difference**: P3 は **conditional carrier updates**if 内でのみキャリア更新vs P2 の unconditional updates before break
**Phase 47-A**: Minimal sum_count (dev-only Normalized) **Phase 47-A**: Minimal sum_countdev-only 正規化・第1ステップ
- ✅ EnvLayout: P2 と同じ構造carrier フィールド) - ✅ AST ベース if-sum lowerer`loop_with_if_phi_if_sum.rs`)で `phase212_if_sum_min.hako` 相当の Structured JoinModule を生成
- ✅ StepScheduleBox: `IfCond`, `ThenUpdates`, `ElseUpdates` ステップ追加 - ✅ Normalized dev ランナー経路で Structured→Normalized→Structured roundtrip を通し、JoinIR Runner の実行結果が一致することをテストで固定
- ✅ JpInst: 既存の `If` 命令を再利用 `build_pattern3_if_sum_min_structured_for_normalized_dev` + `normalized_pattern3_if_sum_minimal_runner_dev_switch_matches_structured`
- 🎯 Test: `phase212_if_sum_min.hako` → Normalized→MIR(direct) 検証 - ⏳ StepScheduleBox 拡張(`IfCond` / `ThenUpdates` / `ElseUpdates`)と direct Normalized→MIR ブリッジ適用は次フェーズの実装タスクPhase 47-A/B 継続)
**Phase 47-B**: array_filter (dev-only, body-local + method calls) **Phase 47-B**: array_filter (dev-only, body-local + method calls)

View File

@ -1,6 +1,6 @@
# Phase 47: Normalized P3 (If-Sum) Design # Phase 47: Normalized P3 (If-Sum) Design
**Status**: Design Complete, Implementation Planned **Status**: Design Complete, Minimal Dev Test Implemented
**Date**: 2025-12-12 **Date**: 2025-12-12
## Goal ## Goal
@ -272,7 +272,7 @@ pub enum JpInst {
### Phase 47-A: Minimal ### Phase 47-A: Minimal
**Test**: `test_normalized_pattern3_if_sum_minimal` **Test (runner-based, implemented)**: `normalized_pattern3_if_sum_minimal_runner_dev_switch_matches_structured`
```rust ```rust
#[cfg(feature = "normalized_dev")] #[cfg(feature = "normalized_dev")]
@ -294,16 +294,13 @@ fn test_normalized_pattern3_if_sum_minimal() {
print("count = " + count.to_string()) print("count = " + count.to_string())
"#; "#;
// Compare Structured→MIR vs Normalized→MIR(direct) // 現在は Runner ベースで Structured→Normalized→Structured roundtrip のみ実装済み。
assert_vm_output_matches(source); // VM Bridge での Normalized→MIR(direct) 比較は後続ステップ。
} }
``` ```
**Expected output**: **Expected output**phase212_if_sum_min.hako 相当):
``` `sum = 2`3 回中 2 回加算)
sum = 6 (1 + 3 + 5)
count = 3
```
### Phase 47-B: array_filter ### Phase 47-B: array_filter

View File

@ -7,6 +7,7 @@ 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_scope_shape::LoopScopeShape;
use crate::mir::join_ir::lowering::loop_update_analyzer::UpdateExpr; 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_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::JoinModule; use crate::mir::join_ir::JoinModule;
use crate::mir::{BasicBlockId, ValueId}; use crate::mir::{BasicBlockId, ValueId};
use crate::{config::env::joinir_dev_enabled, config::env::joinir_test_debug_enabled}; use crate::{config::env::joinir_dev_enabled, config::env::joinir_test_debug_enabled};
@ -210,6 +211,91 @@ pub fn build_jsonparser_atoi_real_structured_for_normalized_dev() -> JoinModule
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
}
/// まとめて import したいとき用のプレリュード。 /// まとめて import したいとき用のプレリュード。
pub mod prelude { pub mod prelude {
pub use super::{ pub use super::{
@ -219,5 +305,6 @@ pub mod prelude {
build_jsonparser_skip_ws_real_structured_for_normalized_dev, build_jsonparser_skip_ws_real_structured_for_normalized_dev,
build_jsonparser_skip_ws_structured_for_normalized_dev, build_jsonparser_skip_ws_structured_for_normalized_dev,
build_pattern2_break_fixture_structured, build_pattern2_minimal_structured, build_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
build_pattern3_if_sum_min_structured_for_normalized_dev,
}; };
} }

View File

@ -16,6 +16,7 @@ use nyash_rust::mir::join_ir::normalized::fixtures::{
build_jsonparser_skip_ws_real_structured_for_normalized_dev, build_jsonparser_skip_ws_real_structured_for_normalized_dev,
build_jsonparser_skip_ws_structured_for_normalized_dev, build_jsonparser_skip_ws_structured_for_normalized_dev,
build_pattern2_break_fixture_structured, build_pattern2_minimal_structured, build_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
build_pattern3_if_sum_min_structured_for_normalized_dev,
}; };
use nyash_rust::mir::join_ir_runner::run_joinir_function; use nyash_rust::mir::join_ir_runner::run_joinir_function;
use nyash_rust::mir::join_ir_ops::JoinValue; use nyash_rust::mir::join_ir_ops::JoinValue;
@ -508,6 +509,26 @@ fn normalized_pattern2_jsonparser_atoi_real_vm_bridge_direct_matches_structured(
} }
} }
#[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)",
);
}
#[cfg(feature = "normalized_dev")] #[cfg(feature = "normalized_dev")]
#[test] #[test]
fn test_phase46_canonical_set_includes_p2_mid() { fn test_phase46_canonical_set_includes_p2_mid() {