anpa/
macros.rs

1/// Shorthand for creating a parser.
2/// ### Example:
3/// ```ignore
4/// let p = create_parser!(s, { /* Define parser behavior using state `s` */ })
5/// ```
6#[macro_export]
7macro_rules! create_parser {
8    ($state:ident, $f:expr) => {
9        move |$state: &mut $crate::core::AnpaState<_, _>| $f
10    }
11}
12
13/// Shorthand for creating a deferred parser. This is mandatory when creating recursive parsers.
14///
15/// ### Example:
16/// ```
17/// use anpa::defer_parser;
18/// use anpa::core::*;
19/// use anpa::combinators::{middle, not_empty, or};
20/// use anpa::parsers::{item_while, take};
21///
22/// /// Can parse e.g. "(((something)))"
23/// fn in_parens<'a>() -> impl StrParser<'a> {
24///     defer_parser!(or(
25///         not_empty(item_while(|c: char| c.is_alphanumeric())),
26///         middle(take('('), in_parens(), take(')')))
27///     )
28/// }
29///
30/// assert_eq!(parse(in_parens(), "((((inside))))" ).result, Some("inside"));
31///
32/// ```
33#[macro_export]
34macro_rules! defer_parser {
35    ($p:expr) => {
36        $crate::create_parser!(s, $p(s))
37    }
38}
39
40/// Variadic version of `map`, where all provided parsers must succeed.
41/// ### Arguments
42/// * `f` - the transformation function. Its arguments must match the result types of `p...` in
43///         both type and number.
44/// * `p...` - any number of parsers.
45#[macro_export]
46macro_rules! map {
47    ($f:expr, $($p:expr),* $(,)?) => {
48        $crate::create_parser!(s, Some($f($($p(s)?),*)))
49    };
50}
51
52/// Variadic version of `map_if`, where all provided parsers must succeed.
53/// ### Arguments
54/// * `f` - the transformation function. Its arguments must match the result types of `p...` in
55///         both type and number.
56/// * `p...` - any number of parsers.
57#[macro_export]
58macro_rules! map_if {
59    ($f:expr, $($p:expr),* $(,)?) => {
60        $crate::create_parser!(s, Some($f($($p(s)?),*)?))
61    };
62}
63
64/// Convert a number of parsers to a single parser producing a tuple with all the results.
65/// ### Arguments
66/// * `p...` - any number of parsers.
67#[macro_export]
68macro_rules! tuplify {
69    ($($p:expr),* $(,)?) => {
70        $crate::create_parser!(s, Some(($($p(s)?),*)))
71    };
72}
73
74/// Create a parser that successfully returns `x`.
75///
76/// ### Arguments
77/// * `x` - the result to be returned from the parser.
78#[macro_export]
79macro_rules! pure {
80    ($x:expr) => {
81        $crate::create_parser!(_s, Some($x))
82    };
83}
84
85/// A helper macro to generate variadic macros using repeated application of the rightmost
86/// argument of a binary function.
87///
88/// E.g. for 4 arguments, the resulting function will be constructed as:
89/// `f(e1, f(e2, f(e3, e4)))`
90///
91/// ### Arguments
92/// * `f` - a binary function.
93/// * `e...` - any number of arguments.
94#[macro_export]
95macro_rules! variadic {
96    ($f:expr, $e:expr) => {
97        $e
98    };
99    ($f:expr, $e:expr, $($e2:expr),*) => {
100        $f($e, $crate::variadic!($f, $($e2),*))
101    };
102}
103
104/// Variadic version of `or`.
105///
106/// ### Arguments
107/// * `p...` - any number of parsers.
108#[macro_export]
109macro_rules! or {
110    ($($p:expr),* $(,)?) => {
111        $crate::variadic!($crate::combinators::or, $($p),*)
112    };
113}
114
115/// Variadic version of `or_no_partial`.
116///
117/// ### Arguments
118/// * `p...` - any number of parsers.
119#[macro_export]
120macro_rules! or_no_partial {
121    ($($p:expr),* $(,)?) => {
122        $crate::variadic!($crate::combinators::or_no_partial, $($p),*)
123    };
124}
125
126/// Variadic version of `or_diff`.
127///
128/// ### Arguments
129/// * `p...` - any number of parsers.
130#[macro_export]
131macro_rules! or_diff {
132    ($($p:expr),* $(,)?) => {
133        $crate::variadic!($crate::combinators::or_diff, $($p),*)
134    };
135}
136
137/// Variadic version of `or_diff_no_partial`.
138///
139/// ### Arguments
140/// * `p...` - any number of parsers.
141#[macro_export]
142macro_rules! or_diff_no_partial {
143    ($($p:expr),* $(,)?) => {
144        $crate::variadic!($crate::combinators::or_diff_no_partial, $($p),*)
145    };
146}
147
148/// Variadic version of `left`, where only the leftmost parser's result will be returned.
149///
150/// ### Arguments
151/// * `p...` - any number of parsers.
152#[macro_export]
153macro_rules! left {
154    ($($p:expr),* $(,)?) => {
155        $crate::variadic!($crate::combinators::left, $($p),*)
156    };
157}
158
159/// Variadic version of `right`, where only the rightmost parser's result will be returned.
160///
161/// ### Arguments
162/// * `p...` - any number of parsers.
163#[macro_export]
164macro_rules! right {
165    ($($p:expr),* $(,)?) => {
166        $crate::variadic!($crate::combinators::right, $($p),*)
167    };
168}
169
170/// Variadic parser that succeeds if the next item matches the provided
171/// patterns. Note that unlike `matches!`, this macro accepts multiple
172/// patterns.
173///
174/// ### Arguments
175/// * `patterns` - match patterns (as one would pass to `matches!`)
176///
177/// ### Example:
178/// ```
179/// use anpa::core::*;
180/// use anpa::item_matches;
181///
182/// let p = item_matches!('0' | '1');
183///
184/// assert_eq!(parse(p, "012").result, Some('0'));
185/// assert_eq!(parse(p, "123").result, Some('1'));
186/// assert_eq!(parse(p, "234").result, None);
187/// ```
188#[macro_export]
189macro_rules! item_matches {
190    ($($($patterns:pat_param)|+ $(if $guard:expr)?),+ $(,)?) => {
191        $crate::parsers::item_if(|c| {
192            match c {
193                $($($patterns)|+ $(if $guard)? => true,)+
194                _ => false
195            }
196        })
197    };
198}
199
200/// Alternative to the `take` parser that inlines the argument into the parser.
201///
202/// This can give better performance and/or smaller binary size, or the opposite.
203/// Try it and don't forget to measure!
204///
205/// This macro is likely only useful when passing a literal as argument.
206///
207/// ### Arguments
208/// * `prefix` - the prefix to parse.
209#[macro_export]
210macro_rules! take {
211    ($prefix:expr) => {
212        $crate::create_parser!(s, {
213            $crate::prefix::Prefix::take_prefix(&$prefix, s.input).map(|(res, rest)| {
214                s.input = rest;
215                res
216            })
217        })
218    }
219}
220
221/// Alternative to the `skip` parser that inlines the argument into the parser.
222///
223/// This can give better performance and/or smaller binary size, or the opposite.
224/// Try it and don't forget to measure!
225///
226/// This macro is likely only useful when passing a literal as argument.
227///
228/// ### Arguments
229/// * `prefix` - the prefix to parse.
230#[macro_export]
231macro_rules! skip {
232    ($prefix:expr) => {
233        $crate::create_parser!(s, {
234            s.input = $crate::prefix::Prefix::skip_prefix(&$prefix, s.input)?;
235            Some(())
236        })
237    }
238}
239/// Alternative to the `until` parser that inlines the argument into the parser.
240///
241/// This can give better performance and/or smaller binary size, or the opposite.
242/// Try it and don't forget to measure!
243///
244/// This macro is likely only useful when passing a literal as argument.
245///
246/// ### Arguments
247/// * `needle` - the element to search for.
248#[macro_export]
249macro_rules! until {
250    ($needle:expr) => {
251        $crate::create_parser!(s, {
252            let (size, index) = $crate::needle::Needle::find_in(&$needle, s.input)?;
253            let res = $crate::slicelike::SliceLike::slice_to(s.input, index);
254            s.input = $crate::slicelike::SliceLike::slice_from(s.input, index + size);
255            Some(res)
256        })
257    }
258}
259
260/// Variadic version of `greedy_or`, where the result of the parser with the most consumed
261/// input will be returned.
262///
263/// ### Arguments
264/// * `p...` - any number of parsers.
265#[macro_export]
266macro_rules! greedy_or {
267    ($($p:expr),* $(,)?) => {
268        $crate::variadic!($crate::combinators::greedy_or, $($p),*)
269    };
270}
271
272/// Create a parser that takes the result of a parser, and returns different
273/// parsers depending on the provided conditions.
274///
275/// If none of the provided conditions match, the parser will fail.
276///
277/// The macro comes in two flavors:
278/// - if-style:
279/// ```
280/// # use anpa::{choose, core::parse, number::integer, parsers::take};
281///     let p = choose!(integer() => n; // Explicit binding to variable `v`
282///                    (0_u8..=4).contains(&n) => take("range"),
283///                    n == 5                  => take("five"));
284/// # parse(p, "dummy");
285/// ```
286/// - match-style:
287/// ```
288/// # use anpa::{choose, core::parse, number::integer, parsers::take};
289///     let p = choose!(integer(); // No binding of result.
290///                     0_u8..=4 => take("range"),
291///                     5        => take("five"));
292/// # parse(p, "dummy");
293/// ```
294///
295///
296/// ### Example:
297/// ```
298/// use anpa::core::*;
299/// use anpa::choose;
300/// use anpa::parsers::take;
301/// use anpa::number::integer;
302///
303/// let p_if = choose!(integer() => x: u8; // Note the semicolon
304///                   x == 0 => take("zero"),
305///                   x == 1 => take("one"),
306///                   (2..=100).contains(&x) => take("big")
307/// );
308///
309/// let p_match = choose!(integer(); // Note the semicolon
310///                       0_u8 => take("zero"),
311///                       1 => take("one"),
312///                       2..=100 => take("big")
313/// );
314///
315/// let input1 = "0zero";
316/// let input2 = "1one";
317/// let input3 = "2big";
318/// let input4 = "100big";
319/// let input5 = "101big";
320/// let input6 = "0one";
321/// let input7 = "1zero";
322///
323/// assert_eq!(parse(p_if, input1).result, Some("zero"));
324/// assert_eq!(parse(p_if, input2).result, Some("one"));
325/// assert_eq!(parse(p_if, input3).result, Some("big"));
326/// assert_eq!(parse(p_if, input4).result, Some("big"));
327/// assert_eq!(parse(p_if, input5).result, None);
328/// assert_eq!(parse(p_if, input6).result, None);
329/// assert_eq!(parse(p_if, input7).result, None);
330///
331/// assert_eq!(parse(p_match, input1).result, Some("zero"));
332/// assert_eq!(parse(p_match, input2).result, Some("one"));
333/// assert_eq!(parse(p_match, input3).result, Some("big"));
334/// assert_eq!(parse(p_match, input4).result, Some("big"));
335/// assert_eq!(parse(p_match, input5).result, None);
336/// assert_eq!(parse(p_match, input6).result, None);
337/// assert_eq!(parse(p_match, input7).result, None);
338/// ```
339#[macro_export]
340macro_rules! choose {
341    ($p:expr => $res:ident $(: $t:ty)?; $($cond:expr => $new_p:expr),* $(,)?) => {
342        $crate::create_parser!(s, {
343            let $res $(:$t)? = $p(s)?;
344
345            $(if $cond {
346                return $new_p(s)
347            })*
348
349            None
350        })
351    };
352
353    ($p:expr; $($arm:pat_param $(| $alt:pat_param)* $(if $guard:expr)? => $new_p:expr),* $(,)?) => {
354        $crate::create_parser!(s, {
355            match $p(s)? {
356                $(
357                    $arm $(| $alt)* $(if $guard)? => $new_p(s),
358                )*
359                #[allow(unreachable_patterns)]
360                _ => None
361            }
362        })
363    };
364}
365
366/// Create a new parser trait with a concrete input type for cleaner APIs.
367/// ### Arguments
368/// * `id` - The identifier of the new trait
369/// * `input` - The type of the input. Do not include lifetime or reference.
370/// * `comment` - The doc comment to be generated for the trait
371///
372/// ### Example
373/// ```
374/// use anpa::create_parser_trait;
375/// create_parser_trait!(I8Parser, [i8], "Convenience alias for a parser that parses a `&'a [i8]`");
376/// ```
377#[macro_export]
378macro_rules! create_parser_trait {
379    ($id:ident, $input:ty, $comment:expr) => {
380        #[doc=$comment]
381        pub trait $id<'a, O = &'a $input, S = ()>: $crate::core::Parser<&'a $input, O, S> {}
382        impl<'a, O, S, P: $crate::core::Parser<&'a $input, O, S>> $id<'a, O, S> for P {}
383    };
384}