2018-09-07 21:06:26 -05:00
|
|
|
//! Contains combinators that can assemble other matchers or combinators into more complex grammars.
|
2018-09-05 22:36:09 -05:00
|
|
|
|
|
|
|
/// Turns a matcher into it's inverse, only succeeding if the the matcher returns a Fail.
|
|
|
|
/// Does not consume it's input and only returns ().
|
2018-09-07 21:06:26 -05:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// # use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::{Result, Offsetable};
|
|
|
|
/// # use std::convert::From;
|
|
|
|
/// # fn main() {
|
|
|
|
/// # let iter: iter::SliceIter<u8> = "foo".into();
|
|
|
|
/// let tok = not!(iter, text_token!("bar"));
|
|
|
|
/// assert!(tok.is_complete());
|
|
|
|
/// if let Result::Complete(i, o) = tok {
|
|
|
|
/// assert_eq!(i.get_offset(), 0);
|
|
|
|
/// assert_eq!(o, ());
|
|
|
|
/// }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2018-09-05 22:36:09 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! not {
|
|
|
|
($i:expr, $f:ident!( $( $args:tt )* ) ) => {{
|
|
|
|
use $crate::{Result, Error};
|
|
|
|
let _i = $i.clone();
|
|
|
|
match trap!(_i, $f!($($args)*)) {
|
|
|
|
Result::Complete(i, _) => Result::Fail(Error::new("Matched on input when we shouldn't have.".to_string(), &i)),
|
|
|
|
Result::Abort(e) => Result::Abort(e),
|
|
|
|
Result::Incomplete(offset) => Result::Incomplete(offset),
|
|
|
|
Result::Fail(_) => Result::Complete($i, ()),
|
|
|
|
}
|
|
|
|
}};
|
|
|
|
|
|
|
|
($i:expr, $f:ident( $( $args:tt )* ) ) => {
|
|
|
|
not!($i, run!($f($($args)*)))
|
|
|
|
};
|
|
|
|
|
|
|
|
($i:expr, $f:ident) => {
|
|
|
|
not!($i, run!($f))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-07 21:06:26 -05:00
|
|
|
/// Checks the given matcher without consuming the input.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// # use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::{Result, Offsetable};
|
|
|
|
/// # use std::convert::From;
|
|
|
|
/// # fn main() {
|
|
|
|
/// # let iter: iter::SliceIter<u8> = "foo".into();
|
|
|
|
/// let tok = peek!(iter, text_token!("foo"));
|
|
|
|
/// # assert!(tok.is_complete());
|
|
|
|
/// # if let Result::Complete(i, o) = tok {
|
|
|
|
/// # assert_eq!(i.get_offset(), 0);
|
|
|
|
/// # assert_eq!(o, "foo");
|
|
|
|
/// # }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2018-09-05 22:36:09 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! peek {
|
|
|
|
($i:expr, $f:ident!( $( $args:tt )* ) ) => {{
|
|
|
|
use $crate::Result;
|
|
|
|
let _i = $i.clone();
|
|
|
|
match $f!(_i, $($args)*) {
|
|
|
|
Result::Complete(_, o) => Result::Complete($i, o),
|
|
|
|
Result::Incomplete(offset) => Result::Incomplete(offset),
|
|
|
|
Result::Abort(e) => Result::Abort(e),
|
|
|
|
Result::Fail(e) => Result::Fail(e),
|
|
|
|
}
|
|
|
|
}};
|
|
|
|
|
|
|
|
($i:expr, $f:ident( $( $args:tt )* ) ) => {
|
|
|
|
peek!($i, run!($f($($args)*)))
|
|
|
|
};
|
|
|
|
|
|
|
|
($i:expr, $f:ident) => {
|
|
|
|
peek!($i, run!($f))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-02 22:10:11 -05:00
|
|
|
/// Converts a function indentifier into a macro call. Useful when writing your own macro combinator.
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! run {
|
|
|
|
($i:expr, $f:ident) => {
|
|
|
|
$f($i)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-07 21:06:26 -05:00
|
|
|
/// Turns Fails into Aborts. Allows you to turn any parse failure into a hard abort of
|
|
|
|
/// the parser.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::Result;
|
|
|
|
/// # use std::convert::From;
|
|
|
|
/// # fn main() {
|
|
|
|
///
|
|
|
|
/// let iter: iter::SliceIter<u8> = "foo".into();
|
|
|
|
///
|
|
|
|
/// let tok = must!(iter, text_token!("foo"));
|
|
|
|
/// # assert!(tok.is_complete());
|
|
|
|
///
|
|
|
|
/// let fail = must!(iter, text_token!("bar"));
|
|
|
|
/// # assert!(fail.is_abort());
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2018-09-02 22:10:11 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! must {
|
|
|
|
($i:expr, $f:ident!( $( $args:tt )* ) ) => {
|
|
|
|
match $f!($i, $($args)*) {
|
|
|
|
$crate::Result::Complete(i, o) => $crate::Result::Complete(i, o),
|
|
|
|
$crate::Result::Incomplete(offset) => $crate::Result::Incomplete(offset),
|
|
|
|
$crate::Result::Fail(e) => $crate::Result::Abort(e),
|
|
|
|
$crate::Result::Abort(e) => $crate::Result::Abort(e),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
($i:expr, $f:ident) => {
|
|
|
|
must!($i, run!($f))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-05 20:43:43 -05:00
|
|
|
/// Wraps any Error return from a subparser in another error. Stores the position at
|
|
|
|
/// this point in the parse tree allowing you to associate context with wrapped errors.
|
2018-09-03 00:05:32 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! wrap_err {
|
|
|
|
($i:expr, $f:ident!( $( $args:tt )* ), $e:expr) => {{
|
|
|
|
let _i = $i.clone();
|
|
|
|
match $f!($i, $($args)*) {
|
|
|
|
$crate::Result::Complete(i, o) => $crate::Result::Complete(i, o),
|
|
|
|
$crate::Result::Incomplete(offset) => $crate::Result::Incomplete(offset),
|
|
|
|
$crate::Result::Fail(e) => $crate::Result::Fail($crate::Error::caused_by($e, &_i, e)),
|
|
|
|
$crate::Result::Abort(e) => $crate::Result::Abort($crate::Error::caused_by($e, &_i, e)),
|
|
|
|
}
|
|
|
|
}};
|
|
|
|
|
2018-09-05 22:02:00 -05:00
|
|
|
($i:expr, $f:ident( $( $args:tt )* ), $e:expr ) => {
|
|
|
|
wrap_err!($i, run!($f($($args)*)), $e:expr)
|
|
|
|
};
|
|
|
|
|
2018-09-03 00:05:32 -05:00
|
|
|
($i:expr, $f:ident, $e:expr) => {
|
|
|
|
wrap_err!($i, run!($f), $e)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-07 21:06:26 -05:00
|
|
|
/// Turns Aborts into fails allowing you to trap and then convert an Abort into a
|
|
|
|
/// normal Fail.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::{Result, Offsetable};
|
|
|
|
/// # fn main() {
|
|
|
|
/// let input_str = "foo";
|
|
|
|
/// let iter = iter::SliceIter::new(input_str.as_bytes());
|
|
|
|
/// let result = trap!(iter, must!(text_token!("bar")));
|
|
|
|
/// # assert!(result.is_fail());
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2018-09-02 22:10:11 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! trap {
|
|
|
|
($i:expr, $f:ident!( $( $args:tt )* ) ) => {
|
|
|
|
match $f!($i, $($args)*) {
|
|
|
|
$crate::Result::Complete(i, o) => $crate::Result::Complete(i, o),
|
|
|
|
$crate::Result::Incomplete(offset) => $crate::Result::Incomplete(offset),
|
|
|
|
$crate::Result::Fail(e) => $crate::Result::Fail(e),
|
|
|
|
$crate::Result::Abort(e) => $crate::Result::Fail(e),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
($i:expr, $f:ident) => {
|
|
|
|
trap!($i, run!($f))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-07 21:06:26 -05:00
|
|
|
/// Turns Fails and Incompletes into Aborts. You must specify the error message
|
|
|
|
/// to use in case the matcher is Incomplete.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::{Result, Offsetable};
|
|
|
|
/// # fn main() {
|
|
|
|
/// let input_str = "foo";
|
|
|
|
/// let iter = iter::SliceIter::new(input_str.as_bytes());
|
|
|
|
/// let mut result = must_complete!(iter, "AHHH".to_string(), text_token!("fooooo"));
|
|
|
|
/// # assert!(result.is_abort());
|
|
|
|
/// # }
|
2018-09-02 22:10:11 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! must_complete {
|
2018-09-03 00:05:32 -05:00
|
|
|
($i:expr, $e:expr, $f:ident!( $( $args:tt )* ) ) => {{
|
|
|
|
let _i = $i.clone();
|
2018-09-02 22:10:11 -05:00
|
|
|
match $f!($i, $($args)*) {
|
|
|
|
$crate::Result::Complete(i, o) => $crate::Result::Complete(i, o),
|
2018-09-03 00:05:32 -05:00
|
|
|
$crate::Result::Incomplete(ref offset) => $crate::Result::Abort($crate::Error::new($e, offset)),
|
2018-09-02 22:10:11 -05:00
|
|
|
$crate::Result::Fail(e) => $crate::Result::Abort(e),
|
|
|
|
$crate::Result::Abort(e) => $crate::Result::Abort(e),
|
|
|
|
}
|
2018-09-03 00:05:32 -05:00
|
|
|
}};
|
2018-09-02 22:10:11 -05:00
|
|
|
|
|
|
|
($i:expr, $efn:expr, $f:ident) => {
|
|
|
|
must_complete!($i, $efn, run!($f))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Captures a sequence of sub parsers output.
|
2018-09-07 21:06:26 -05:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::{Result, Offsetable};
|
|
|
|
/// # fn main() {
|
|
|
|
/// let input_str = "(foobar)";
|
|
|
|
/// let iter = iter::SliceIter::new(input_str.as_bytes());
|
|
|
|
/// let result = do_each!(iter,
|
|
|
|
/// _ => text_token!("("),
|
|
|
|
/// foo => text_token!("foo"),
|
|
|
|
/// bar => text_token!("bar"),
|
|
|
|
/// _ => text_token!(")"),
|
|
|
|
/// (foo, bar) // This expression will be the result of the parse
|
|
|
|
/// );
|
|
|
|
/// # assert!(result.is_complete());
|
|
|
|
/// if let Result::Complete(_, o) = result {
|
|
|
|
/// assert_eq!("foo", o.0);
|
|
|
|
/// assert_eq!("bar", o.1);
|
|
|
|
/// }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Or alternatively rather than a tuple as the output you can return a single
|
|
|
|
/// expression.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// # use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::{Result, Offsetable};
|
|
|
|
/// # fn main() {
|
|
|
|
/// # let input_str = "(foobar)";
|
|
|
|
/// # let iter = iter::SliceIter::new(input_str.as_bytes());
|
|
|
|
/// let result = do_each!(iter,
|
|
|
|
/// _ => text_token!("("),
|
|
|
|
/// foo => text_token!("foo"),
|
|
|
|
/// bar => text_token!("bar"),
|
|
|
|
/// _ => text_token!(")"),
|
|
|
|
/// (vec![foo, bar]) // Non tuple expression as a result.
|
|
|
|
/// );
|
|
|
|
/// # assert!(result.is_complete());
|
|
|
|
/// if let Result::Complete(_, o) = result {
|
|
|
|
/// assert_eq!(vec!["foo", "bar"], o);
|
|
|
|
/// }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// The output from this combinator must be indicated by parentheses.
|
2018-09-02 22:10:11 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! do_each {
|
|
|
|
($i:expr, $val:ident => $f:ident) => {
|
|
|
|
// This is a compile failure.
|
|
|
|
compile_error!("do_each! must end with a tuple capturing the results")
|
|
|
|
};
|
|
|
|
|
|
|
|
($i:expr, $val:ident => $f:ident!($( $args:tt )* ), $($rest:tt)* ) => {
|
|
|
|
// If any single one of these matchers fails then all of them are failures.
|
|
|
|
match $f!($i, $($args)*) {
|
|
|
|
$crate::Result::Complete(i, o) => {
|
|
|
|
let $val = o;
|
|
|
|
do_each!(i, $($rest)*)
|
|
|
|
}
|
|
|
|
$crate::Result::Incomplete(offset) => {
|
|
|
|
Result::Incomplete(offset)
|
|
|
|
}
|
|
|
|
$crate::Result::Fail(e) => Result::Fail(e),
|
|
|
|
$crate::Result::Abort(e) => Result::Abort(e),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
($i:expr, _ => $f:ident!($( $args:tt )* ), $($rest:tt)* ) => {
|
|
|
|
// If any single one of these matchers fails then all of them are failures.
|
|
|
|
match $f!($i, $($args)*) {
|
|
|
|
$crate::Result::Complete(i, _) => {
|
|
|
|
do_each!(i, $($rest)*)
|
|
|
|
}
|
|
|
|
$crate::Result::Incomplete(offset) => {
|
|
|
|
Result::Incomplete(offset)
|
|
|
|
}
|
|
|
|
$crate::Result::Fail(e) => Result::Fail(e),
|
|
|
|
$crate::Result::Abort(e) => Result::Abort(e),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
($i:expr, $val:ident => $f:ident, $($rest:tt)* ) => {
|
|
|
|
// If any single one of these matchers fails then all of them are failures.
|
|
|
|
do_each!($i, $val => run!($f), $( $rest )* )
|
|
|
|
};
|
|
|
|
|
|
|
|
($i:expr, _ => $f:ident, $($rest:tt)* ) => {
|
|
|
|
// If any single one of these matchers fails then all of them are failures.
|
|
|
|
do_each!($i, _ => run!($f), $( $rest )* )
|
|
|
|
};
|
|
|
|
|
|
|
|
// Our Terminal condition
|
|
|
|
($i:expr, ( $($rest:tt)* ) ) => {
|
|
|
|
Result::Complete($i, ($($rest)*))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the output of the first sub parser to succeed.
|
2018-09-07 21:06:26 -05:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::{Result, Offsetable};
|
|
|
|
/// # fn main() {
|
|
|
|
/// let input_str = "foo";
|
|
|
|
/// let iter = iter::SliceIter::new(input_str.as_bytes());
|
|
|
|
/// let result = either!(iter, text_token!("bar"), text_token!("foo"));
|
|
|
|
/// # assert!(result.is_complete());
|
|
|
|
/// # if let Result::Complete(_, o) = result {
|
|
|
|
/// # assert_eq!("foo", o);
|
|
|
|
/// # } else {
|
|
|
|
/// # assert!(false, "either! did not complete");
|
|
|
|
/// # }
|
|
|
|
/// # }
|
2018-09-02 22:10:11 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! either {
|
|
|
|
// Initialization case.
|
|
|
|
($i:expr, $f:ident!( $( $args:tt )* ), $( $rest:tt)* ) => { // 0
|
|
|
|
either!(__impl $i, $f!( $($args)* ), $($rest)*)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Initialization case.
|
|
|
|
($i:expr, $f:ident, $($rest:tt)* ) => { // 1
|
|
|
|
either!(__impl $i, run!($f), $($rest)*)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Initialization failure case.
|
|
|
|
($i:expr, $f:ident!( $( $args:tt )* )) => { // 2
|
|
|
|
compile_error!("Either requires at least two sub matchers.")
|
|
|
|
};
|
|
|
|
|
|
|
|
// Initialization failure case.
|
|
|
|
($i:expr, $f:ident) => { // 3
|
|
|
|
either!($i, run!($f))
|
|
|
|
};
|
|
|
|
|
|
|
|
// Termination clause
|
|
|
|
(__impl $i:expr, $f:ident) => { // 4
|
|
|
|
either!(__impl $i, run!($f))
|
|
|
|
};
|
|
|
|
|
|
|
|
// Termination clause
|
|
|
|
(__impl $i:expr, $f:ident,) => { // 5
|
|
|
|
either!(__impl $i, run!($f))
|
|
|
|
};
|
|
|
|
|
|
|
|
// Termination clause
|
|
|
|
(__impl $i:expr, $f:ident!( $( $args:tt )* ),) => { // 6
|
|
|
|
either!(__impl $i, $f!($($args)*) __end)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Termination clause
|
|
|
|
(__impl $i:expr, $f:ident!( $( $args:tt )* )) => {{ // 7
|
|
|
|
match $f!($i, $($args)*) {
|
|
|
|
// The first one to match is our result.
|
|
|
|
$crate::Result::Complete(i, o) => {
|
|
|
|
Result::Complete(i, o)
|
|
|
|
}
|
|
|
|
// Incompletes may still be parseable.
|
|
|
|
$crate::Result::Incomplete(i) => {
|
|
|
|
Result::Incomplete(i)
|
|
|
|
}
|
|
|
|
// Fail means it didn't match so we are now done.
|
|
|
|
$crate::Result::Fail(e) => {
|
|
|
|
$crate::Result::Fail(e)
|
|
|
|
},
|
|
|
|
// Aborts are hard failures that the parser can't recover from.
|
|
|
|
$crate::Result::Abort(e) => Result::Abort(e),
|
|
|
|
}
|
|
|
|
}};
|
|
|
|
|
|
|
|
// Internal Loop Implementation
|
|
|
|
(__impl $i:expr, $f:ident!( $( $args:tt )* ), $( $rest:tt )* ) => {{ // 8
|
|
|
|
let _i = $i.clone();
|
|
|
|
match $f!($i, $($args)*) {
|
|
|
|
// The first one to match is our result.
|
|
|
|
$crate::Result::Complete(i, o) => {
|
|
|
|
Result::Complete(i, o)
|
|
|
|
}
|
|
|
|
// Incompletes may still be parseable.
|
|
|
|
$crate::Result::Incomplete(i) => {
|
|
|
|
Result::Incomplete(i)
|
|
|
|
}
|
|
|
|
// Fail means it didn't match so continue to next one.
|
|
|
|
$crate::Result::Fail(_) => {
|
|
|
|
either!(__impl _i, $($rest)*)
|
|
|
|
},
|
|
|
|
// Aborts are hard failures that the parser can't recover from.
|
|
|
|
$crate::Result::Abort(e) => Result::Abort(e),
|
|
|
|
}
|
|
|
|
}};
|
|
|
|
|
|
|
|
// Internal Loop Implementation
|
|
|
|
(__impl $i:expr, $f:ident, $( $rest:tt )* ) => { // 9
|
|
|
|
either!(__impl $i, run!($f), $( $rest )* )
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Treats a sub parser as optional. It returns Some(output) for a successful match
|
|
|
|
/// and None for Fails.
|
2018-09-07 21:06:26 -05:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::{Result, Offsetable};
|
|
|
|
/// # fn main() {
|
|
|
|
/// let input_str = "foo";
|
|
|
|
/// let iter = iter::SliceIter::new(input_str.as_bytes());
|
|
|
|
/// let result = optional!(iter, text_token!("foo"));
|
|
|
|
/// # assert!(result.is_complete());
|
|
|
|
/// # if let Result::Complete(_, o) = result {
|
|
|
|
/// # assert_eq!("foo", o.unwrap());
|
|
|
|
/// # } else {
|
|
|
|
/// # assert!(false, "optional! did not complete");
|
|
|
|
/// # }
|
|
|
|
/// # }
|
2018-09-02 22:10:11 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! optional {
|
|
|
|
($i:expr, $f:ident) => {
|
|
|
|
optional!(__impl $i, run!($f))
|
|
|
|
};
|
|
|
|
|
|
|
|
($i:expr, $f:ident!( $( $args:tt )* ) ) => {
|
|
|
|
optional!(__impl $i, $f!( $( $args )* ))
|
|
|
|
};
|
|
|
|
|
|
|
|
(__impl $i:expr, $f:ident!( $( $args:tt )* )) => {{
|
|
|
|
let _i = $i.clone();
|
|
|
|
match $f!($i, $($args)*) {
|
|
|
|
$crate::Result::Complete(i, o) => {
|
|
|
|
Result::Complete(i, Some(o))
|
|
|
|
}
|
|
|
|
// Incomplete could still work possibly parse.
|
|
|
|
$crate::Result::Incomplete(i) => {
|
|
|
|
Result::Incomplete(i)
|
|
|
|
}
|
|
|
|
// Fail just means it didn't match.
|
|
|
|
$crate::Result::Fail(_) => {
|
|
|
|
Result::Complete(_i, None)
|
|
|
|
},
|
|
|
|
// Aborts are hard failures that the parser can't recover from.
|
|
|
|
$crate::Result::Abort(e) => Result::Abort(e),
|
|
|
|
}
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
2018-09-07 21:06:26 -05:00
|
|
|
/// Runs a single matcher repeating 0 or mre times and returns a possibly empty
|
2018-09-02 22:10:11 -05:00
|
|
|
/// vector of the parsed results.
|
2018-09-07 21:06:26 -05:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # #[macro_use] extern crate abortable_parser;
|
|
|
|
/// use abortable_parser::iter;
|
|
|
|
/// # use abortable_parser::{Result, Offsetable};
|
|
|
|
/// # fn main() {
|
|
|
|
/// let input_str = "foofoo";
|
|
|
|
/// let iter = iter::SliceIter::new(input_str.as_bytes());
|
|
|
|
/// let result = repeat!(iter, text_token!("foo"));
|
|
|
|
/// # assert!(result.is_complete());
|
|
|
|
/// if let Result::Complete(_, o) = result {
|
|
|
|
/// assert_eq!(2, o.len());
|
|
|
|
/// assert_eq!("foo", o[0]);
|
|
|
|
/// assert_eq!("foo", o[1]);
|
|
|
|
/// }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2018-09-02 22:10:11 -05:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! repeat {
|
|
|
|
($i:expr, $f:ident!( $( $args:tt )* ) ) => {{
|
|
|
|
let mut _i = $i.clone();
|
|
|
|
let mut seq = Vec::new();
|
|
|
|
let mut opt_error = None;
|
|
|
|
loop {
|
|
|
|
let __i = _i.clone();
|
|
|
|
match $f!(_i, $($args)*) {
|
|
|
|
$crate::Result::Complete(i, o) => {
|
|
|
|
seq.push(o);
|
|
|
|
_i = i;
|
|
|
|
}
|
|
|
|
// Aborts are always a hard fail.
|
|
|
|
$crate::Result::Abort(e) => {
|
|
|
|
opt_error = Some($crate::Result::Abort(e));
|
|
|
|
_i = $i.clone();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Everything else just means we are finished parsing.
|
|
|
|
$crate::Result::Incomplete(_) => {
|
|
|
|
_i = __i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
$crate::Result::Fail(_) => {
|
|
|
|
_i = __i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
match opt_error {
|
|
|
|
Some(e) => e,
|
|
|
|
None => $crate::Result::Complete(_i, seq),
|
|
|
|
}
|
|
|
|
}};
|
|
|
|
|
|
|
|
($i:expr, $f:ident) => {
|
|
|
|
repeat!($i, run!($f))
|
|
|
|
};
|
2018-09-03 00:06:15 -05:00
|
|
|
}
|