nessie_parse/
primitives.rs

1use crate::parser::{ParseResult, Parser};
2use crate::state::State;
3
4use functionality::prelude::*;
5
6impl<'a, T: 'a, F: 'a, E: 'a> Parser<'a, T, E, F> {
7    pub fn of_bool(value: bool) -> Parser<'a, T, E, F>
8    where
9        T: Default + Clone,
10        F: Default + Clone,
11    {
12        if value {
13            Parser::ret(T::default())
14        } else {
15            Parser::fail(F::default())
16        }
17    }
18}
19
20#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
21pub struct EofFailure;
22
23impl<'a, E: 'a> Parser<'a, char, E, EofFailure> {
24    pub fn char() -> Parser<'a, char, E, EofFailure> {
25        Parser::from_fn(|state| {
26            if state.rest().is_empty() {
27                ParseResult::Fail(EofFailure, state.pos)
28            } else {
29                let ch = state.rest().chars().next().unwrap();
30                let new_pos = if ch == '\n' {
31                    state.pos.down()
32                } else {
33                    state.pos.right()
34                };
35                ParseResult::Ok(ch, new_pos)
36            }
37        })
38    }
39}
40
41impl<'a, F: Clone + Default + 'a, E: 'a> Parser<'a, char, E, F> {
42    pub fn char_eq(ch: char) -> Parser<'a, char, E, F> {
43        Parser::char()
44            .map_fail(|_| F::default())
45            .filter(move |&c| c == ch)
46    }
47}
48
49#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
50pub struct NotWhitespace;
51
52impl<'a, E: 'a> Parser<'a, char, E, NotWhitespace> {
53    pub fn whitespace() -> Parser<'a, char, E, NotWhitespace> {
54        Parser::char()
55            .map_fail(|_| NotWhitespace)
56            .filter(|c| c.is_whitespace())
57    }
58}
59
60impl<'a, F: 'a, E: 'a> Parser<'a, (), E, F> {
61    pub fn skip_whitespace() -> Parser<'a, (), E, F> {
62        Parser::whitespace().repeat_0().map(|_| ())
63    }
64}
65
66#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
67pub struct NotALetter;
68
69impl<'a, E: 'a> Parser<'a, char, E, NotALetter> {
70    pub fn letter() -> Parser<'a, char, E, NotALetter> {
71        Parser::char()
72            .map_fail(|_| NotALetter)
73            .filter(|c| c.is_ascii_alphabetic())
74    }
75}
76
77#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
78pub struct NotADigit;
79
80impl<'a, E: 'a> Parser<'a, char, E, NotADigit> {
81    pub fn digit() -> Parser<'a, char, E, NotADigit> {
82        Parser::char()
83            .map_fail(|_| NotADigit)
84            .filter(|c| c.is_ascii_digit())
85    }
86}
87
88#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
89pub struct NotFound;
90
91impl<'a, E: 'a> Parser<'a, char, E, NotFound> {
92    pub fn eof() -> Parser<'a, (), E, NotFound> {
93        Parser::state()
94            .map(|state| state.rest().is_empty())
95            .and_then(Parser::of_bool)
96    }
97
98    pub fn expect_string(expected: &'static str) -> Parser<'a, (), E, NotFound> {
99        Parser::state()
100            .map(move |state: State| state.rest().starts_with(expected))
101            .and_then(Parser::of_bool)
102            .and_then(move |()| {
103                Parser::from_fn(move |state| {
104                    // TODO: This could be so much cleaner. Also, need to handle newlines?
105                    assert!(expected.chars().all(|c| c != '\n'));
106                    let mut new_pos = state.pos;
107                    for _ in 0..expected.len() {
108                        new_pos = new_pos.right();
109                    }
110                    ParseResult::Ok((), new_pos)
111                })
112            })
113    }
114}
115
116impl<'a, T, F, E> Parser<'a, T, E, F> {
117    /// Repeats this parser zero or one times.
118    pub fn maybe<G>(self) -> Parser<'a, Option<T>, E, G>
119    where
120        T: 'a,
121        E: 'a,
122        F: 'a,
123    {
124        let name = format!("maybe({})", &self.name);
125        self.map(Some)
126            .or(Parser::<_, _, ()>::ret_with(|| None))
127            .map_fail(|()| panic!("maybe should not fail"))
128            .with_name(name)
129    }
130
131    /// Repeats this parser zero or more times.
132    pub fn repeat_0<G>(self) -> Parser<'a, Vec<T>, E, G>
133    where
134        T: Clone + 'a,
135        E: 'a,
136        F: 'a,
137        G: 'a,
138    {
139        let name = format!("repeat_0({})", &self.name);
140        self.clone()
141            .and_then(move |x| {
142                self.clone()
143                    .repeat_0()
144                    .map(move |xs| vec![x.clone()].mutate(|v| v.extend(xs)))
145            })
146            .or(Parser::<_, _, G>::ret_with(Vec::new))
147            .map_fail(|(_, g)| g)
148            .with_name(name)
149    }
150
151    /// Repeats this parser one or more times.
152    pub fn repeat_1(self) -> Parser<'a, Vec<T>, E, F>
153    where
154        T: Clone + 'a,
155        E: 'a,
156        F: 'a,
157    {
158        let name = format!("repeat_1({})", &self.name);
159        self.clone()
160            .and_then(move |x| {
161                self.clone()
162                    .repeat_0()
163                    .map(move |xs| vec![x.clone()].mutate(|v| v.extend(xs)))
164            })
165            .with_name(name)
166    }
167}
168
169impl<'a, T, F, E> Parser<'a, T, E, F> {
170    #[allow(clippy::should_implement_trait)]
171    pub fn not<G>(self) -> Parser<'a, (), E, G>
172    where
173        T: 'a,
174        E: 'a,
175        F: 'a,
176        G: Default + 'a,
177    {
178        #[rustfmt::skip]
179        #[derive(Debug, Clone)]
180        enum ShouldFail { Yes, No }
181
182        let name = format!("not({})", &self.name);
183        self.map_fail(|_| ShouldFail::No)
184            .and_then(|_| Parser::fail(ShouldFail::Yes))
185            .and_then_fail(|f| match f {
186                ShouldFail::Yes => Parser::fail_with(|| G::default()),
187                ShouldFail::No => Parser::ret(()),
188            })
189            .with_name(name)
190    }
191}