#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FunctionConstant {
pub index: u32,
pub name: String,
pub type_name: String,
}
pub fn parse_function_constants(ll: &str) -> Vec<FunctionConstant> {
let mut out: Vec<FunctionConstant> = Vec::new();
for line in ll.lines() {
let t = line.trim_start();
if !t.starts_with('@') || !t.contains(".MTL_FC_INIT_") {
continue;
}
let Some(eq) = t.find(" = ") else {
continue;
};
let Some((base, marker)) = t[1..eq].trim().split_once(".MTL_FC_INIT_") else {
continue;
};
let digits: String = marker.chars().take_while(|c| c.is_ascii_digit()).collect();
let Ok(index) = digits.parse::<u32>() else {
continue;
};
if out.iter().any(|f| f.index == index) {
continue;
}
out.push(FunctionConstant {
index,
name: base.to_string(),
type_name: fc_global_decl_type(&t[eq + 3..]).unwrap_or_default(),
});
}
out.sort_by_key(|f| f.index);
out
}
fn fc_global_decl_type(decl: &str) -> Option<String> {
let after = decl
.split(" constant ")
.nth(1)
.or_else(|| decl.split(" global ").nth(1))?;
let s = after.trim_start();
if let Some(rest) = s.strip_prefix('<') {
let end = rest.find('>')?;
Some(format!("<{}>", &rest[..end]))
} else {
s.split_whitespace().next().map(str::to_string)
}
}