Phase 179-A Step 2: Separate LoopFrontendBinding JSON construction logic into dedicated module for better organization. Changes: - New file: routing_legacy_binding.rs (223 lines) - routing.rs: cf_loop_joinir_impl() simplified to 15 lines (delegates to legacy path) - Routing now clearly separates pattern-based vs. legacy binding paths Benefits: - Clear separation of concerns (pattern router vs. legacy whitelist) - routing.rs reduced from 364 to 146 lines (60% reduction) - Legacy path isolated for future deprecation
146 lines
6.6 KiB
Rust
146 lines
6.6 KiB
Rust
//! JoinIR routing logic for loop lowering
|
||
|
||
use crate::ast::ASTNode;
|
||
use crate::mir::builder::MirBuilder;
|
||
use crate::mir::ValueId;
|
||
use super::trace;
|
||
|
||
impl MirBuilder {
|
||
/// Phase 49: Try JoinIR Frontend for mainline integration
|
||
///
|
||
/// Returns `Ok(Some(value))` if the loop is successfully lowered via JoinIR,
|
||
/// `Ok(None)` if no JoinIR pattern matched (unsupported loop structure).
|
||
/// Phase 187-2: Legacy LoopBuilder removed - all loops must use JoinIR.
|
||
///
|
||
/// # Phase 49-4: Multi-target support
|
||
///
|
||
/// Targets are enabled via separate dev flags:
|
||
/// - `HAKO_JOINIR_PRINT_TOKENS_MAIN=1`: JsonTokenizer.print_tokens/0
|
||
/// - `HAKO_JOINIR_ARRAY_FILTER_MAIN=1`: ArrayExtBox.filter/2
|
||
///
|
||
/// Note: Arity in function names does NOT include implicit `me` receiver.
|
||
/// - Instance method `print_tokens()` → `/0` (no explicit params)
|
||
/// - Static method `filter(arr, pred)` → `/2` (two params)
|
||
pub(in crate::mir::builder) fn try_cf_loop_joinir(
|
||
&mut self,
|
||
condition: &ASTNode,
|
||
body: &[ASTNode],
|
||
) -> Result<Option<ValueId>, String> {
|
||
// Get current function name
|
||
let func_name = self
|
||
.current_function
|
||
.as_ref()
|
||
.map(|f| f.signature.name.clone())
|
||
.unwrap_or_default();
|
||
|
||
// Phase 195: Use unified trace
|
||
trace::trace().routing("router", &func_name, "try_cf_loop_joinir called");
|
||
|
||
// Phase 170-4: Structure-based routing option
|
||
// When NYASH_JOINIR_STRUCTURE_ONLY=1, skip function name whitelist
|
||
// and route purely based on loop structure analysis
|
||
let structure_only = std::env::var("NYASH_JOINIR_STRUCTURE_ONLY")
|
||
.ok()
|
||
.as_deref()
|
||
== Some("1");
|
||
|
||
if structure_only {
|
||
trace::trace().routing("router", &func_name, "Structure-only mode enabled, skipping whitelist");
|
||
} else {
|
||
// Phase 49-4 + Phase 80: Multi-target routing (legacy whitelist)
|
||
// - Core ON なら代表2本(print_tokens / ArrayExt.filter)は JoinIR を優先し、失敗したら LoopBuilder へフォールバック
|
||
// - Core OFF では従来通り dev フラグで opt-in
|
||
// Note: Arity does NOT include implicit `me` receiver
|
||
// Phase 188: Add "main" routing for loop pattern expansion
|
||
// Phase 170: Add JsonParserBox methods for selfhost validation
|
||
let core_on = crate::config::env::joinir_core_enabled();
|
||
let is_target = match func_name.as_str() {
|
||
"main" => true, // Phase 188-Impl-1: Enable JoinIR for main function (Pattern 1)
|
||
"JoinIrMin.main/0" => true, // Phase 188-Impl-2: Enable JoinIR for JoinIrMin.main/0 (Pattern 2)
|
||
"JsonTokenizer.print_tokens/0" => {
|
||
if core_on {
|
||
true
|
||
} else {
|
||
std::env::var("HAKO_JOINIR_PRINT_TOKENS_MAIN")
|
||
.ok()
|
||
.as_deref()
|
||
== Some("1")
|
||
}
|
||
}
|
||
"ArrayExtBox.filter/2" => {
|
||
if core_on {
|
||
true
|
||
} else {
|
||
std::env::var("HAKO_JOINIR_ARRAY_FILTER_MAIN")
|
||
.ok()
|
||
.as_deref()
|
||
== Some("1")
|
||
}
|
||
}
|
||
// Phase 170-A-1: Enable JsonParserBox methods for JoinIR routing
|
||
"JsonParserBox._trim/1" => true,
|
||
"JsonParserBox._skip_whitespace/2" => true,
|
||
"JsonParserBox._match_literal/2" => true,
|
||
"JsonParserBox._parse_string/2" => true,
|
||
"JsonParserBox._parse_array/2" => true,
|
||
"JsonParserBox._parse_object/2" => true,
|
||
// Phase 170-A-1: Test methods (simplified versions)
|
||
"TrimTest.trim/1" => true,
|
||
"Main.trim/1" => true, // Phase 171-fix: Main box variant
|
||
"Main.trim_string_simple/1" => true, // Phase 33-13: Simple trim variant
|
||
"TrimTest.main/0" => true, // Phase 170: TrimTest.main for loop pattern test
|
||
// Phase 173: JsonParser P5 expansion test
|
||
"JsonParserTest._skip_whitespace/3" => true,
|
||
"JsonParserTest.main/0" => true,
|
||
// Phase 174: JsonParser complex loop P5B extension test
|
||
"JsonParserStringTest.parse_string_min/0" => true,
|
||
"JsonParserStringTest.main/0" => true,
|
||
// Phase 175: P5 multi-carrier support (2 carriers: pos + result)
|
||
"JsonParserStringTest2.parse_string_min2/0" => true,
|
||
"JsonParserStringTest2.main/0" => true,
|
||
_ => false,
|
||
};
|
||
|
||
if !is_target {
|
||
return Ok(None);
|
||
}
|
||
}
|
||
|
||
// Debug log when routing through JoinIR Frontend
|
||
// Phase 195: Check trace flags directly from JoinLoopTrace
|
||
let debug = trace::trace().is_loopform_enabled() || trace::trace().is_mainline_enabled();
|
||
trace::trace().routing("router", &func_name, "Routing through JoinIR Frontend mainline");
|
||
|
||
// Phase 49-3: Implement JoinIR Frontend integration
|
||
self.cf_loop_joinir_impl(condition, body, &func_name, debug)
|
||
}
|
||
|
||
/// Phase 49-3: JoinIR Frontend integration implementation
|
||
///
|
||
/// Routes loop compilation through either:
|
||
/// 1. Pattern-based router (Phase 194+) - preferred for new patterns
|
||
/// 2. Legacy binding path (Phase 49-3) - for whitelisted functions only
|
||
pub(in crate::mir::builder) fn cf_loop_joinir_impl(
|
||
&mut self,
|
||
condition: &ASTNode,
|
||
body: &[ASTNode],
|
||
func_name: &str,
|
||
debug: bool,
|
||
) -> Result<Option<ValueId>, String> {
|
||
// Phase 194: Use table-driven router instead of if/else chain
|
||
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)? {
|
||
trace::trace().routing("router", func_name, "Pattern router succeeded");
|
||
return Ok(Some(result));
|
||
}
|
||
|
||
// Phase 187-2: Pattern router failed, try legacy whitelist
|
||
trace::trace().routing("router", func_name, "Pattern router found no match, trying legacy whitelist");
|
||
|
||
// Delegate to legacy binding path (routing_legacy_binding.rs)
|
||
self.cf_loop_joinir_legacy_binding(condition, body, func_name, debug)
|
||
}
|
||
}
|