use pest::iterators::{Pair, Pairs};
use super::{Moo, TeaPair, grammar::Rule};
pub fn proc_str(pair: TeaPair) -> Moo {
assert_eq!(pair.as_rule(), Rule::word);
if should_proc_str(&pair.clone().into_inner()) {
let mut str = String::with_capacity(pair.as_str().len());
for pair in pair.into_inner() {
match pair.as_rule() {
Rule::esc => str.push(handle_esc_code(pair)),
Rule::char => str.push_str(pair.as_str()),
other => panic!("Unexpected rule in word: {other:?}"),
}
}
str.into()
} else {
pair.as_str().into()
}
}
fn should_proc_str(pairs: &Pairs<Rule>) -> bool {
for pair in pairs.clone() {
if pair.as_rule() == Rule::esc {
return true;
}
}
false
}
fn handle_esc_code(pair: Pair<Rule>) -> char {
assert_eq!(pair.as_rule(), Rule::esc);
let inner = pair
.into_inner()
.next()
.expect("escape code should contain pairs!");
match inner.as_rule() {
Rule::esc_unicode => unicode_escape(inner.as_str()),
Rule::esc_ascii => ascii_escape(inner.as_str()),
Rule::esc_tc => inner
.as_str()
.chars()
.next()
.expect("escape code should not be empty!"),
other => panic!("Unexpected rule in esc: {other:?}"),
}
}
fn ascii_escape(str: &str) -> char {
match str {
"t" => '\t',
"n" => '\n',
other => panic!("Unexpected ascii esc: \\{other}"),
}
}
fn unicode_escape(str: &str) -> char {
let hex = &str[2..str.len() - 1];
let num = u32::from_str_radix(hex, 16).expect("Unicode hex should be valid!");
char::from_u32(num).unwrap_or_else(|| panic!("Invalid unicode hex: {hex}"))
}