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:
nyash-codex
2025-11-29 06:51:43 +09:00
parent ee6e95b164
commit ad9daf37ac
11 changed files with 456 additions and 45 deletions

View File

@ -1,6 +1,6 @@
//! Control-flow entrypoints (if/loop/try/throw) centralized here.
use super::{Effect, EffectMask, MirInstruction, ValueId};
use crate::ast::{ASTNode, Span};
use crate::ast::ASTNode;
impl super::MirBuilder {
/// Control-flow: block
@ -173,16 +173,29 @@ impl super::MirBuilder {
// Phase 50: Generate Local declarations from binding
let (i_local, acc_local, n_local) = binding.generate_local_declarations();
// Phase 52: Check if `me` receiver is needed
// Instance methods (like print_tokens) need `me` to be passed as a parameter
let params: Vec<serde_json::Value> = if binding.needs_me_receiver() {
// Phase 52/56: Build params from external_refs
// Instance methods need `me`, static methods need their parameters (arr, pred, etc.)
let mut params: Vec<serde_json::Value> = Vec::new();
// Phase 52: Add 'me' for instance methods
if binding.needs_me_receiver() {
if debug {
eprintln!("[cf_loop/joinir] Adding 'me' to params (instance method)");
}
vec![serde_json::json!("me")]
} else {
vec![]
};
params.push(serde_json::json!("me"));
}
// Phase 56: Add external_refs as parameters (arr, pred for filter)
for ext_ref in &binding.external_refs {
// Skip "me" and "me.*" as they're handled above
if ext_ref == "me" || ext_ref.starts_with("me.") {
continue;
}
if debug {
eprintln!("[cf_loop/joinir] Adding '{}' to params (external_ref)", ext_ref);
}
params.push(serde_json::json!(ext_ref));
}
// Step 2: Construct JSON v0 format with "defs" array
// The function is named "simple" to match JoinIR Frontend's pattern matching