Files
hakorune/docs/archive/phases/phase-170-197/phase170-loop-condition-scope.md
nyash-codex a7dbc15878 feat(joinir): Phase 240-EX - Pattern2 header condition ExprLowerer integration
Implementation:
- Add make_pattern2_scope_manager() helper for DRY
- Header conditions use ExprLowerer for supported patterns
- Legacy fallback for unsupported patterns
- Fail-Fast on supported patterns that fail

Tests:
- 4 new tests (all pass)
- test_expr_lowerer_supports_simple_header_condition_i_less_literal
- test_expr_lowerer_supports_header_condition_var_less_var
- test_expr_lowerer_header_condition_generates_expected_instructions
- test_pattern2_header_condition_via_exprlowerer

Also: Archive old phase documentation (34k lines removed)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 00:33:04 +09:00

3.2 KiB
Raw Blame History

Phase 170D: LoopConditionScopeBox 設計メモ

日付: 20251207
状態: 設計完了(実装は今後の Phase で)

背景

Pattern2/Pattern4Loop with Break / Loop with Continueは、もともと

  • ループパラメータ(例: i
  • ループ外のローカル・引数(例: start, end, len

のみを条件式に使う前提で設計されていた。

しかし JsonParserBox / trim などでは、

local ch = …
if (ch != " ") { break }

のように「ループ本体ローカル」を条件に使うパターンが現れ、この範囲を超えると

  • バグが出たりValueId 伝播ミス)
  • たまたま動いたり

という 曖昧な状態 になっていた。

これを箱理論的に整理するために、条件で使われる変数の「スコープ」を明示的に分類する LoopConditionScopeBox を導入する。

LoopConditionScopeBox の責務

責務は 1 つだけ:

「条件式に登場する変数が、どのスコープで定義されたか」を教える

型イメージ

pub enum CondVarScope {
    LoopParam,     // ループパラメータ (i)
    OuterLocal,    // ループ外のローカル/引数 (start, end, len)
    LoopBodyLocal, // ループ本体で定義された変数 (ch)
}

pub struct CondVarInfo {
    pub name: String,
    pub scope: CondVarScope,
}

pub struct LoopConditionScope {
    pub vars: Vec<CondVarInfo>,
}

主なメソッド例:

impl LoopConditionScope {
    pub fn has_loop_body_local(&self) -> bool {  }

    pub fn all_in(&self, allowed: &[CondVarScope]) -> bool {  }

    pub fn vars_in(&self, scope: CondVarScope) -> impl Iterator<Item = &CondVarInfo> {  }
}

入力 / 出力

入力:

  • ループヘッダ条件 AST
  • break/continue 条件 ASTPattern2/4
  • LoopScopeShapeどの変数がどのスコープで定義されたか

出力:

  • LoopConditionScopeCondVarInfo の集合)

Pattern2/Pattern4 との関係

Pattern2/4 は LoopConditionScopeBox の結果だけを見て「対応可否」を決める:

let cond_scope = LoopConditionScopeBox::analyze(&loop_ast, &loop_scope);

// 対応範囲LoopParam + OuterLocal のみ
if !cond_scope.all_in(&[CondVarScope::LoopParam, CondVarScope::OuterLocal]) {
    return Err(JoinIrError::UnsupportedPattern {  });
}

これにより、

  • いままで暗黙だった「対応範囲」が 設計として明示される
  • LoopBodyLocal を条件に含む trim/JsonParser 系ループは
    • 現状は [joinir/freeze] UnsupportedPattern にする
    • 将来 Pattern5+ で扱いたくなったときに、LoopConditionScopeBox の結果を使って設計できる

将来の拡張

LoopBodyLocal を含む条件式を扱いたくなった場合は:

  • LoopConditionScopeBox の結果から vars_in(LoopBodyLocal) を取り出し、
    • その変数を carrier に昇格させる
    • もしくは LoopHeader に「状態保持用」の追加パラメータを生やす
  • それを新しい Pattern5 として設計すれば、既存 Pattern2/4 の仕様を崩さずに拡張できる。

このドキュメントは設計メモのみであり、実装は別フェーズPhase 170Dimpl など)で行う。 Status: Historical