parser_fuck/combinators/
or.rs

1use crate::*;
2use std::marker::PhantomData;
3
4/// Pass when any subparser passes
5#[derive(Debug, PartialEq, Eq, Clone)]
6pub struct Or<A, B, I = ()> {
7    a: A,
8    b: B,
9    _i: PhantomData<I>,
10}
11impl<I: TimeTravel, A, B> Or<A, B, I>
12where
13    A: Parser<I>,
14    B: Parser<I, Output = A::Output>,
15{
16    #[inline]
17    pub fn new(a: A, b: B) -> Self {
18        Self {
19            a,
20            b,
21            _i: PhantomData,
22        }
23    }
24}
25impl<I: TimeTravel, A, B> Parser<I> for Or<A, B, I>
26where
27    A: Parser<I>,
28    B: Parser<I, Output = A::Output>,
29{
30    type Output = A::Output;
31
32    fn parse(&self, mut input: I) -> Option<Self::Output> {
33        let from = input.save();
34        let a = self.a.parse(input.ref_clone());
35        a.or_else(|| {
36            input.back(from);
37            let b = self.b.parse(input);
38            b
39        })
40    }
41}
42
43#[macro_export]
44#[doc(hidden)]
45macro_rules! _or {
46    { $input:ident, $from:ident ; $a:expr, $b: expr } => {
47        $a.parse($input.ref_clone()).or_else(|| {
48            $input.back($from);
49            $b.parse($input)
50        })
51    };
52    { $input:ident, $from:ident ; $a:expr, $($b: expr),+ } => {
53        $a.parse($input.ref_clone()).or_else(|| {
54            $input.back($from);
55            _or!($input, $from ; $($b),+)
56        })
57    }
58}
59/// Pass when any subparser passes
60/// # Example
61/// ```rust
62/// # use parser_fuck::*;
63/// let code = "b".span();
64/// let r = or!(code ; one('a'), one('b'), one('c'));
65/// assert_eq!(r, Some(0..1));
66/// ```
67#[macro_export(local_inner_macros)]
68macro_rules! or {
69    { } => {{ }};
70    { $input:expr } => {{ }};
71    { $input:expr ; } => {{ }};
72    { $input:expr ; $a:expr $(,)? } => {{
73        $a.parse($input)
74    }};
75    { $input:expr ; $a:expr, $($b: expr),+ $(,)? } => {{
76        let mut input = $input;
77        let from = input.save();
78        _or!(input, from ; $a, $($b),+)
79    }};
80}
81
82#[cfg(test)]
83mod tests {
84    use crate::*;
85
86    #[test]
87    fn test_macro() {
88        let code = "b";
89        let span = code.span();
90
91        let r = or!(span ; one('a'), one('b'), one('c'));
92        println!("{:?}", r);
93        assert_eq!(r, Some(0..1));
94    }
95
96    #[test]
97    fn test() {
98        let code = "asd";
99        let span = code.span();
100        let a = substr("b");
101        let b = substr("a");
102        let x = a.or(b);
103
104        let r = x.parse(span);
105        println!("{:?}", r);
106        assert_eq!(r, Some(0..1));
107    }
108
109    #[test]
110    fn test_a() {
111        let code = "asd";
112        let span = code.span();
113        let a = substr("a");
114        let b = substr("b");
115        let x = a.or(b);
116
117        let r = x.parse(span);
118        println!("{:?}", r);
119        assert_eq!(r, Some(0..1));
120    }
121
122    #[test]
123    fn test_none() {
124        let code = "asd";
125        let span = code.span();
126        let a = substr("b");
127        let b = substr("c");
128        let x = a.or(b);
129
130        let r = x.parse(span);
131        println!("{:?}", r);
132        assert_eq!(r, None);
133    }
134}