use mon::{Parser, ParserIter, ascii_alpha, ascii_alphanumeric, r#if, one_of, tag}; use crate::{ Parseable, repo::profile::make_defaults::{Assignment, Interpolation, Key, Literal, Segment}, }; impl<'a> Parseable<'a, &'a str> for Key { type Parser = impl Parser<&'a str, Output = Self>; fn parser() -> Self::Parser { let start = ascii_alpha(); let rest = ascii_alphanumeric() .or(one_of("_".chars())) .repeated() .many(); start .followed_by(rest) .recognize() .map(|output: &str| Key(output.to_string())) } } impl<'a> Parseable<'a, &'a str> for Literal { type Parser = impl Parser<&'a str, Output = Self>; fn parser() -> Self::Parser { r#if(|c: &char| *c != '"') .and_not(Interpolation::parser()) .repeated() .at_least(1) .recognize() .map(|output: &str| Literal(output.to_string())) } } impl<'a> Parseable<'a, &'a str> for Interpolation { type Parser = impl Parser<&'a str, Output = Self>; fn parser() -> Self::Parser { Key::parser() .recognize() .delimited_by(tag("{"), tag("}")) .preceded_by(tag("$")) .map(|output: &str| Interpolation(output.to_string())) } } impl<'a> Parseable<'a, &'a str> for Segment { type Parser = impl Parser<&'a str, Output = Self>; fn parser() -> Self::Parser { Literal::parser() .map(Segment::Literal) .or(Interpolation::parser().map(Segment::Interpolation)) } } impl<'a> Parseable<'a, &'a str> for Assignment { type Parser = impl Parser<&'a str, Output = Self>; fn parser() -> Self::Parser { Key::parser() .followed_by(tag("=")) .and( Segment::parser() .repeated() .many() .delimited_by(tag("\""), tag("\"")), ) .map(|(key, value)| Assignment(key, value)) } } #[cfg(test)] mod test { use mon::input::InputIter; use super::*; #[test] fn test_parse_value() { let it = InputIter::new(r#"KEY="foo ${bar}""#); Assignment::parser().check_finished(it).unwrap(); } }