use crate::{InputToken, Parser};
pub fn look_ahead<P, IT, O>(parser: &P) -> impl Parser<IT, O>
where
P: Parser<IT, O>,
IT: InputToken,
{
|input| {
let handler = input.start_look_ahead();
let output = parser(input);
input.stop_look_ahead(handler, output.is_ok());
output
}
}
#[cfg(test)]
mod tests {
use crate::input::Position;
use crate::*;
#[test]
fn empty() {
let parser = is('h');
let mut input = Input::new_from_chars("".chars(), None);
let parse_look_ahead = look_ahead(&parser)(&mut input);
assert_eq!(
parse_look_ahead,
Err(Error::EndOfInput(Some(Box::new('h'))))
);
}
#[test]
fn success_does_not_consume() {
let parser = is('h');
let mut input = Input::new_from_chars("hello".chars(), None);
let output = look_ahead(&parser)(&mut input);
assert_eq!(output, Ok('h'));
assert_eq!(is('h')(&mut input), Ok('h'));
assert_eq!(is('e')(&mut input), Ok('e'));
assert_eq!(is('l')(&mut input), Ok('l'));
assert_eq!(is('l')(&mut input), Ok('l'));
assert_eq!(is('o')(&mut input), Ok('o'));
assert!(end_of_input()(&mut input).is_ok());
}
#[test]
fn non_consuming_fail_does_not_consume() {
let parser = is('h');
let mut input = Input::new_from_chars("j".chars(), None);
let output = look_ahead(&parser)(&mut input);
let mismatch = Mismatch::new('h', 'j');
assert_eq!(
output,
Err(Error::UnexpectedToken(
None,
Position::new(1, 1),
Some(mismatch)
))
);
assert_eq!(any()(&mut input), Ok('j'));
assert!(end_of_input()(&mut input).is_ok());
}
#[test]
fn consuming_fail_consumes() {
let mut input = Input::new_from_chars("he".chars(), None);
let parser = |input: &mut Input<_>| {
let output1 = is('h')(input)?; let output2 = is('a')(input)?; Ok((output1, output2))
};
let output = look_ahead(&parser)(&mut input);
let mismatch = Mismatch::new('a', 'e');
assert_eq!(
output,
Err(Error::UnexpectedToken(
None,
Position::new(1, 2),
Some(mismatch)
))
);
assert_eq!(any()(&mut input), Ok('e'));
assert!(end_of_input()(&mut input).is_ok());
}
#[test]
fn parse_does_not_consume_on_failure() {
let parser = is('h');
let mut input = Input::new_from_chars("jello".chars(), None);
let result = look_ahead(&parser)(&mut input);
let mismatch = Mismatch::new('h', 'j');
assert_eq!(
result,
Err(Error::UnexpectedToken(
None,
Position::new(1, 1),
Some(mismatch)
))
);
assert_eq!(is('j')(&mut input), Ok('j'));
assert_eq!(is('e')(&mut input), Ok('e'));
assert_eq!(is('l')(&mut input), Ok('l'));
assert_eq!(is('l')(&mut input), Ok('l'));
assert_eq!(is('o')(&mut input), Ok('o'));
assert!(end_of_input()(&mut input).is_ok());
}
#[test]
fn parse_look_ahead_twice() {
let parser = is('h');
let mut input = Input::new_from_chars("h".chars(), None);
let first = look_ahead(&parser)(&mut input);
let second = look_ahead(&parser)(&mut input);
assert_eq!(first, Ok('h'));
assert_eq!(second, Ok('h'));
assert!(end_of_input()(&mut input).is_err()); }
}