use std::sync::LazyLock;
use regex::bytes::Regex;
static STR_RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r#"(?-u)"[^"]*"|'[^']*'|`[^`]*`"#).unwrap());
static NUM_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?-u)\b\d+\b").unwrap());
static IDENT_RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"(?-u)[A-Za-z_][A-Za-z0-9_\-]{3,}").unwrap());
static WS_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?-u)\s+").unwrap());
static DEF_RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(
r"(?-u)\b(?:fn|struct|enum|trait|class|interface|type|def|func|impl|const|static|mod|module|package|protocol)\s+([A-Za-z_][A-Za-z0-9_]{2,})",
)
.unwrap()
});
static REF_RE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"(?-u)[A-Za-z_][A-Za-z0-9_]{3,}").unwrap());
pub fn symbol_definitions(line: &[u8]) -> Vec<Vec<u8>> {
DEF_RE.captures_iter(line).map(|c| c[1].to_vec()).collect()
}
pub fn symbol_references(line: &[u8]) -> Vec<Vec<u8>> {
REF_RE
.find_iter(line)
.map(|m| m.as_bytes().to_vec())
.collect()
}
pub fn normalize_line(line: &[u8]) -> Vec<u8> {
let s = STR_RE.replace_all(line, b"\"S\"".as_slice());
let s = NUM_RE.replace_all(&s, b"N".as_slice());
let s = IDENT_RE.replace_all(&s, b"I".as_slice());
let s = WS_RE.replace_all(&s, b" ".as_slice());
trim_ascii(&s).to_vec()
}
fn trim_ascii(s: &[u8]) -> &[u8] {
let start = s
.iter()
.position(|b| !b.is_ascii_whitespace())
.unwrap_or(s.len());
let end = s
.iter()
.rposition(|b| !b.is_ascii_whitespace())
.map_or(start, |e| e + 1);
&s[start..end]
}