feat(joinir): Phase 194 - Table-driven loop pattern router

Replace if/else chain with table-driven pattern dispatch for easier
pattern addition and maintenance.

# Changes

## New Files
- router.rs (137 lines): Pattern router table and dispatch logic
  - LoopPatternContext: Context passed to detect/lower functions
  - LoopPatternEntry: Pattern registration structure
  - LOOP_PATTERNS: Static table with 3 registered patterns
  - route_loop_pattern(): Single dispatch function

## Modified Files
- patterns/mod.rs (+8 lines): Export router module
- pattern1_minimal.rs (+19 lines): Added can_lower() + lower() wrapper
- pattern2_with_break.rs (+17 lines): Added can_lower() + lower() wrapper
- pattern3_with_if_phi.rs (+22 lines): Added can_lower() + lower() wrapper
- routing.rs (-21 lines): Replaced if/else chain with router call

# Architecture Improvement

## Before (if/else chain)
```rust
if func_name == "main" && has_sum {
    return pattern3(...);
} else if func_name == "main" {
    return pattern1(...);
} else if func_name == "JoinIrMin.main/0" {
    return pattern2(...);
}
```

## After (table-driven)
```rust
let ctx = LoopPatternContext::new(...);
route_loop_pattern(self, &ctx)?
```

# Adding New Patterns (Now Trivial!)

1. Create pattern4_your_name.rs
2. Implement can_lower() + lower()
3. Add entry to LOOP_PATTERNS table

That's it! No routing logic changes needed.

# Testing

 Pattern 1 (loop_min_while.hako): PASSED
 Pattern 2 (joinir_min_loop.hako): PASSED
 Pattern 3 (loop_if_phi.hako): Routes correctly (VM error is pre-existing)

Router logging verified:
```
NYASH_TRACE_VARMAP=1 ./target/release/hakorune apps/tests/*.hako
[route] Pattern 'Pattern1_Minimal' matched for function 'main'
[route] Pattern 'Pattern2_WithBreak' matched for function 'JoinIrMin.main/0'
[route] Pattern 'Pattern3_WithIfPhi' matched for function 'main'
```

# Line Counts

- router.rs: 137 lines (new)
- Total pattern files: 491 lines (3 patterns)
- routing.rs: Reduced by 21 lines (-6%)
- Net addition: +137 lines (infrastructure investment)

# Documentation

See router.rs header for:
- Architecture overview
- How to add new patterns
- Priority ordering (Pattern3=30, Pattern1=10, Pattern2=20)

Phase 194 complete - pattern addition is now a trivial task!

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-05 22:11:39 +09:00
parent e1f1ba6427
commit 67e2bfada4
6 changed files with 215 additions and 20 deletions

View File

@ -124,30 +124,20 @@ impl MirBuilder {
use crate::mir::MirInstruction;
use crate::r#macro::ast_json::ast_to_json;
// Phase 188-Impl-3: Route Pattern 3 (If-Else PHI) - detect by 'sum' variable presence
// This MUST come before Pattern 1 check to avoid incorrect routing
// Pattern 3 test (loop_if_phi.hako) uses "main" with 'sum' accumulator variable
if func_name == "main" && self.variable_map.contains_key("sum") {
// Phase 194: Use table-driven router instead of if/else chain
// This makes adding new patterns trivial - just add an entry to LOOP_PATTERNS table
use super::patterns::{route_loop_pattern, LoopPatternContext};
let ctx = LoopPatternContext::new(condition, body, &func_name, debug);
if let Some(result) = route_loop_pattern(self, &ctx)? {
if debug {
eprintln!("[cf_loop/joinir] Routing 'main' (with sum var) through Pattern 3 minimal lowerer");
eprintln!("[cf_loop/joinir] Pattern router succeeded for '{}'", func_name);
}
return self.cf_loop_pattern3_with_if_phi(condition, body, func_name, debug);
return Ok(Some(result));
}
// Phase 188-Impl-1-F: Route Pattern 1 (Simple While) - "main" without 'sum' variable
if func_name == "main" {
if debug {
eprintln!("[cf_loop/joinir] Routing '{}' through Pattern 1 minimal lowerer", func_name);
}
return self.cf_loop_pattern1_minimal(condition, body, func_name, debug);
}
// Phase 188-Impl-2: Route "JoinIrMin.main/0" through Pattern 2 minimal lowerer (Loop with Break)
if func_name == "JoinIrMin.main/0" {
if debug {
eprintln!("[cf_loop/joinir] Routing 'JoinIrMin.main/0' through Pattern 2 minimal lowerer");
}
return self.cf_loop_pattern2_with_break(condition, body, func_name, debug);
if debug {
eprintln!("[cf_loop/joinir] Pattern router found no match for '{}', continuing to legacy path", func_name);
}
// Phase 50: Create appropriate binding based on function name