mirror of
https://github.com/zaphar/abortable_parser.git
synced 2025-07-23 20:49:49 -04:00
FEATURE: Add peek and not combinators.
This commit is contained in:
parent
9b3f69d7f4
commit
b8534bc717
@ -25,17 +25,62 @@ macro_rules! text_token {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(jwall): We need until!, not! and peek!.
|
|
||||||
|
// 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.
|
/// Converts a function indentifier into a macro call. Useful when writing your own macro combinator.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! run {
|
macro_rules! run {
|
||||||
($i:expr, $f:ident) => {
|
($i:expr, $f:ident) => {
|
||||||
$f($i)
|
$f($i)
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $f:ident( $( $args:tt )* ) ) => {
|
|
||||||
$f($i, $($args)*)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turns Fails into Aborts. Allows you to turn any parse failure into a hard abort of the parser.
|
/// Turns Fails into Aborts. Allows you to turn any parse failure into a hard abort of the parser.
|
||||||
@ -50,10 +95,6 @@ macro_rules! must {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $f:ident( $( $args:tt )* ) ) => {
|
|
||||||
must!($i, run!($f($($args)*)))
|
|
||||||
};
|
|
||||||
|
|
||||||
($i:expr, $f:ident) => {
|
($i:expr, $f:ident) => {
|
||||||
must!($i, run!($f))
|
must!($i, run!($f))
|
||||||
};
|
};
|
||||||
@ -94,10 +135,6 @@ macro_rules! trap {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $f:ident( $( $args:tt )* ) ) => {
|
|
||||||
trap!($i, run!($f($($args)*)))
|
|
||||||
};
|
|
||||||
|
|
||||||
($i:expr, $f:ident) => {
|
($i:expr, $f:ident) => {
|
||||||
trap!($i, run!($f))
|
trap!($i, run!($f))
|
||||||
};
|
};
|
||||||
@ -117,10 +154,6 @@ macro_rules! must_complete {
|
|||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
($i:expr, $efn:expr, $f:ident( $( $args:tt )* ) ) => {
|
|
||||||
must_complete!($i, $efn, run!($f($($args)*)))
|
|
||||||
};
|
|
||||||
|
|
||||||
($i:expr, $efn:expr, $f:ident) => {
|
($i:expr, $efn:expr, $f:ident) => {
|
||||||
must_complete!($i, $efn, run!($f))
|
must_complete!($i, $efn, run!($f))
|
||||||
};
|
};
|
||||||
@ -173,16 +206,6 @@ macro_rules! do_each {
|
|||||||
do_each!($i, _ => run!($f), $( $rest )* )
|
do_each!($i, _ => run!($f), $( $rest )* )
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $val:ident => $f:ident( $(args:tt)* ), $($rest:tt)* ) => {
|
|
||||||
// If any single one of these matchers fails then all of them are failures.
|
|
||||||
do_each!($i, $val => run!($f($($args)*)), $( $rest )* )
|
|
||||||
};
|
|
||||||
|
|
||||||
($i:expr, _ => $f:ident( $(args:tt)* ), $($rest:tt)* ) => {
|
|
||||||
// If any single one of these matchers fails then all of them are failures.
|
|
||||||
do_each!($i, _ => run!($f($($args)*)), $( $rest )* )
|
|
||||||
};
|
|
||||||
|
|
||||||
// Our Terminal condition
|
// Our Terminal condition
|
||||||
($i:expr, ( $($rest:tt)* ) ) => {
|
($i:expr, ( $($rest:tt)* ) ) => {
|
||||||
Result::Complete($i, ($($rest)*))
|
Result::Complete($i, ($($rest)*))
|
||||||
|
50
src/test.rs
50
src/test.rs
@ -1,4 +1,6 @@
|
|||||||
use super::{Offsetable, Result};
|
use std::fmt::{Display, Debug};
|
||||||
|
|
||||||
|
use super::{InputIter, Offsetable, Result};
|
||||||
use iter::SliceIter;
|
use iter::SliceIter;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -31,22 +33,26 @@ fn test_slice_iter() {
|
|||||||
assert_eq!('o' as u8, out[2]);
|
assert_eq!('o' as u8, out[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn will_fail(i: SliceIter<u8>) -> Result<SliceIter<u8>, String, String> {
|
fn will_fail<I, C>(i: I) -> Result<I, String, String>
|
||||||
|
where I: InputIter<Item=C>, C: Debug + Display {
|
||||||
Result::Fail(super::Error::new("AAAAHHH!!!".to_string(), &i))
|
Result::Fail(super::Error::new("AAAAHHH!!!".to_string(), &i))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_byte(mut i: SliceIter<u8>) -> Result<SliceIter<u8>, u8, String> {
|
fn parse_byte<'a, I>(mut i: I) -> Result<I, u8, String>
|
||||||
|
where I: InputIter<Item=&'a u8> {
|
||||||
match i.next() {
|
match i.next() {
|
||||||
Some(b) => Result::Complete(i, *b),
|
Some(b) => Result::Complete(i, *b),
|
||||||
None => Result::Incomplete(i.get_offset()),
|
None => Result::Incomplete(i.get_offset()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn will_not_complete(_: SliceIter<u8>) -> Result<SliceIter<u8>, String, String> {
|
fn will_not_complete<'a, I>(_: I) -> Result<I, String, String>
|
||||||
|
where I: InputIter<Item=&'a u8> {
|
||||||
Result::Incomplete(0)
|
Result::Incomplete(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_three(i: SliceIter<u8>) -> Result<SliceIter<u8>, String, String> {
|
fn parse_three<'a, I>(i: I) -> Result<I, String, String>
|
||||||
|
where I: InputIter<Item=&'a u8> {
|
||||||
let mut _i = i.clone();
|
let mut _i = i.clone();
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
loop {
|
loop {
|
||||||
@ -66,6 +72,40 @@ fn parse_three(i: SliceIter<u8>) -> Result<SliceIter<u8>, String, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_peek() {
|
||||||
|
let input_str = "foo bar";
|
||||||
|
let iter = SliceIter::new(input_str.as_bytes());
|
||||||
|
let pristine = iter.clone();
|
||||||
|
let result = peek!(iter, text_token!("foo"));
|
||||||
|
assert!(result.is_complete());
|
||||||
|
if let Result::Complete(i, o) = result {
|
||||||
|
assert_eq!(pristine.get_offset(), i.get_offset());
|
||||||
|
assert_eq!("foo", o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_not_success() {
|
||||||
|
let input_str = "foo bar";
|
||||||
|
let iter = SliceIter::new(input_str.as_bytes());
|
||||||
|
let pristine = iter.clone();
|
||||||
|
let result = not!(iter, will_fail);
|
||||||
|
assert!(result.is_complete());
|
||||||
|
if let Result::Complete(i, o) = result {
|
||||||
|
assert_eq!(pristine.get_offset(), i.get_offset());
|
||||||
|
assert_eq!((), o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_not_fail() {
|
||||||
|
let input_str = "foo bar";
|
||||||
|
let iter = SliceIter::new(input_str.as_bytes());
|
||||||
|
let result = not!(iter, text_token!("foo"));
|
||||||
|
assert!(result.is_fail());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_text_token() {
|
fn test_text_token() {
|
||||||
let input_str = "foo bar";
|
let input_str = "foo bar";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user