feat(joinir): Phase 56 ArrayExtBox.filter JoinIR lowering完全実装
## Summary
ArrayExtBox.filter/2 の JoinIR Frontend lowering を完全実装し、
ConditionalMethodCall 命令を導入して filter パターンに対応。
56 JoinIR テスト全て PASS(退行なし)。
## Technical Changes
### 1. ConditionalMethodCall 命令追加
- **新規命令**: `if pred(v) { acc.push(v) }` パターン用
- **構造**: cond が true なら method 実行、false なら no-op
- **MIR 変換**: 4ブロック構造 (cond→then/else→merge)
### 2. AST JSON 拡張
- Break/Continue/FunctionCall に "type" フィールド追加
- ArrayLiteral/MapLiteral に "type" フィールド追加
- JoinIR Frontend 互換性向上
### 3. Expression Handler 拡張
- Unary 演算子(not, 負号)サポート
- Call(変数関数呼び出し)を MethodCall に変換
### 4. Loop Pattern Binding 修正
- `BoundExpr::Variable("n")` 問題修正
- `MethodCall { receiver: "arr", method: "size" }` に変更
- external_refs (arr, pred) を step 関数に伝播
### 5. If Statement Handler 拡張
- 条件付き側効果パターン(ケース4)追加
- MethodCall/Method 形式の statement を ConditionalMethodCall に変換
## Files Modified (10 files, +456/-45 lines)
- ast_json.rs: AST JSON "type" フィールド追加
- loop_frontend_binding.rs: n バインディング修正
- control_flow.rs: external_refs params 追加
- loop_patterns.rs: external_refs step 関数伝播
- expr.rs: Unary, Call handler 追加
- stmt_handlers.rs: ConditionalMethodCall パターン追加
- mod.rs: ConditionalMethodCall, UnaryOp 定義
- json.rs: ConditionalMethodCall, UnaryOp シリアライズ
- join_ir_runner.rs: ConditionalMethodCall, UnaryOp スタブ
- convert.rs: ConditionalMethodCall → MIR 変換
## Test Results
- 56 JoinIR tests: ✅ PASSED
- Regression: ❌ None
- ArrayExtBox.filter/2: ✅ JoinIR lowering 成功
## Milestone
JoinIR 2ループ完走達成:
- ✅ JsonTokenizer.print_tokens/0
- ✅ ArrayExtBox.filter/2 (NEW!)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -49,8 +49,6 @@ pub enum BoundExpr {
|
||||
Variable(String),
|
||||
/// メソッド呼び出し (e.g., "me.tokens", "length")
|
||||
MethodCall { receiver: String, method: String },
|
||||
/// 不明(フォールバック用)
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// ループパターン種別
|
||||
@ -62,12 +60,6 @@ pub enum LoopPattern {
|
||||
|
||||
/// フィルターパターン (if + push)
|
||||
Filter,
|
||||
|
||||
/// マップパターン (変換 + push)
|
||||
Map,
|
||||
|
||||
/// 不明(フォールバック用)
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl LoopFrontendBinding {
|
||||
@ -114,7 +106,7 @@ impl LoopFrontendBinding {
|
||||
/// ```nyash
|
||||
/// local out = new ArrayBox()
|
||||
/// local i = 0
|
||||
/// local n = arr.size()
|
||||
/// local n = arr.size() // ← JoinIR では arr.size() を直接評価
|
||||
/// loop(i < n) {
|
||||
/// local v = arr.get(i)
|
||||
/// if pred(v) { out.push(v) }
|
||||
@ -122,12 +114,21 @@ impl LoopFrontendBinding {
|
||||
/// }
|
||||
/// return out
|
||||
/// ```
|
||||
///
|
||||
/// Phase 56: `BoundExpr::Variable("n")` から `BoundExpr::MethodCall` に変更。
|
||||
/// `n` はループ外で宣言されているため、JoinIR コンテキストに存在しない。
|
||||
/// 代わりに `arr.size()` を直接呼び出して `n` を初期化する。
|
||||
pub fn for_array_filter() -> Self {
|
||||
Self {
|
||||
counter_var: "i".to_string(),
|
||||
counter_init: 0,
|
||||
accumulator_var: Some("out".to_string()), // filter has "out" as accumulator
|
||||
bound_expr: BoundExpr::Variable("n".to_string()),
|
||||
// Phase 56: Variable("n") → MethodCall { arr, size }
|
||||
// n はループ外で宣言されているため、arr.size() を直接呼び出す
|
||||
bound_expr: BoundExpr::MethodCall {
|
||||
receiver: "arr".to_string(),
|
||||
method: "size".to_string(),
|
||||
},
|
||||
external_refs: vec!["arr".to_string(), "pred".to_string()],
|
||||
pattern: LoopPattern::Filter,
|
||||
}
|
||||
@ -264,17 +265,6 @@ impl LoopFrontendBinding {
|
||||
}
|
||||
})
|
||||
}
|
||||
BoundExpr::Unknown => {
|
||||
// フォールバック: 0 を使う
|
||||
json!({
|
||||
"type": "Local",
|
||||
"name": "n",
|
||||
"expr": {
|
||||
"type": "Int",
|
||||
"value": 0
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
(i_local, acc_local, n_local)
|
||||
|
||||
Reference in New Issue
Block a user