daisychain/cookbook/
ch_3_binding_vars.rs

1use crate::prelude::*;
2
3#[derive(PartialEq, Debug)]
4struct QuotedText {
5    quote: char,
6    text: String,
7}
8
9impl QuotedText {
10    fn new(quote: char, text: String) -> Self {
11        Self { quote, text }
12    }
13}
14
15/// eg "'Hello World!', said Ferris"
16/// lexing and parsing together
17///
18fn parse_quoted_text(inp: &str) -> Result<(&str, QuotedText), ParsingError> {
19    // step 1: find out which quote char is used
20    let (c, quote) = Cursor::from(inp)
21        .chars_in(1..=1, &['"', '\''])
22        .parse_selection()
23        .validate()?;
24
25    // step 2: use the quote character to extract the text between quotes
26    let (c, text) = Cursor::from(c)
27        .chars_not_in(0.., &[quote])
28        .parse_selection()
29        .chars_in(1..=1, &[quote])
30        .validate()?;
31    Ok((c, QuotedText { quote, text }))
32}
33
34/// alternative implementation using "bind"
35///
36fn parse_quoted_text_v2(inp: &str) -> Result<(&str, QuotedText), ParsingError> {
37    let mut quote = char::default();
38    let (c, text) = Cursor::from(inp)
39        .chars_in(1..=1, &['"', '\''])
40        .parse_selection()
41        .bind(&mut quote) // store the quote found, to use below in the matching method-chain
42        .chars_not_in(0.., &[quote])
43        .parse_selection()
44        .chars_in(1..=1, &[quote])
45        .validate()?;
46    Ok((c, QuotedText { quote, text }))
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52    use test_log::test;
53
54    #[test]
55    fn test_parse_quoted_text() -> Result<(), ParsingError> {
56        let s = "'Hello World!', said Ferris";
57        let (c, qt) = parse_quoted_text(s)?;
58        assert_eq!(qt, QuotedText::new('\'', "Hello World!".to_string()));
59        assert_eq!(c, ", said Ferris");
60
61        let (c, qt) = parse_quoted_text("\"Hi\", he said")?;
62        assert_eq!(qt, QuotedText::new('"', "Hi".to_string()));
63        assert_eq!(c, ", he said");
64
65        let (c, qt) = parse_quoted_text_v2("\"Hi\", he said")?;
66        assert_eq!(qt, QuotedText::new('"', "Hi".to_string()));
67        assert_eq!(c, ", he said");
68
69        let res = parse_quoted_text("'Hi, ");
70        assert!(res.is_err());
71        Ok(())
72    }
73}