//! Contains the helper macros for abortable-parser. /// Convenience macro for looking for a specific text token in a byte input stream. #[macro_export] macro_rules! text_token { ($i:expr, $e:expr) => {{ use $crate::Error; use $crate::Result; let mut _i = $i.clone(); let mut count = 0; for expected in $e.bytes() { let item = match _i.next() { Some(item) => item, None => break, }; if item == &expected { count += 1; } } if count == $e.len() { Result::Complete(_i.clone(), $e) } else { Result::Fail(Error::new(format!("Expected {} but didn't get it.", $e), &$i)) } }}; } // FIXME(jwall): We need peek!. /// 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 (). #[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)) }; } /// Matches the provided #[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)) }; } /// 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) }; } /// Turns Fails into Aborts. Allows you to turn any parse failure into a hard abort of the parser. #[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)) }; } /// 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. #[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)), } }}; ($i:expr, $f:ident( $( $args:tt )* ), $e:expr ) => { wrap_err!($i, run!($f($($args)*)), $e:expr) }; ($i:expr, $f:ident, $e:expr) => { wrap_err!($i, run!($f), $e) }; } /// Turns Aborts into fails allowing you to trap and then convert an Abort into a normal Fail. #[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)) }; } /// Turns Fails and Incompletes into Aborts. It uses an error factory /// to construct the errors for the Incomplete case. #[macro_export] macro_rules! must_complete { ($i:expr, $e:expr, $f:ident!( $( $args:tt )* ) ) => {{ let _i = $i.clone(); match $f!($i, $($args)*) { $crate::Result::Complete(i, o) => $crate::Result::Complete(i, o), $crate::Result::Incomplete(ref offset) => $crate::Result::Abort($crate::Error::new($e, offset)), $crate::Result::Fail(e) => $crate::Result::Abort(e), $crate::Result::Abort(e) => $crate::Result::Abort(e), } }}; ($i:expr, $efn:expr, $f:ident) => { must_complete!($i, $efn, run!($f)) }; } /// Captures a sequence of sub parsers output. #[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. #[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. #[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), } }}; } /// Runs a single parser repeating 0 or mre times and returns a possibly empty /// vector of the parsed results. #[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)) }; }