pear/
macros.rs

1//! Macros.
2//!
3//!
4//!   * [`parse_declare!`](#parse_declare)
5//!   * [`parse_error!`](#parse_error)
6//!   * [`impl_show_with!`](#impl_show_with)
7//!
8//! [`Input`]: crate::input::Input
9//! [`Result<O, I>`]: crate::result::Result
10//! [`Input::mark()`]: crate::input::Input::mark()
11//! [`Input::unmark()`]: crate::input::Input::unmark()
12//! [`Input::context()`]: crate::input::Input::context()
13//! [`ParseError::push_context()`]: crate::error::ParseError::push_context()
14//! [`eof()`]: crate::parsers::eof()
15
16#[doc(inline)]
17pub use pear_codegen::{parser, switch};
18#[doc(inline)]
19pub use crate::{parse, parse_declare, parse_error, parse_try, is_parse_debug};
20#[doc(inline)]
21pub use crate::{parse_current_marker, parse_last_marker, parse_mark, parse_context};
22#[doc(inline)]
23pub use crate::impl_show_with;
24
25/// Runs the parser with the given name and input, then [`parsers::eof()`].
26///
27/// Returns the combined result.
28///
29/// Syntax:
30///
31/// ```text
32/// parse := PARSER_NAME ( '(' (EXPR ',')* ')' )? ':' INPUT_EXPR
33///
34/// PARSER_NAME := rust identifier to parser function
35/// INPUT_EXPR := any valid rust expression which resolves to a mutable
36///               reference to type that implements `Input`
37/// ```
38#[macro_export]
39macro_rules! parse {
40    ($parser:ident : &mut $e:expr) => ({
41        let input = &mut $e;
42        (move || {
43            let result = $parser(input)?;
44            $crate::parsers::eof(input).map_err(|e| e.into())?;
45            $crate::result::IntoResult::into_result(result)
46        })()
47    });
48    ($parser:ident : $e:expr) => (parse!($parser(): $e));
49    ($parser:ident ($($x:expr),*) : $e:expr) => ({
50        let mut input: $crate::input::Pear<_> = $e.into();
51        (move || {
52            let result = $parser(&mut input $(, $x)*)?;
53            $crate::parsers::eof(&mut input).map_err(|e| e.into())?;
54            $crate::result::IntoResult::into_result(result)
55        })()
56    })
57}
58
59#[doc(hidden)]
60#[macro_export(local_inner_macros)]
61macro_rules! parse_declare {
62    (pub($($inner:tt)+) $($rest:tt)*) => { $crate::_parse_declare!([pub($($inner)+)] $($rest)*); };
63    (pub $($rest:tt)*) => { $crate::_parse_declare!([pub] $($rest)*); };
64    ($($rest:tt)*) => { $crate::_parse_declare!([] $($rest)*); }
65}
66
67#[doc(hidden)]
68#[macro_export(local_inner_macros)]
69macro_rules! _parse_declare {
70    ([$($vis:tt)*] $input:ident $(<$($gen:tt),+>)* ($($T:ident = $t:ty),*)) => {
71        $($vis)* trait $input $(<$($gen),+>)*: $crate::input::Input<$($T = $t),*> {  }
72
73        impl<$($($gen,)+)* T> $input $(<$($gen)+>)* for T
74            where T: $crate::input::Input<$($T = $t),*> + $($($gen),+)* {  }
75    }
76}
77
78/// Like `format!` but tries to inline the string.
79#[doc(hidden)]
80#[macro_export]
81macro_rules! iformat {
82    () => (iformat!("",));
83    ($fmt:expr) => (iformat!($fmt,));
84    ($fmt:expr, $($arg:tt)*) => ({
85        #[allow(unused_imports)]
86        use std::fmt::Write;
87        #[allow(unused_imports)]
88        use $crate::inlinable_string::{InlinableString, StringExt};
89        let mut string = $crate::inlinable_string::InlinableString::new();
90        let _ = write!(string, $fmt, $($arg)*);
91        string
92    })
93}
94
95/// Returns an `Err(ParseError::new($e))`. Can used like `format!` as well.
96#[macro_export]
97macro_rules! parse_error {
98    ([$info:expr; $input:expr; $marker:expr; $T:ty] $err:expr) => ({
99        let context = $crate::parse_context!([$info; $input; $marker; $T]);
100        Err($crate::error::ParseError::new(*$info, $err, context))
101    });
102    ([$n:expr; $i:expr; $m:expr; $T:ty] $fmt:expr, $($arg:tt)*) => {
103        parse_error!([$n; $i; $m; $T] $crate::iformat!($fmt, $($arg)*))
104    };
105}
106
107/// Returns the last marker that was set.
108///
109/// Invoked with no arguments: `parse_marker!()`
110#[macro_export]
111macro_rules! parse_last_marker {
112    ([$n:expr; $i:expr; $marker:expr; $T:ty]) => (*$marker);
113}
114
115/// Return the mark at the current parsing position.
116///
117/// Invoked with no arguments: `parse_current_marker!()`
118#[macro_export]
119macro_rules! parse_current_marker {
120    ([$info:expr; $input:expr; $marker:expr; $T:ty]) => (
121        $crate::input::Input::mark($input, $info)
122    )
123}
124
125/// Sets the marker to the current position.
126#[macro_export]
127macro_rules! parse_mark {
128    ([$info:expr; $input:expr; $marker:expr; $T:ty]) => {{
129        *$marker = $crate::input::Input::mark($input, $info);
130    }}
131}
132
133/// Returns the context from the current mark to the input position inclusive.
134///
135/// Invoked with no arguments: `parse_context!()`
136#[macro_export]
137macro_rules! parse_context {
138    ([$n:expr; $i:expr; $marker:expr; $T:ty]) => (
139        $crate::input::Input::context($i, *$marker)
140    );
141}
142
143/// Runs a parser returning `Some` if it succeeds or `None` otherwise.
144///
145/// Take a single parser expression as input. Without additional arguments,
146/// returns the output in `Some` on success. If called as `parse_try!(parse_expr
147/// => result_expr)`, returns `result_expr` in `Some` on success. The result of
148/// the parse expression can be pattern-binded as `parse_try!(pat@pexpr =>
149/// rexpr)`.
150// FIXME: This is an issue with rustc here where if `$input` is `expr`
151// everything fails.
152#[macro_export]
153macro_rules! parse_try {
154    ([$n:expr; $input:ident; $m:expr; $T:ty] $e:expr) => {{
155        $crate::macros::switch! { [$n;$input;$m;$T] result@$e => { Some(result) }, _ => { None } }
156    }};
157    ([$n:expr; $input:ident; $m:expr; $T:ty] $e:expr => $r:expr) => {{
158        $crate::macros::switch! { [$n;$input;$m;$T] $e => { Some($r) }, _ => { None } }
159    }};
160    ([$n:expr; $input:ident; $m:expr; $T:ty] $e:expr => $r:expr => || $f:expr) => {{
161        $crate::macros::switch! { [$n;$input;$m;$T] $e => { $r }, _ => { $f } }
162    }};
163    ([$n:expr; $input:ident; $m:expr; $T:ty] $pat:ident@$e:expr => $r:expr) => {{
164        $crate::macros::switch! { [$n;$input;$m;$T] $pat@$e => { Some($r) }, _ => { None } }
165    }}
166}
167
168#[doc(hidden)]
169#[macro_export]
170macro_rules! is_parse_debug {
171    () => ({
172        #[cfg(not(debug_assertions))] { false }
173        #[cfg(debug_assertions)] { ::std::env::var("PARSE_DEBUG").is_ok() }
174    });
175
176    ($kind:expr) => ({
177        #[cfg(not(debug_assertions))] { false }
178        #[cfg(debug_assertions)] {
179            ::std::env::var("PARSE_DEBUG").map(|v| v == $kind).unwrap_or(false)
180        }
181    })
182}
183
184/// Implements the `Show` trait for $($T)+ using the existing trait `$trait`.
185#[macro_export]
186macro_rules! impl_show_with {
187    ($trait:ident, $($T:ty),+) => (
188        $(impl $crate::input::Show for $T {
189            #[inline(always)]
190            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191                std::fmt::$trait::fmt(self, f)
192            }
193        })+
194    )
195}