#[cfg(test)]
mod tests;
use fancy_regex_macro::regex;
use crate::{error::Error, REGEX_MATCH_FAIL};
use super::Classes;
fn replace_angle_brackets(pattern: &str) -> String {
regex!(r"(?<!\(\?)(?<!\(\?P)(?<!\\k)<([^>]*)>")
.replace_all(pattern, r"⟨$1⟩")
.to_string()
}
pub(crate) fn replace_classes(
pattern: &str,
classes: &Classes,
line: usize,
) -> Result<String, Error> {
let pattern = replace_angle_brackets(pattern);
let mut output = String::new();
let mut name_build: Option<String> = None;
for ch in pattern.chars() {
match ch {
'⟨' => {
if name_build.is_some() {
return parse_error!(line, UnexpectedClassNameOpen);
}
name_build = Some(String::new());
}
'⟩' => {
let Some(name) = name_build else {
return parse_error!(line, UnexpectedClassNameClose);
};
if !regex!(r"^\w+$").is_match(&name).expect(REGEX_MATCH_FAIL) {
return parse_error!(line, InvalidClassName, name);
}
let Some((value, _line)) = classes.get(&name) else {
return parse_error!(line, ClassNotFound, name);
};
output.push_str(&replace_classes(value, classes, line)?);
name_build = None;
}
_ => {
match &mut name_build {
Some(name) => name.push(ch),
None => output.push(ch),
}
}
}
}
if name_build.is_some() {
return parse_error!(line, UnexpectedPatternEnd);
}
Ok(output)
}