Skip to main content

gobble/
strings.rs

1use crate::iter::LCChars;
2use crate::ptrait::*;
3
4pub struct String2P<A: Parser, B: Parser> {
5    a: A,
6    b: B,
7}
8
9impl<A, B> Parser for String2P<A, B>
10where
11    A: Parser,
12    B: Parser,
13    A::Out: Into<String>,
14    B::Out: AsRef<str>,
15{
16    type Out = String;
17    fn parse<'a>(&self, it: &LCChars<'a>) -> ParseRes<'a, String> {
18        let (it2, av, c1) = self.a.parse(it)?;
19        let (itres, bv, c2) = self.b.parse(&it2).map_err(|e| e.join_op(c1))?;
20        let mut s: String = av.into();
21        s.push_str(bv.as_ref());
22        Ok((itres, s, c2))
23    }
24}
25
26pub fn strings_plus_until<A: Parser<Out = String>, B: Parser>(
27    a: A,
28    b: B,
29) -> StringsPlusUntil<A, B> {
30    StringsPlusUntil { a, b }
31}
32
33pub struct StringsPlusUntil<A: Parser<Out = String>, B> {
34    a: A,
35    b: B,
36}
37
38pub fn do_strings_until<'a, A: Parser<Out = String>, B: Parser>(
39    it: &LCChars<'a>,
40    a: &A,
41    b: &B,
42    min: usize,
43) -> ParseRes<'a, (String, B::Out)> {
44    let mut res = String::new();
45    let mut it = it.clone();
46    let mut done = 0;
47    loop {
48        let b_err = if done >= min {
49            match b.parse(&it) {
50                Ok((nit, v, e)) => return Ok((nit, (res, v), e)),
51                Err(e) => Some(e),
52            }
53        } else {
54            None
55        };
56        match a.parse(&it) {
57            Ok((nit, v, _e)) => {
58                res.push_str(&v);
59                it = nit;
60                done += 1;
61            }
62            Err(e) => {
63                if let Some(berr) = b_err {
64                    return Err(e.join(berr));
65                }
66            }
67        }
68    }
69}
70
71impl<A: Parser<Out = String>, B: Parser> Parser for StringsPlusUntil<A, B> {
72    type Out = (String, B::Out);
73    fn parse<'a>(&self, it: &LCChars<'a>) -> ParseRes<'a, Self::Out> {
74        do_strings_until(it, &self.a, &self.b, 1)
75    }
76}
77
78pub fn string_2_parts<A, B>(a: A, b: B) -> String2P<A, B>
79where
80    A: Parser,
81    B: Parser,
82    A::Out: Into<String>,
83    B::Out: AsRef<str>,
84{
85    String2P { a, b }
86}
87
88///A parser that ignores the result of another parser and returns the string between the
89///previous
90pub fn string<A: Parser>(a: A) -> AsString<A> {
91    AsString { a }
92}
93
94pub struct AsString<A: Parser> {
95    a: A,
96}
97
98impl<A: Parser> Parser for AsString<A> {
99    type Out = String;
100    fn parse<'a>(&self, it: &LCChars<'a>) -> ParseRes<'a, String> {
101        self.a
102            .parse(it)
103            .map(|(nit, _, ct)| match (it.index(), nit.index()) {
104                (Some(s), Some(f)) => (nit, it.as_str()[0..(f - s)].to_string(), ct),
105                _ => (nit, it.as_str().to_string(), ct),
106            })
107    }
108}