use std::error::Error;
use super::ast::{ReplaceItem, Replacement};
pub fn parse(text: &str) -> Result<Replacement, Box<dyn Error>> {
let mut v = Vec::new();
let mut i = 0;
while i < text.len() {
let (p, n) = parse_item(text, i)?;
v.push(p);
i = n;
}
Ok(Replacement {replacements: v})
}
fn parse_item(text: &str, start: usize) -> Result<(ReplaceItem, usize), Box<dyn Error>> {
let mut chars = text.chars().enumerate().skip(start);
if chars.next().ok_or("Out of characters")?.1 == '\\' {
let mut last = 0;
while let Some((i, c)) = chars.next() {
if !c.is_digit(10) {
break;
} else {
last = i;
}
}
if last != 0 {
return Ok((
ReplaceItem::BackRef(text[start + 1..last+1].parse::<usize>()?),
last + 1,
));
}
}
while let Some((i, c)) = chars.next() {
if c == '\\' {
return Ok((ReplaceItem::String(text[start..i].to_string()), i));
}
}
Ok((
ReplaceItem::String(text[start..].to_string()),
text.len() + 1,
))
}
#[test]
fn parsing_replacement() -> Result<(), Box<dyn Error>>{
let parsed = parse("bob\\\\\\13dole")?;
if let ReplaceItem::String(s) = parsed.replacements.get(0).ok_or("sad")? {
assert_eq!(s, "bob");
} else {
panic!("Expected a string, but didn't get it");
}
if let ReplaceItem::String(s) = parsed.replacements.get(1).ok_or("sad")? {
assert_eq!(s, "\\\\");
} else {
panic!("Expected a string, but didn't get it");
}
if let ReplaceItem::BackRef(x) = parsed.replacements.get(2).ok_or("sad")? {
assert_eq!(*x, 13);
} else {
panic!("Expected a string, but didn't get it");
}
if let ReplaceItem::String(s) = parsed.replacements.get(3).ok_or("sad")? {
assert_eq!(s, "dole");
} else {
panic!("Expected a string, but didn't get it");
}
assert_eq!(parsed.replacements.len(), 4);
Ok(())
}