tantivy_query_grammar/
infallible.rs

1//! nom combinators for infallible operations
2
3use std::convert::Infallible;
4
5use nom::{AsChar, IResult, InputLength, InputTakeAtPosition};
6use serde::Serialize;
7
8pub(crate) type ErrorList = Vec<LenientErrorInternal>;
9pub(crate) type JResult<I, O> = IResult<I, (O, ErrorList), Infallible>;
10
11/// An error, with an end-of-string based offset
12#[derive(Debug)]
13pub(crate) struct LenientErrorInternal {
14    pub pos: usize,
15    pub message: String,
16}
17
18/// A recoverable error and the position it happened at
19#[derive(Debug, PartialEq, Serialize)]
20#[serde(rename_all = "snake_case")]
21pub struct LenientError {
22    pub pos: usize,
23    pub message: String,
24}
25
26impl LenientError {
27    pub(crate) fn from_internal(internal: LenientErrorInternal, str_len: usize) -> LenientError {
28        LenientError {
29            pos: str_len - internal.pos,
30            message: internal.message,
31        }
32    }
33}
34
35fn unwrap_infallible<T>(res: Result<T, nom::Err<Infallible>>) -> T {
36    match res {
37        Ok(val) => val,
38        Err(_) => unreachable!(),
39    }
40}
41
42// when rfcs#1733 get stabilized, this can make things clearer
43// trait InfallibleParser<I, O> = nom::Parser<I, (O, ErrorList), std::convert::Infallible>;
44
45/// A variant of the classical `opt` parser, except it returns an infallible error type.
46///
47/// It's less generic than the original to ease type resolution in the rest of the code.
48pub(crate) fn opt_i<I: Clone, O, F>(mut f: F) -> impl FnMut(I) -> JResult<I, Option<O>>
49where F: nom::Parser<I, O, nom::error::Error<I>> {
50    move |input: I| {
51        let i = input.clone();
52        match f.parse(input) {
53            Ok((i, o)) => Ok((i, (Some(o), Vec::new()))),
54            Err(_) => Ok((i, (None, Vec::new()))),
55        }
56    }
57}
58
59pub(crate) fn opt_i_err<'a, I: Clone + InputLength, O, F>(
60    mut f: F,
61    message: impl ToString + 'a,
62) -> impl FnMut(I) -> JResult<I, Option<O>> + 'a
63where
64    F: nom::Parser<I, O, nom::error::Error<I>> + 'a,
65{
66    move |input: I| {
67        let i = input.clone();
68        match f.parse(input) {
69            Ok((i, o)) => Ok((i, (Some(o), Vec::new()))),
70            Err(_) => {
71                let errs = vec![LenientErrorInternal {
72                    pos: i.input_len(),
73                    message: message.to_string(),
74                }];
75                Ok((i, (None, errs)))
76            }
77        }
78    }
79}
80
81pub(crate) fn space0_infallible<T>(input: T) -> JResult<T, T>
82where
83    T: InputTakeAtPosition + Clone,
84    <T as InputTakeAtPosition>::Item: AsChar + Clone,
85{
86    opt_i(nom::character::complete::multispace0)(input)
87        .map(|(left, (spaces, errors))| (left, (spaces.expect("multispace0 can't fail"), errors)))
88}
89
90pub(crate) fn space1_infallible<T>(input: T) -> JResult<T, Option<T>>
91where
92    T: InputTakeAtPosition + Clone + InputLength,
93    <T as InputTakeAtPosition>::Item: AsChar + Clone,
94{
95    opt_i(nom::character::complete::multispace1)(input).map(|(left, (spaces, mut errors))| {
96        if spaces.is_none() {
97            errors.push(LenientErrorInternal {
98                pos: left.input_len(),
99                message: "missing space".to_string(),
100            })
101        }
102        (left, (spaces, errors))
103    })
104}
105
106pub(crate) fn fallible<I, O, E: nom::error::ParseError<I>, F>(
107    mut f: F,
108) -> impl FnMut(I) -> IResult<I, O, E>
109where F: nom::Parser<I, (O, ErrorList), Infallible> {
110    use nom::Err;
111    move |input: I| match f.parse(input) {
112        Ok((input, (output, _err))) => Ok((input, output)),
113        Err(Err::Incomplete(needed)) => Err(Err::Incomplete(needed)),
114        // old versions don't understand this is uninhabited and need the empty match to help,
115        // newer versions warn because this arm is unreachable (which it is indeed).
116        Err(Err::Error(val)) | Err(Err::Failure(val)) => match val {},
117    }
118}
119
120pub(crate) fn delimited_infallible<I, O1, O2, O3, F, G, H>(
121    mut first: F,
122    mut second: G,
123    mut third: H,
124) -> impl FnMut(I) -> JResult<I, O2>
125where
126    F: nom::Parser<I, (O1, ErrorList), Infallible>,
127    G: nom::Parser<I, (O2, ErrorList), Infallible>,
128    H: nom::Parser<I, (O3, ErrorList), Infallible>,
129{
130    move |input: I| {
131        let (input, (_, mut err)) = first.parse(input)?;
132        let (input, (o2, mut err2)) = second.parse(input)?;
133        err.append(&mut err2);
134        let (input, (_, mut err3)) = third.parse(input)?;
135        err.append(&mut err3);
136        Ok((input, (o2, err)))
137    }
138}
139
140// Parse nothing. Just a lazy way to not implement terminated/preceded and use delimited instead
141pub(crate) fn nothing(i: &str) -> JResult<&str, ()> {
142    Ok((i, ((), Vec::new())))
143}
144
145pub(crate) trait TupleInfallible<I, O> {
146    /// Parses the input and returns a tuple of results of each parser.
147    fn parse(&mut self, input: I) -> JResult<I, O>;
148}
149
150impl<Input, Output, F: nom::Parser<Input, (Output, ErrorList), Infallible>>
151    TupleInfallible<Input, (Output,)> for (F,)
152{
153    fn parse(&mut self, input: Input) -> JResult<Input, (Output,)> {
154        self.0.parse(input).map(|(i, (o, e))| (i, ((o,), e)))
155    }
156}
157
158// these macros are heavily copied from nom, with some minor adaptations for our type
159macro_rules! tuple_trait(
160  ($name1:ident $ty1:ident, $name2: ident $ty2:ident, $($name:ident $ty:ident),*) => (
161    tuple_trait!(__impl $name1 $ty1, $name2 $ty2; $($name $ty),*);
162  );
163  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident, $($name2:ident $ty2:ident),*) => (
164    tuple_trait_impl!($($name $ty),+);
165    tuple_trait!(__impl $($name $ty),+ , $name1 $ty1; $($name2 $ty2),*);
166  );
167  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident) => (
168    tuple_trait_impl!($($name $ty),+);
169    tuple_trait_impl!($($name $ty),+, $name1 $ty1);
170  );
171);
172
173macro_rules! tuple_trait_impl(
174  ($($name:ident $ty: ident),+) => (
175    impl<
176      Input: Clone, $($ty),+ ,
177      $($name: nom::Parser<Input, ($ty, ErrorList), Infallible>),+
178    > TupleInfallible<Input, ( $($ty),+ )> for ( $($name),+ ) {
179
180      fn parse(&mut self, input: Input) -> JResult<Input, ( $($ty),+ )> {
181        let mut error_list = Vec::new();
182        tuple_trait_inner!(0, self, input, (), error_list, $($name)+)
183      }
184    }
185  );
186);
187
188macro_rules! tuple_trait_inner(
189  ($it:tt, $self:expr, $input:expr, (), $error_list:expr, $head:ident $($id:ident)+) => ({
190    let (i, (o, mut err)) = $self.$it.parse($input.clone())?;
191    $error_list.append(&mut err);
192
193    succ!($it, tuple_trait_inner!($self, i, ( o ), $error_list, $($id)+))
194  });
195  ($it:tt, $self:expr, $input:expr, ($($parsed:tt)*), $error_list:expr, $head:ident $($id:ident)+) => ({
196    let (i, (o, mut err)) = $self.$it.parse($input.clone())?;
197    $error_list.append(&mut err);
198
199    succ!($it, tuple_trait_inner!($self, i, ($($parsed)* , o), $error_list, $($id)+))
200  });
201  ($it:tt, $self:expr, $input:expr, ($($parsed:tt)*), $error_list:expr, $head:ident) => ({
202    let (i, (o, mut err)) = $self.$it.parse($input.clone())?;
203    $error_list.append(&mut err);
204
205    Ok((i, (($($parsed)* , o), $error_list)))
206  });
207);
208
209macro_rules! succ (
210  (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
211  (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
212  (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
213  (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
214  (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
215  (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
216  (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
217  (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
218  (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
219  (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
220  (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
221  (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
222  (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
223  (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
224  (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
225  (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
226  (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
227  (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
228  (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
229  (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
230  (20, $submac:ident ! ($($rest:tt)*)) => ($submac!(21, $($rest)*));
231);
232
233tuple_trait!(FnA A, FnB B, FnC C, FnD D, FnE E, FnF F, FnG G, FnH H, FnI I, FnJ J, FnK K, FnL L,
234  FnM M, FnN N, FnO O, FnP P, FnQ Q, FnR R, FnS S, FnT T, FnU U);
235
236// Special case: implement `TupleInfallible` for `()`, the unit type.
237// This can come up in macros which accept a variable number of arguments.
238// Literally, `()` is an empty tuple, so it should simply parse nothing.
239impl<I> TupleInfallible<I, ()> for () {
240    fn parse(&mut self, input: I) -> JResult<I, ()> {
241        Ok((input, ((), Vec::new())))
242    }
243}
244
245pub(crate) fn tuple_infallible<I, O, List: TupleInfallible<I, O>>(
246    mut l: List,
247) -> impl FnMut(I) -> JResult<I, O> {
248    move |i: I| l.parse(i)
249}
250
251pub(crate) fn separated_list_infallible<I, O, O2, F, G>(
252    mut sep: G,
253    mut f: F,
254) -> impl FnMut(I) -> JResult<I, Vec<O>>
255where
256    I: Clone + InputLength,
257    F: nom::Parser<I, (O, ErrorList), Infallible>,
258    G: nom::Parser<I, (O2, ErrorList), Infallible>,
259{
260    move |i: I| {
261        let mut res: Vec<O> = Vec::new();
262        let mut errors: ErrorList = Vec::new();
263
264        let (mut i, (o, mut err)) = unwrap_infallible(f.parse(i.clone()));
265        errors.append(&mut err);
266        res.push(o);
267
268        loop {
269            let (i_sep_parsed, (_, mut err_sep)) = unwrap_infallible(sep.parse(i.clone()));
270            let len_before = i_sep_parsed.input_len();
271
272            let (i_elem_parsed, (o, mut err_elem)) =
273                unwrap_infallible(f.parse(i_sep_parsed.clone()));
274
275            // infinite loop check: the parser must always consume
276            // if we consumed nothing here, don't produce an element.
277            if i_elem_parsed.input_len() == len_before {
278                return Ok((i, (res, errors)));
279            }
280            res.push(o);
281            errors.append(&mut err_sep);
282            errors.append(&mut err_elem);
283            i = i_elem_parsed;
284        }
285    }
286}
287
288pub(crate) trait Alt<I, O> {
289    /// Tests each parser in the tuple and returns the result of the first one that succeeds
290    fn choice(&mut self, input: I) -> Option<JResult<I, O>>;
291}
292
293macro_rules! alt_trait(
294  ($first_cond:ident $first:ident, $($id_cond:ident $id: ident),+) => (
295    alt_trait!(__impl $first_cond $first; $($id_cond $id),+);
296  );
297  (__impl $($current_cond:ident $current:ident),*; $head_cond:ident $head:ident, $($id_cond:ident $id:ident),+) => (
298    alt_trait_impl!($($current_cond $current),*);
299
300    alt_trait!(__impl $($current_cond $current,)* $head_cond $head; $($id_cond $id),+);
301  );
302  (__impl $($current_cond:ident $current:ident),*; $head_cond:ident $head:ident) => (
303    alt_trait_impl!($($current_cond $current),*);
304    alt_trait_impl!($($current_cond $current,)* $head_cond $head);
305  );
306);
307
308macro_rules! alt_trait_impl(
309  ($($id_cond:ident $id:ident),+) => (
310    impl<
311      Input: Clone, Output,
312      $(
313          // () are to make things easier on me, but I'm not entirely sure whether we can do better
314          // with rule E0207
315          $id_cond: nom::Parser<Input, (), ()>,
316          $id: nom::Parser<Input, (Output, ErrorList), Infallible>
317      ),+
318    > Alt<Input, Output> for ( $(($id_cond, $id),)+ ) {
319
320      fn choice(&mut self, input: Input) -> Option<JResult<Input, Output>> {
321        match self.0.0.parse(input.clone()) {
322          Err(_) => alt_trait_inner!(1, self, input, $($id_cond $id),+),
323          Ok((input_left, _)) => Some(self.0.1.parse(input_left)),
324        }
325      }
326    }
327  );
328);
329
330macro_rules! alt_trait_inner(
331  ($it:tt, $self:expr, $input:expr, $head_cond:ident $head:ident, $($id_cond:ident $id:ident),+) => (
332    match $self.$it.0.parse($input.clone()) {
333      Err(_) => succ!($it, alt_trait_inner!($self, $input, $($id_cond $id),+)),
334      Ok((input_left, _)) => Some($self.$it.1.parse(input_left)),
335    }
336  );
337  ($it:tt, $self:expr, $input:expr, $head_cond:ident $head:ident) => (
338    None
339  );
340);
341
342alt_trait!(A1 A, B1 B, C1 C, D1 D, E1 E, F1 F, G1 G, H1 H, I1 I, J1 J, K1 K,
343           L1 L, M1 M, N1 N, O1 O, P1 P, Q1 Q, R1 R, S1 S, T1 T, U1 U);
344
345/// An alt() like combinator. For each branch, it first tries a fallible parser, which commits to
346/// this branch, or tells to check next branch, and the execute the infallible parser which follow.
347///
348/// In case no branch match, the default (fallible) parser is executed.
349pub(crate) fn alt_infallible<I: Clone, O, F, List: Alt<I, O>>(
350    mut l: List,
351    mut default: F,
352) -> impl FnMut(I) -> JResult<I, O>
353where
354    F: nom::Parser<I, (O, ErrorList), Infallible>,
355{
356    move |i: I| l.choice(i.clone()).unwrap_or_else(|| default.parse(i))
357}
358
359#[cfg(test)]
360mod tests {
361    use super::*;
362
363    #[test]
364    fn test_lenient_error_serialization() {
365        let error = LenientError {
366            pos: 42,
367            message: "test error message".to_string(),
368        };
369
370        assert_eq!(
371            serde_json::to_string(&error).unwrap(),
372            "{\"pos\":42,\"message\":\"test error message\"}"
373        );
374    }
375}