Files
hakorune/src/backend/mir_interpreter/handlers/call_resolution.rs

90 lines
2.8 KiB
Rust
Raw Normal View History

// Unique-tail function name resolution
// Extracted from execute_legacy_call to keep handlers lean
use std::collections::HashMap;
use super::MirFunction;
/// Resolve function name using unique-tail matching algorithm.
///
/// Resolution strategy:
/// 1. Fast path: exact match on raw name
/// 2. Normalize with arity: "base/N"
/// 3. Unique-tail matching: find candidates ending with ".method/N"
/// 4. Same-box preference: prioritize functions in the same box as current_function
///
/// Returns resolved function name, or None if resolution fails.
pub(super) fn resolve_function_name(
raw: &str,
arity: usize,
functions: &HashMap<String, MirFunction>,
current_function: Option<&str>,
) -> Option<String> {
// Fast path: exact match
if functions.contains_key(raw) {
return Some(raw.to_string());
}
// Robust normalization for names like "Box.method/Arity" or just "method"
let (base, ar_from_raw) = if let Some((b, a)) = raw.rsplit_once('/') {
(b.to_string(), a.parse::<usize>().ok())
} else {
(raw.to_string(), None)
};
let want_arity = ar_from_raw.unwrap_or(arity);
// Try exact canonical form: "base/arity"
let exact = format!("{}/{}", base, want_arity);
if functions.contains_key(&exact) {
return Some(exact);
}
// Split base into optional box and method name
let (maybe_box, method) = if let Some((bx, m)) = base.split_once('.') {
(Some(bx.to_string()), m.to_string())
} else {
(None, base.clone())
};
// Collect candidates that end with ".method/arity"
let mut cands: Vec<String> = Vec::new();
let tail = format!(".{}{}", method, format!("/{}", want_arity));
for k in functions.keys() {
if k.ends_with(&tail) {
if let Some(ref bx) = maybe_box {
if k.starts_with(&format!("{}.", bx)) {
cands.push(k.clone());
}
} else {
cands.push(k.clone());
}
}
}
if cands.len() > 1 {
// Prefer same-box candidate based on current function's box
if let Some(cur) = current_function {
let cur_box = cur.split('.').next().unwrap_or("");
let scoped: Vec<String> = cands
.iter()
.filter(|k| k.starts_with(&format!("{}.", cur_box)))
.cloned()
.collect();
if scoped.len() == 1 {
cands = scoped;
}
}
}
match cands.len() {
0 => None,
1 => Some(cands.into_iter().next().unwrap()),
_ => {
// Multiple candidates: sort and pick first (deterministic fallback)
let mut c = cands;
c.sort();
Some(c.into_iter().next().unwrap())
}
}
}