2025-11-23 16:49:49 +09:00
|
|
|
|
//! JoinIR — 関数正規化 IR(Phase 26-H)
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! 目的: Hakorune の制御構造を **関数呼び出し+継続だけに正規化** する IR 層。
|
|
|
|
|
|
//! - φ ノード = 関数の引数
|
|
|
|
|
|
//! - merge ブロック = join 関数
|
|
|
|
|
|
//! - ループ = 再帰関数(loop_step)+ exit 継続(k_exit)
|
|
|
|
|
|
//! - break / continue = 適切な関数呼び出し
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! 位置づけ:
|
|
|
|
|
|
//! ```text
|
|
|
|
|
|
//! AST → MIR(+LoopForm v2) → JoinIR → VM / LLVM
|
|
|
|
|
|
//! ```
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! Phase 26-H スコープ:
|
|
|
|
|
|
//! - 型定義のみ(変換ロジックは次フェーズ)
|
|
|
|
|
|
//! - 最小限の命令セット
|
|
|
|
|
|
//! - Debug 出力で妥当性確認
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! Phase 27.9: Modular Structure
|
|
|
|
|
|
//! - Type definitions and common utilities in this file
|
|
|
|
|
|
//! - Lowering functions in `lowering/` submodule
|
|
|
|
|
|
|
|
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
|
|
2025-11-24 15:02:51 +09:00
|
|
|
|
use crate::mir::ValueId;
|
2025-11-23 16:49:49 +09:00
|
|
|
|
|
|
|
|
|
|
// Phase 27.9: Lowering submodule
|
|
|
|
|
|
pub mod lowering;
|
|
|
|
|
|
|
2025-11-25 06:38:43 +09:00
|
|
|
|
// Phase 29 L-5.2: Progress verification
|
|
|
|
|
|
pub mod verify;
|
|
|
|
|
|
|
feat(joinir): Phase 30.x jsonir v0 - JoinIR JSON serialization
Implement JSON serialization for JoinIR module.
Implementation:
- src/mir/join_ir/json.rs: JSON serializer (~250 lines, no external deps)
- src/tests/joinir_json_min.rs: Integration tests (8 unit + 2 integration)
- 10 tests total, all passing
Features:
- JoinModule → JSON serialization
- All instruction types: Call, Jump, Ret, Compute
- All MirLikeInst types: Const, BinOp, Compare, BoxCall
- Full ConstValue support: Integer, Bool, String, Null
- Full operator coverage: Add/Sub/Mul/Div/Or/And, Lt/Le/Gt/Ge/Eq/Ne
- JSON string escaping for special characters
Usage:
use crate::mir::join_ir::json::join_module_to_json_string;
let json = join_module_to_json_string(&module);
Non-goals (this phase):
- CLI flag (--emit-joinir-json)
- JSON → JoinIR reverse conversion
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 09:53:26 +09:00
|
|
|
|
// Phase 30.x: JSON serialization (jsonir v0)
|
|
|
|
|
|
pub mod json;
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// Phase 34-1: Frontend (AST→JoinIR) — skeleton only
|
|
|
|
|
|
pub mod frontend;
|
|
|
|
|
|
|
2025-11-23 16:49:49 +09:00
|
|
|
|
// Re-export lowering functions for backward compatibility
|
|
|
|
|
|
pub use lowering::{
|
|
|
|
|
|
lower_funcscanner_trim_to_joinir, lower_min_loop_to_joinir, lower_skip_ws_to_joinir,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-25 06:38:43 +09:00
|
|
|
|
// Re-export verification functions
|
|
|
|
|
|
pub use verify::verify_progress_for_skip_ws;
|
|
|
|
|
|
|
2025-11-23 16:49:49 +09:00
|
|
|
|
/// JoinIR 関数ID(MIR 関数とは別 ID でもよい)
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
|
pub struct JoinFuncId(pub u32);
|
|
|
|
|
|
|
|
|
|
|
|
impl JoinFuncId {
|
|
|
|
|
|
pub fn new(id: u32) -> Self {
|
|
|
|
|
|
JoinFuncId(id)
|
|
|
|
|
|
}
|
2025-11-28 01:02:49 +09:00
|
|
|
|
|
|
|
|
|
|
/// JoinFuncId を JoinContId に変換
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Use Case
|
|
|
|
|
|
/// Jump 命令で関数を continuation として使う場合
|
|
|
|
|
|
/// ```rust
|
|
|
|
|
|
/// let func_id = JoinFuncId(42);
|
|
|
|
|
|
/// let cont_id = func_id.as_cont();
|
|
|
|
|
|
/// Jump { cont: cont_id, args: vec![], cond: None }
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Phase 34-7 Note
|
|
|
|
|
|
/// JoinFuncId と JoinContId は別の newtype だが、内部的には同じ u32 ID を共有する。
|
|
|
|
|
|
/// この変換は型レベルでの役割の明示(関数 vs 継続)を可能にする。
|
|
|
|
|
|
pub fn as_cont(self) -> JoinContId {
|
|
|
|
|
|
JoinContId(self.0)
|
|
|
|
|
|
}
|
2025-11-23 16:49:49 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 継続(join / ループ step / exit continuation)を識別するID
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
|
pub struct JoinContId(pub u32);
|
|
|
|
|
|
|
|
|
|
|
|
impl JoinContId {
|
|
|
|
|
|
pub fn new(id: u32) -> Self {
|
|
|
|
|
|
JoinContId(id)
|
|
|
|
|
|
}
|
2025-11-28 01:02:49 +09:00
|
|
|
|
|
|
|
|
|
|
/// JoinContId を JoinFuncId に変換
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Use Case
|
|
|
|
|
|
/// 継続 ID を関数 ID として参照する場合(JoinModule の functions map でルックアップ時など)
|
|
|
|
|
|
/// ```rust
|
|
|
|
|
|
/// let cont_id = JoinContId(42);
|
|
|
|
|
|
/// let func = join_module.functions.get(&cont_id.as_func())?;
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Phase 34-7 Note
|
|
|
|
|
|
/// JoinIR では継続も関数として実装されるため、この変換が必要になる。
|
|
|
|
|
|
pub fn as_func(self) -> JoinFuncId {
|
|
|
|
|
|
JoinFuncId(self.0)
|
|
|
|
|
|
}
|
2025-11-23 16:49:49 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 変数ID(Phase 26-H では MIR の ValueId を再利用)
|
|
|
|
|
|
pub type VarId = ValueId;
|
|
|
|
|
|
|
|
|
|
|
|
/// 環境変数フラグが "1" かチェックするヘルパー(JoinIR 実験経路用)
|
|
|
|
|
|
pub(crate) fn env_flag_is_1(name: &str) -> bool {
|
|
|
|
|
|
std::env::var(name).ok().as_deref() == Some("1")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Phase 27.4-A: ループ header φ の意味を表す構造(Pinned/Carrier 分類)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// HeaderPhiBuilder が生成していた「ループ変数の合流」を JoinIR の loop_step 引数として表現するためのヘルパー。
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 用語:
|
|
|
|
|
|
/// - **Pinned**: ループ中で値が変わらない変数(例: skip_ws の s, n / trim の str, b)
|
|
|
|
|
|
/// - **Carrier**: ループで更新される変数(例: skip_ws の i / trim の e)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Phase 27.4 では minimal/trim 用に手動で構成するが、将来は LoopVarClassBox から自動導出する。
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
#[allow(dead_code)] // Phase 27.4-C で実際に使用予定(現在は設計の雛形)
|
|
|
|
|
|
pub(crate) struct LoopHeaderShape {
|
|
|
|
|
|
/// Pinned: ループ中で不変の変数リスト(初期値がそのまま使われる)
|
|
|
|
|
|
pinned: Vec<ValueId>,
|
|
|
|
|
|
/// Carrier: ループで更新される変数リスト(φ ノードで合流が必要)
|
|
|
|
|
|
carriers: Vec<ValueId>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)] // Phase 27.4-C で実際に使用予定
|
|
|
|
|
|
impl LoopHeaderShape {
|
|
|
|
|
|
/// Phase 27.4-A: 手動で Pinned/Carrier を指定して構築
|
|
|
|
|
|
pub(crate) fn new_manual(pinned: Vec<ValueId>, carriers: Vec<ValueId>) -> Self {
|
|
|
|
|
|
LoopHeaderShape { pinned, carriers }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// loop_step 関数の引数リストを生成(pinned → carrier の順)
|
|
|
|
|
|
pub(crate) fn to_loop_step_params(&self) -> Vec<ValueId> {
|
|
|
|
|
|
let mut params = self.pinned.clone();
|
|
|
|
|
|
params.extend(self.carriers.clone());
|
|
|
|
|
|
params
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Phase 27.5: ループ exit φ の意味を表す構造
|
|
|
|
|
|
///
|
|
|
|
|
|
/// ExitPhiBuilder が生成していた「ループ脱出時の変数合流」を JoinIR の k_exit 引数として表現するためのヘルパー。
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 用語:
|
|
|
|
|
|
/// - **exit_args**: ループから脱出する際に k_exit に渡す値のリスト
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 例:
|
|
|
|
|
|
/// - **minimal_ssa_skip_ws**: exit_args = [i]
|
|
|
|
|
|
/// - ループから抜ける時、現在の i の値を返す
|
|
|
|
|
|
/// - **FuncScanner.trim**: exit_args = [e] (Option A)
|
|
|
|
|
|
/// - ループから抜ける時、現在の e の値を返す(後続で substring(b, e) を呼ぶ)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Phase 27.5 では minimal/trim 用に手動で構成するが、将来は ExitPhiBuilder の分析から自動導出する。
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
#[allow(dead_code)] // Phase 27.6 で Exit φ 統合の実装フェーズで使用予定(現在は設計の雛形)
|
|
|
|
|
|
pub(crate) struct LoopExitShape {
|
|
|
|
|
|
/// Exit 時に k_exit に渡したい値(JoinIR 引数)
|
|
|
|
|
|
exit_args: Vec<ValueId>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)] // Phase 27.6 で実際に使用予定
|
|
|
|
|
|
impl LoopExitShape {
|
|
|
|
|
|
/// Phase 27.5: 手動で exit_args を指定して構築
|
|
|
|
|
|
pub(crate) fn new_manual(exit_args: Vec<ValueId>) -> Self {
|
|
|
|
|
|
LoopExitShape { exit_args }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// JoinIR 関数
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub struct JoinFunction {
|
|
|
|
|
|
/// 関数ID
|
|
|
|
|
|
pub id: JoinFuncId,
|
|
|
|
|
|
|
|
|
|
|
|
/// 関数名(デバッグ用)
|
|
|
|
|
|
pub name: String,
|
|
|
|
|
|
|
|
|
|
|
|
/// 引数(φ に相当)
|
|
|
|
|
|
pub params: Vec<VarId>,
|
|
|
|
|
|
|
|
|
|
|
|
/// 命令列(現在は直列、将来的にはブロック構造も可)
|
|
|
|
|
|
pub body: Vec<JoinInst>,
|
|
|
|
|
|
|
|
|
|
|
|
/// 呼び出し元に返す継続(ルートは None)
|
|
|
|
|
|
pub exit_cont: Option<JoinContId>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl JoinFunction {
|
|
|
|
|
|
pub fn new(id: JoinFuncId, name: String, params: Vec<VarId>) -> Self {
|
|
|
|
|
|
Self {
|
|
|
|
|
|
id,
|
|
|
|
|
|
name,
|
|
|
|
|
|
params,
|
|
|
|
|
|
body: Vec::new(),
|
|
|
|
|
|
exit_cont: None,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
/// Phase 33-6: 複数変数を merge する if/else のペア
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub struct MergePair {
|
|
|
|
|
|
/// merge 先の変数
|
|
|
|
|
|
pub dst: VarId,
|
|
|
|
|
|
/// then 分岐での値
|
|
|
|
|
|
pub then_val: VarId,
|
|
|
|
|
|
/// else 分岐での値
|
|
|
|
|
|
pub else_val: VarId,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-23 16:49:49 +09:00
|
|
|
|
/// JoinIR 命令セット(最小版)
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub enum JoinInst {
|
2025-11-28 01:02:49 +09:00
|
|
|
|
/// 通常の関数呼び出し(末尾再帰): f(args..., k_next)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Semantics
|
|
|
|
|
|
/// - 他の JoinIR 関数を呼び出す(MIR の Call に変換)
|
|
|
|
|
|
/// - ループでは末尾再帰として使うのが典型的
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # MIR 変換
|
|
|
|
|
|
/// - `MirInstruction::Call { func, args, ... }` を生成
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Constraints (Phase 31/34 時点)
|
|
|
|
|
|
/// - **k_next は常に None にすること!**
|
|
|
|
|
|
/// JoinIR→MIR bridge が `k_next: Some(...)` 未対応
|
|
|
|
|
|
/// → エラー: "Call with k_next is not yet supported"
|
|
|
|
|
|
/// - 典型的な使い方: `Call { func, args, k_next: None, dst: Some(...) }`
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Loop Pattern での使い方 (Phase 34-7)
|
|
|
|
|
|
/// ```rust
|
|
|
|
|
|
/// // ✅ 正解: 末尾再帰
|
|
|
|
|
|
/// Call {
|
|
|
|
|
|
/// func: loop_step_id,
|
|
|
|
|
|
/// args: vec![i_next, acc_next, n],
|
|
|
|
|
|
/// k_next: None, // ⚠️ 必須: None にすること
|
|
|
|
|
|
/// dst: Some(result),
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// ```
|
2025-11-23 16:49:49 +09:00
|
|
|
|
Call {
|
|
|
|
|
|
func: JoinFuncId,
|
|
|
|
|
|
args: Vec<VarId>,
|
|
|
|
|
|
k_next: Option<JoinContId>,
|
|
|
|
|
|
/// 呼び出し結果を書き込む変数(None の場合は末尾呼び出しとして扱う)
|
|
|
|
|
|
dst: Option<VarId>,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-28 01:02:49 +09:00
|
|
|
|
/// 継続呼び出し(早期 return / exit 継続)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Semantics
|
|
|
|
|
|
/// - **「早期 return」(条件付き関数脱出)として使う!**
|
|
|
|
|
|
/// - cond=Some(v): v が true なら cont に Jump、false なら次の命令へ
|
|
|
|
|
|
/// - cond=None: 無条件 Jump
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # MIR 変換
|
|
|
|
|
|
/// - cond=Some(v): `Branch(v, exit_block[Return], continue_block)` を生成
|
|
|
|
|
|
/// - exit_block: cont 関数を Call して Return
|
|
|
|
|
|
/// - continue_block: 次の JoinInst に続く
|
|
|
|
|
|
/// - cond=None: 無条件に cont を Call して Return
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Loop Pattern での使い方 (Phase 34-7)
|
|
|
|
|
|
/// ```rust
|
|
|
|
|
|
/// // ✅ 正解: 条件付き早期 return
|
|
|
|
|
|
/// Jump {
|
|
|
|
|
|
/// cont: k_exit_id.as_cont(),
|
|
|
|
|
|
/// args: vec![acc],
|
|
|
|
|
|
/// cond: Some(exit_cond), // exit_cond が true なら k_exit へ
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// // ↑ exit_cond が false なら次の命令(body 処理)へ進む
|
|
|
|
|
|
///
|
|
|
|
|
|
/// // ❌ 間違い: Call で条件分岐しようとする
|
|
|
|
|
|
/// Call {
|
|
|
|
|
|
/// func: k_exit_id,
|
|
|
|
|
|
/// cond: Some(exit_cond), // こんなフィールドはない!
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # 典型的なパターン
|
|
|
|
|
|
/// ```text
|
|
|
|
|
|
/// loop_step(i, acc, n):
|
|
|
|
|
|
/// exit_cond = !(i < n)
|
|
|
|
|
|
/// Jump(k_exit, [acc], cond=exit_cond) // 🔑 早期 return
|
|
|
|
|
|
/// // ↓ Jump で抜けなかった場合のみ実行
|
|
|
|
|
|
/// acc_next = acc + 1
|
|
|
|
|
|
/// i_next = i + 1
|
|
|
|
|
|
/// Call(loop_step, [i_next, acc_next, n]) // 🔑 末尾再帰
|
|
|
|
|
|
/// ```
|
2025-11-23 16:49:49 +09:00
|
|
|
|
Jump {
|
|
|
|
|
|
cont: JoinContId,
|
|
|
|
|
|
args: Vec<VarId>,
|
|
|
|
|
|
/// None のときは無条件ジャンプ、Some(var) のときは var が truthy のときだけ実行
|
|
|
|
|
|
cond: Option<VarId>,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// ルート関数 or 上位への戻り
|
2025-11-24 14:17:02 +09:00
|
|
|
|
Ret { value: Option<VarId> },
|
2025-11-23 16:49:49 +09:00
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
/// Phase 33: If/Else の単純な値選択(単一値)
|
2025-11-27 02:58:38 +09:00
|
|
|
|
/// cond が true なら then_val、false なら else_val を dst に代入
|
|
|
|
|
|
Select {
|
|
|
|
|
|
dst: VarId,
|
|
|
|
|
|
cond: VarId,
|
|
|
|
|
|
then_val: VarId,
|
|
|
|
|
|
else_val: VarId,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
/// Phase 33-6: If/Else の複数変数 merge
|
|
|
|
|
|
/// cond が true なら各 dst に then_val を、false なら else_val を代入
|
|
|
|
|
|
/// 複数の PHI ノードを一括で表現する
|
|
|
|
|
|
IfMerge {
|
|
|
|
|
|
cond: VarId,
|
|
|
|
|
|
merges: Vec<MergePair>,
|
|
|
|
|
|
k_next: Option<JoinContId>,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// Phase 34-6: メソッド呼び出し構造
|
|
|
|
|
|
/// receiver.method(args...) の構造を JoinIR で表現
|
|
|
|
|
|
/// 意味論(BoxCall/Call への変換)は JoinIR→MIR ブリッジで実装
|
|
|
|
|
|
MethodCall {
|
|
|
|
|
|
dst: VarId,
|
|
|
|
|
|
receiver: VarId,
|
|
|
|
|
|
method: String,
|
|
|
|
|
|
args: Vec<VarId>,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-29 06:51:43 +09:00
|
|
|
|
/// Phase 56: 条件付きメソッド呼び出し(filter パターン用)
|
|
|
|
|
|
/// cond が true の場合のみ receiver.method(args) を実行
|
|
|
|
|
|
/// cond が false の場合は dst = receiver(変更なし)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 使用例: `if pred(v) { acc.push(v) }` → ConditionalMethodCall
|
|
|
|
|
|
ConditionalMethodCall {
|
|
|
|
|
|
cond: VarId,
|
|
|
|
|
|
dst: VarId,
|
|
|
|
|
|
receiver: VarId,
|
|
|
|
|
|
method: String,
|
|
|
|
|
|
args: Vec<VarId>,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-28 21:10:30 +09:00
|
|
|
|
/// Phase 51: フィールドアクセス
|
|
|
|
|
|
/// object.field の構造を JoinIR で表現
|
|
|
|
|
|
/// MIR 変換時に Load 命令に変換
|
|
|
|
|
|
FieldAccess {
|
|
|
|
|
|
dst: VarId,
|
|
|
|
|
|
object: VarId,
|
|
|
|
|
|
field: String,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// Phase 51: Box インスタンス生成
|
|
|
|
|
|
/// new BoxName(args...) の構造を JoinIR で表現
|
|
|
|
|
|
/// MIR 変換時に NewBox 命令に変換
|
|
|
|
|
|
NewBox {
|
|
|
|
|
|
dst: VarId,
|
|
|
|
|
|
box_name: String,
|
|
|
|
|
|
args: Vec<VarId>,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-28 12:32:25 +09:00
|
|
|
|
/// Phase 41-4: 深いネスト if の複数変数 merge(else なし)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Pattern
|
|
|
|
|
|
/// ```text
|
|
|
|
|
|
/// if cond1 {
|
|
|
|
|
|
/// if cond2 {
|
|
|
|
|
|
/// if cond3 {
|
|
|
|
|
|
/// x = new_val // modifications only at deepest level
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// // merge: x = phi(new_val if all conds true, original otherwise)
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Semantics
|
|
|
|
|
|
/// - `conds`: 外側から内側への条件リスト
|
|
|
|
|
|
/// - `merges`: 最深レベルでの変数更新
|
|
|
|
|
|
/// - then_val: 全ての conds が true の場合の値
|
|
|
|
|
|
/// - else_val: いずれかの cond が false の場合の値(元の値)
|
|
|
|
|
|
/// - MIR 変換時に多段 Branch + PHI を生成
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Target
|
|
|
|
|
|
/// ParserControlBox.parse_loop() の 4 レベルネスト if パターン
|
|
|
|
|
|
NestedIfMerge {
|
|
|
|
|
|
/// 条件リスト(外側から内側へ)
|
|
|
|
|
|
conds: Vec<VarId>,
|
|
|
|
|
|
/// 変数更新(全条件 true 時 → then_val、いずれか false 時 → else_val)
|
|
|
|
|
|
merges: Vec<MergePair>,
|
|
|
|
|
|
/// merge 後の継続
|
|
|
|
|
|
k_next: Option<JoinContId>,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-23 16:49:49 +09:00
|
|
|
|
/// それ以外の演算は、現行 MIR の算術/比較/boxcall を再利用
|
|
|
|
|
|
Compute(MirLikeInst),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// MIR からの算術・比較命令のラッパー(Phase 26-H では最小限)
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub enum MirLikeInst {
|
|
|
|
|
|
/// 定数代入
|
2025-11-24 14:17:02 +09:00
|
|
|
|
Const { dst: VarId, value: ConstValue },
|
2025-11-23 16:49:49 +09:00
|
|
|
|
|
|
|
|
|
|
/// 二項演算
|
|
|
|
|
|
BinOp {
|
|
|
|
|
|
dst: VarId,
|
|
|
|
|
|
op: BinOpKind,
|
|
|
|
|
|
lhs: VarId,
|
|
|
|
|
|
rhs: VarId,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// 比較演算
|
|
|
|
|
|
Compare {
|
|
|
|
|
|
dst: VarId,
|
|
|
|
|
|
op: CompareOp,
|
|
|
|
|
|
lhs: VarId,
|
|
|
|
|
|
rhs: VarId,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/// Box呼び出し(将来的には統一 Call に統合予定)
|
|
|
|
|
|
BoxCall {
|
|
|
|
|
|
dst: Option<VarId>,
|
|
|
|
|
|
box_name: String,
|
|
|
|
|
|
method: String,
|
|
|
|
|
|
args: Vec<VarId>,
|
|
|
|
|
|
},
|
2025-11-29 06:51:43 +09:00
|
|
|
|
|
|
|
|
|
|
/// Phase 56: 単項演算(not, 負号)
|
|
|
|
|
|
UnaryOp {
|
|
|
|
|
|
dst: VarId,
|
|
|
|
|
|
op: UnaryOp,
|
|
|
|
|
|
operand: VarId,
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Phase 56: 単項演算種別
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
|
pub enum UnaryOp {
|
|
|
|
|
|
/// 論理否定
|
|
|
|
|
|
Not,
|
|
|
|
|
|
/// 算術否定(負号)
|
|
|
|
|
|
Neg,
|
2025-11-23 16:49:49 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 定数値(MIR の ConstValue を簡略化)
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub enum ConstValue {
|
|
|
|
|
|
Integer(i64),
|
|
|
|
|
|
Bool(bool),
|
|
|
|
|
|
String(String),
|
|
|
|
|
|
Null,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 二項演算種別
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
|
pub enum BinOpKind {
|
|
|
|
|
|
Add,
|
|
|
|
|
|
Sub,
|
|
|
|
|
|
Mul,
|
|
|
|
|
|
Div,
|
|
|
|
|
|
Or, // Phase 27.1: 論理OR (bool || bool)
|
|
|
|
|
|
And, // Phase 27.1: 論理AND (bool && bool)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 比較演算種別
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
|
pub enum CompareOp {
|
|
|
|
|
|
Lt,
|
|
|
|
|
|
Le,
|
|
|
|
|
|
Gt,
|
|
|
|
|
|
Ge,
|
|
|
|
|
|
Eq,
|
|
|
|
|
|
Ne,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// JoinIR モジュール(複数の関数を保持)
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub struct JoinModule {
|
|
|
|
|
|
/// 関数マップ
|
|
|
|
|
|
pub functions: BTreeMap<JoinFuncId, JoinFunction>,
|
|
|
|
|
|
|
|
|
|
|
|
/// エントリーポイント関数ID
|
|
|
|
|
|
pub entry: Option<JoinFuncId>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl JoinModule {
|
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
|
Self {
|
|
|
|
|
|
functions: BTreeMap::new(),
|
|
|
|
|
|
entry: None,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn add_function(&mut self, func: JoinFunction) {
|
|
|
|
|
|
self.functions.insert(func.id, func);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Default for JoinModule {
|
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
|
Self::new()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
|
mod tests {
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_join_function_creation() {
|
|
|
|
|
|
let func_id = JoinFuncId::new(0);
|
2025-11-24 14:17:02 +09:00
|
|
|
|
let func = JoinFunction::new(
|
|
|
|
|
|
func_id,
|
|
|
|
|
|
"test_func".to_string(),
|
|
|
|
|
|
vec![ValueId(1), ValueId(2)],
|
|
|
|
|
|
);
|
2025-11-23 16:49:49 +09:00
|
|
|
|
|
|
|
|
|
|
assert_eq!(func.id, func_id);
|
|
|
|
|
|
assert_eq!(func.name, "test_func");
|
|
|
|
|
|
assert_eq!(func.params.len(), 2);
|
|
|
|
|
|
assert_eq!(func.body.len(), 0);
|
|
|
|
|
|
assert_eq!(func.exit_cont, None);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_join_module() {
|
|
|
|
|
|
let mut module = JoinModule::new();
|
|
|
|
|
|
let func = JoinFunction::new(JoinFuncId::new(0), "main".to_string(), vec![]);
|
|
|
|
|
|
module.add_function(func);
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(module.functions.len(), 1);
|
|
|
|
|
|
assert!(module.functions.contains_key(&JoinFuncId::new(0)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn loop_header_shape_params_order_is_pinned_then_carrier() {
|
|
|
|
|
|
// Phase 27.4-A: to_loop_step_params() が pinned→carriers の順を返すことを保証
|
|
|
|
|
|
let v1 = ValueId(1);
|
|
|
|
|
|
let v2 = ValueId(2);
|
|
|
|
|
|
let v3 = ValueId(3);
|
|
|
|
|
|
let shape = LoopHeaderShape::new_manual(vec![v1, v2], vec![v3]);
|
|
|
|
|
|
let params = shape.to_loop_step_params();
|
|
|
|
|
|
assert_eq!(params, vec![v1, v2, v3]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|