Files
hakorune/src/mir/builder/control_flow/joinir/routing.rs

166 lines
7.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! JoinIR routing logic for loop lowering
use super::trace;
use crate::ast::ASTNode;
use crate::mir::builder::MirBuilder;
use crate::mir::ValueId;
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
// Phase 196: Default to structure-first routing now that LoopBuilder is removed.
// - Default: ON (structure_only = true) to allow JoinIR patterns to run for all loops.
// - To revert to the previous whitelist-only behavior, set NYASH_JOINIR_STRUCTURE_ONLY=0.
let structure_only = match std::env::var("NYASH_JOINIR_STRUCTURE_ONLY").ok().as_deref() {
Some("0") | Some("off") => false,
_ => true,
};
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)
// - JoinIR は常時 ON。legacy LoopBuilder は削除済み。
// - 代表2本print_tokens / ArrayExt.filterも常に JoinIR で試行する。
// 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 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" => true,
"ArrayExtBox.filter/2" => true,
// Phase 170-A-1: Enable JsonParserBox methods for JoinIR routing
"JsonParserBox._trim/1" => true,
"JsonParserBox._skip_whitespace/2" => true,
"JsonParserBox._match_literal/3" => true, // Phase 182: Fixed arity (s, pos, literal)
"JsonParserBox._parse_string/2" => true,
"JsonParserBox._parse_array/2" => true,
"JsonParserBox._parse_object/2" => true,
// Phase 182: Add simple loop methods
"JsonParserBox._parse_number/2" => true, // P2 Break (s, pos)
"JsonParserBox._atoi/1" => true, // P2 Break (s)
// 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};
// Phase 200-C: Pass fn_body_ast to LoopPatternContext if available
// Clone fn_body_ast to avoid borrow checker issues
let fn_body_clone = self.fn_body_ast.clone();
eprintln!(
"[routing] fn_body_ast is {} for '{}'",
if fn_body_clone.is_some() {
"SOME"
} else {
"NONE"
},
func_name
);
let ctx = if let Some(ref fn_body) = fn_body_clone {
eprintln!(
"[routing] Creating ctx with fn_body ({} nodes)",
fn_body.len()
);
LoopPatternContext::with_fn_body(condition, body, &func_name, debug, fn_body)
} else {
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)
}
}