use peginator::PegParser;
use super::grammar::{CharsOrGroup, Group, Rle as RleGrammar, RleChunk, Section};
use super::{Rle, RleSyntaxError, RleSyntaxErrorKind};
pub struct Parser {}
impl Parser {
pub fn parse(input: &str, drop_spaces: bool) -> Result<String, RleSyntaxError> {
let mut retv = String::new();
match RleGrammar::parse(input) {
Ok(rle) => {
for section in rle.sections {
retv.push_str(&Self::process_section(§ion));
}
}
Err(e) => {
return Err(RleSyntaxError(RleSyntaxErrorKind::DecodingFailure {
position: e.position,
input: input.into(),
}));
}
}
Ok(retv
.chars()
.map(|chr| if chr == Rle::EOL { '\n' } else { chr })
.filter(|chr| {
if drop_spaces {
!chr.is_ascii_whitespace()
} else {
true
}
})
.collect())
}
fn process_section(section: &Section) -> String {
match section {
Section::Chars(chars) => chars.clone(),
Section::Group(group) => Self::process_group(group),
Section::RleChunk(rle_chunk) => Self::process_rle_chunk(rle_chunk),
}
}
fn process_group(group: &Group) -> String {
let mut group_str = String::new();
for group_section in group {
group_str.push_str(&Self::process_section(group_section));
}
group_str
}
fn process_rle_chunk(rle_chunk: &RleChunk) -> String {
let Ok(count) = rle_chunk.count.parse::<usize>() else {
unreachable!(
"internal bug, failed to convert already parsed RLE count sequence {}!",
rle_chunk.count
)
};
match &rle_chunk.data {
CharsOrGroup::Chars(chars) => {
let mut first = chars[..1].to_string().repeat(count);
first.push_str(&chars[1..]);
first.clone()
}
CharsOrGroup::Group(group) => Self::process_group(group).repeat(count),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_decodes_rle_encoded_string() -> Result<(), RleSyntaxError> {
for (input, output) in [
("3r4U", "rrrUUUU"),
("3rabcd4U", "rrrabcdUUUU"),
("2(3(dr)R)", "drdrdrRdrdrdrR"),
("4a4b2cd3e", "aaaabbbbccdeee"),
("aa2(bb)cc2(dd2(ee)ff)", "aabbbbccddeeeeffddeeeeff"),
("2a4b2c2d2e|2e2f2d4e2f", "aabbbbccddee\neeffddeeeeff"),
("2a4b2c2d2e5 2e2f2d4e2f", "aabbbbccddee eeffddeeeeff"),
("2abc3def3(adfdf)2abc3def", "aabcdddefadfdfadfdfadfdfaabcdddef"),
("2abc3def3(2a3bc)2abc3def", "aabcdddefaabbbcaabbbcaabbbcaabcdddef"),
(
"2abc3def2(fdsfs2(dfgh)gtr)2abc3def",
"aabcdddeffdsfsdfghdfghgtrfdsfsdfghdfghgtraabcdddef",
),
(
"2abc3def2(2a2bc2(2a3b)2d)2abc3def",
"aabcdddefaabbcaabbbaabbbddaabbcaabbbaabbbddaabcdddef",
),
("2(abcd)efgh", "abcdabcdefgh"),
("2(3abcd)efgh", "aaabcdaaabcdefgh"),
("2(abcd)3efgh", "abcdabcdeeefgh"),
("(abcd)3efgh", "abcdeeefgh"),
("(ab3cd)efgh", "abcccdefgh"),
("(ab2(3c)d)efgh", "abccccccdefgh"),
("efgh(ab3cd)", "efghabcccd"),
] {
assert_eq!(Parser::parse(input, false)?, output);
}
Ok(())
}
#[test]
fn it_preserves_new_lines() -> Result<(), RleSyntaxError> {
for (input, output) in [
("\n\n\n", "\n\n\n"),
("\n|\n", "\n\n\n"),
("|||", "\n\n\n"),
("\n 3r 4U\n", "\n rrr UUUU\n"),
(
"3-#-#-#-#10-|2-#7-#9-|-#-@5-#10-",
"---#-#-#-#----------\n--#-------#---------\n-#-@-----#----------",
),
] {
assert_eq!(Parser::parse(input, false)?, output);
}
Ok(())
}
#[test]
fn it_refuses_to_decode_only_digits() {
assert!(Parser::parse("12345678", false).is_err());
assert!(Parser::parse(" 1 2 3 \t 45 \n \r678", false).is_err());
}
}