pub const TEMPLATE_MEM: &str = "\u{1}m\u{2}";
#[must_use]
pub fn template_mem_at(offset: i64) -> String {
format!("\u{1}m{offset}\u{2}")
}
#[must_use]
pub fn template_name(name: &str) -> String {
format!("\u{1}n{name}\u{2}")
}
#[must_use]
pub fn template_reg(at: usize, width: char) -> String {
format!("\u{1}r{at}{width}\u{2}")
}
#[must_use]
pub fn template_arm(arm: usize) -> String {
format!("\u{1}l{arm}\u{2}")
}
#[must_use]
pub fn template_arms(text: &str, arm: impl Fn(usize) -> Option<String>) -> Option<String> {
let mut out = String::with_capacity(text.len());
let mut rest = text;
while let Some(at) = rest.find("\u{1}l") {
out.push_str(&rest[..at]);
let hole = &rest[at + 2..];
let end = hole.find('\u{2}').unwrap_or(hole.len());
out.push_str(&arm(hole[..end].parse().ok()?)?);
rest = hole.get(end + 1..).unwrap_or("");
}
out.push_str(rest);
Some(out)
}
#[must_use]
pub fn template_jumps(text: &str) -> bool {
text.contains("\u{1}l")
}
#[must_use]
pub fn template_filled(
text: &str,
mem: &str,
name: impl Fn(&str) -> String,
reg: impl Fn(usize, char) -> String,
) -> String {
let mut out = String::with_capacity(text.len());
let mut rest = text;
while let Some(at) = rest.find('\u{1}') {
out.push_str(&rest[..at]);
let hole = &rest[at + 1..];
let end = hole.find('\u{2}').unwrap_or(hole.len());
match hole[..end].split_at_checked(1) {
Some(("m", offset)) => match offset.parse::<i64>() {
Ok(offset) if mem.starts_with('(') => out.push_str(&format!("{offset}{mem}")),
Ok(offset) => out.push_str(&format!("{offset}+{mem}")),
Err(_) => out.push_str(mem),
},
Some(("n", named)) => out.push_str(&name(named)),
Some(("r", held)) => {
let (at, width) = held.split_at(held.len().saturating_sub(1));
if let (Ok(at), Some(width)) = (at.parse(), width.chars().next()) {
out.push_str(®(at, width));
}
}
_ => {}
}
rest = hole.get(end + 1..).unwrap_or("");
}
out.push_str(rest);
out
}