pub(crate) fn collapse_role_name(name: &str) -> Option<String> {
let base = role_base(name)?;
let idx = role_index(name)?;
let place = nibli_lexicon::relation_places(base)
.and_then(|p| p.get(idx - 1).copied())
.map(str::to_owned)
.unwrap_or_else(|| format!("x{idx}"));
Some(format!("{base}.{place}"))
}
pub(crate) fn role_base(name: &str) -> Option<&str> {
let u = name.rfind('_')?;
let suffix = &name[u + 1..];
let rest = suffix.strip_prefix('x')?;
if !rest.is_empty() && rest.bytes().all(|b| b.is_ascii_digit()) {
Some(&name[..u])
} else {
None
}
}
pub(crate) fn role_index(name: &str) -> Option<usize> {
let u = name.rfind('_')?;
let rest = name[u + 1..].strip_prefix('x')?;
rest.parse::<usize>().ok()
}
pub(crate) fn is_event_skolem(s: &str) -> bool {
s.strip_prefix("sk_")
.is_some_and(|r| !r.is_empty() && r.bytes().all(|b| b.is_ascii_digit()))
}
pub(crate) fn is_event_skolem_arg(s: &str) -> bool {
s.strip_prefix("sk_")
.and_then(|r| r.bytes().next())
.is_some_and(|b| b.is_ascii_digit())
}
pub(crate) fn humanize_skolem(s: &str) -> String {
if let Some(rest) = s.strip_prefix("sk_") {
if !rest.is_empty() && rest.bytes().all(|b| b.is_ascii_digit()) {
return format!("#{rest}");
}
if let Some(paren) = rest.find('(') {
let num = &rest[..paren];
if !num.is_empty() && num.bytes().all(|b| b.is_ascii_digit()) {
return format!("#{num}{}", &rest[paren..]);
}
}
}
if let Some(name) = crate::overlay::active().and_then(|o| o.name(s)) {
return name.to_string();
}
s.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn role_detection() {
assert_eq!(collapse_role_name("dog_x1").as_deref(), Some("dog.dog"));
assert_eq!(role_base("dog_x2"), Some("dog"));
assert_eq!(role_index("dog_x2"), Some(2));
assert_eq!(collapse_role_name("dog"), None);
assert_eq!(collapse_role_name("se_katna"), None); assert_eq!(role_base("animal"), None);
}
#[test]
fn role_names_use_argument_labels() {
assert_eq!(
collapse_role_name("goes_x2").as_deref(),
Some("goes.destination")
);
assert_eq!(collapse_role_name("goes_x1").as_deref(), Some("goes.goer"));
assert_eq!(collapse_role_name("dog_x1").as_deref(), Some("dog.dog"));
assert_eq!(
collapse_role_name("mystery_x1").as_deref(),
Some("mystery.x1")
);
}
#[test]
fn event_skolem_detection() {
assert!(is_event_skolem("sk_0"));
assert!(is_event_skolem("sk_12"));
assert!(!is_event_skolem("sk_1(adam)")); assert!(!is_event_skolem("adam"));
assert!(!is_event_skolem("sk_"));
}
#[test]
fn skolem_humanization() {
assert_eq!(humanize_skolem("sk_2"), "#2");
assert_eq!(humanize_skolem("sk_1(adam)"), "#1(adam)");
assert_eq!(humanize_skolem("adam"), "adam");
}
#[test]
fn overlay_name_override_then_restores() {
use crate::corpus_overlay::DRUG_INTERACTIONS_OVERLAY;
use crate::overlay::with_overlay;
assert_eq!(humanize_skolem("varfarin"), "varfarin");
with_overlay(Some(&DRUG_INTERACTIONS_OVERLAY), || {
assert_eq!(humanize_skolem("varfarin"), "warfarin");
assert_eq!(humanize_skolem("siptucin"), "CYP2C9");
assert_eq!(humanize_skolem("zo'e"), "zo'e");
assert_eq!(humanize_skolem("sk_2"), "#2");
});
assert_eq!(humanize_skolem("varfarin"), "varfarin");
}
}