pub use self::error::Error;
use crate::primitives::Primitives;
use crate::types::{Buffer, Input, ParseResult};
pub type SimpleResult<I, T> = ParseResult<I, T, Error<<I as Input>::Token>>;
#[cfg(feature = "backtrace")]
pub use debugtrace::StackFrame;
#[inline]
pub fn any<I: Input>(mut i: I) -> SimpleResult<I, I::Token> {
match i.pop() {
Some(c) => i.ret(c),
None => i.err(Error::unexpected()),
}
}
#[inline]
pub fn satisfy<I: Input, F>(mut i: I, f: F) -> SimpleResult<I, I::Token>
where
F: FnOnce(I::Token) -> bool,
{
match i.peek() {
Some(c) if f(c) => {
i.pop();
i.ret(c)
}
_ => i.err(Error::unexpected()),
}
}
#[inline]
pub fn satisfy_with<I: Input, T: Clone, F, P>(mut i: I, f: F, p: P) -> SimpleResult<I, T>
where
F: FnOnce(I::Token) -> T,
P: FnOnce(T) -> bool,
{
match i.peek().map(f) {
Some(c) => {
if p(c.clone()) {
i.pop();
i.ret(c)
} else {
i.err(Error::unexpected())
}
}
_ => i.err(Error::unexpected()),
}
}
#[inline]
pub fn token<I: Input>(mut i: I, t: I::Token) -> SimpleResult<I, I::Token> {
match i.peek() {
Some(c) if c == t => {
i.pop();
i.ret(c)
}
_ => i.err(Error::expected(t)),
}
}
#[inline]
pub fn not_token<I: Input>(mut i: I, t: I::Token) -> SimpleResult<I, I::Token> {
match i.peek() {
Some(c) if c != t => {
i.pop();
i.ret(c)
}
_ => i.err(Error::unexpected()),
}
}
#[inline]
pub fn peek<I: Input>(mut i: I) -> SimpleResult<I, Option<I::Token>> {
let t = i.peek();
i.ret(t)
}
#[inline]
pub fn peek_next<I: Input>(mut i: I) -> SimpleResult<I, I::Token> {
match i.peek() {
Some(c) => i.ret(c),
None => i.err(Error::unexpected()),
}
}
#[inline]
pub fn take<I: Input>(mut i: I, num: usize) -> SimpleResult<I, I::Buffer> {
match i.consume(num) {
Some(b) => i.ret(b),
None => i.err(Error::unexpected()),
}
}
#[inline]
pub fn take_while<I: Input, F>(mut i: I, f: F) -> SimpleResult<I, I::Buffer>
where
F: FnMut(I::Token) -> bool,
{
let b = i.consume_while(f);
i.ret(b)
}
#[inline]
pub fn take_while1<I: Input, F>(mut i: I, f: F) -> SimpleResult<I, I::Buffer>
where
F: FnMut(I::Token) -> bool,
{
let b = i.consume_while(f);
if b.is_empty() {
i.err(Error::unexpected())
} else {
i.ret(b)
}
}
#[inline]
pub fn skip_while<I: Input, F>(mut i: I, f: F) -> SimpleResult<I, ()>
where
F: FnMut(I::Token) -> bool,
{
i.skip_while(f);
i.ret(())
}
#[inline]
pub fn skip_while1<I: Input, F>(i: I, mut f: F) -> SimpleResult<I, ()>
where
F: FnMut(I::Token) -> bool,
{
satisfy(i, &mut f).then(|i| skip_while(i, f))
}
#[inline]
pub fn take_till<I: Input, F>(mut i: I, mut f: F) -> SimpleResult<I, I::Buffer>
where
F: FnMut(I::Token) -> bool,
{
let mut ok = false;
let b = i.consume_while(|c| {
if f(c) {
ok = true;
false
} else {
true
}
});
if ok {
i.ret(b)
} else {
i.err(Error::unexpected())
}
}
#[inline]
pub fn scan<I: Input, S, F>(mut i: I, s: S, mut f: F) -> SimpleResult<I, I::Buffer>
where
F: FnMut(S, I::Token) -> Option<S>,
{
let mut state = Some(s);
let b = i.consume_while(|c| {
state = f(
state.take().expect(
"scan: Failed to obtain state, consume_while most likely called closure after end",
),
c,
);
state.is_some()
});
i.ret(b)
}
#[inline]
pub fn run_scanner<I: Input, S: Copy, F>(
mut i: I,
s: S,
mut f: F,
) -> SimpleResult<I, (I::Buffer, S)>
where
F: FnMut(S, I::Token) -> Option<S>,
{
let mut state = s;
let b = i.consume_while(|c| {
let t = f(state, c);
match t {
None => false,
Some(v) => {
state = v;
true
}
}
});
i.ret((b, state))
}
#[inline]
pub fn take_remainder<I: Input>(mut i: I) -> SimpleResult<I, I::Buffer> {
let b = i.consume_remaining();
i.ret(b)
}
#[inline]
pub fn string<T: Copy + PartialEq, I: Input<Token = T>>(
mut i: I,
s: &[T],
) -> SimpleResult<I, I::Buffer> {
let mut n = 0;
let len = s.len();
let b = i.consume_while(|c| {
if n >= len || c != s[n] {
false
} else {
n += 1;
true
}
});
if n >= len {
i.ret(b)
} else {
i.err(Error::expected(s[n]))
}
}
#[inline]
pub fn eof<I: Input>(mut i: I) -> SimpleResult<I, ()> {
if i.peek().is_none() {
i.ret(())
} else {
i.err(Error::unexpected())
}
}
mod error {
#[cfg(feature = "std")]
use std::any;
#[cfg(feature = "std")]
use std::error;
use std::fmt;
#[cfg(feature = "noop_error")]
use std::marker::PhantomData;
#[cfg(not(feature = "noop_error"))]
use std::ops::Deref;
use debugtrace::Trace;
#[cfg(feature = "noop_error")]
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct Expected<I>(PhantomData<I>);
#[cfg(feature = "noop_error")]
impl<I: fmt::Debug> fmt::Debug for Expected<I> {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
#[cfg(not(feature = "noop_error"))]
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct Expected<I>(Option<I>);
#[cfg(not(feature = "noop_error"))]
impl<I> Deref for Expected<I> {
type Target = Option<I>;
fn deref(&self) -> &Option<I> {
&self.0
}
}
#[cfg(not(feature = "noop_error"))]
impl<I: fmt::Debug> fmt::Debug for Expected<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(ref c) => write!(f, "Expected({:?})", c),
None => write!(f, "Unexpected"),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Error<I>(Trace<Expected<I>>);
#[cfg(feature = "noop_error")]
impl<I> fmt::Display for Error<I>
where
I: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "parse error")
}
}
#[cfg(not(feature = "noop_error"))]
impl<I> fmt::Display for Error<I>
where
I: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0.as_ref() {
Some(c) => write!(f, "expected {:?}", *c),
None => write!(f, "unexpected"),
}
}
}
#[cfg(feature = "noop_error")]
#[cfg(feature = "std")]
impl<I: any::Any + fmt::Debug> error::Error for Error<I> {
fn description(&self) -> &str {
&"parse error"
}
}
#[cfg(not(feature = "noop_error"))]
#[cfg(feature = "std")]
impl<I: any::Any + fmt::Debug> error::Error for Error<I> {
fn description(&self) -> &str {
match self.0.as_ref() {
Some(_) => "expected a certain token, received another",
None => "received an unexpected token",
}
}
}
#[cfg(feature = "noop_error")]
macro_rules! create_error {
($_e:expr) => {
Error(Trace::new(Expected(PhantomData)))
};
}
#[cfg(not(feature = "noop_error"))]
macro_rules! create_error {
($e:expr) => {
Error(Trace::new(Expected($e)))
};
}
impl<I> Error<I> {
#[inline(always)]
pub fn new() -> Self {
create_error!(None)
}
#[inline(always)]
pub fn unexpected() -> Self {
create_error!(None)
}
#[inline(always)]
#[allow(unused_variables)]
pub fn expected(i: I) -> Self {
create_error!(Some(i))
}
#[inline]
#[cfg(feature = "noop_error")]
pub fn expected_token(&self) -> Option<&I> {
None
}
#[inline]
#[cfg(not(feature = "noop_error"))]
pub fn expected_token(&self) -> Option<&I> {
self.0.as_ref()
}
#[cfg(feature = "backtrace")]
pub fn trace(&self) -> Vec<::debugtrace::StackFrame> {
self.0.resolve()
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::primitives::IntoInner;
use crate::types::{Input, ParseResult};
#[test]
fn parse_decimal() {
fn is_digit(c: u8) -> bool {
c.is_ascii_digit()
}
fn decimal<'i, I: Input<Token = u8, Buffer = &'i [u8]>>(i: I) -> SimpleResult<I, usize> {
take_while1(i, is_digit)
.bind(|i, bytes| i.ret(bytes.iter().fold(0, |a, b| a * 10 + (b - b'0') as usize)))
}
let i = &b"123.4567 "[..];
let p = decimal(i).bind(|i, real| {
token(i, b'.').bind(|i, _| decimal(i).bind(|i, frac| i.ret((real, frac))))
});
let d: ParseResult<_, _, Error<u8>> =
p.bind(|i, num| take_remainder(i).bind(|i, r| i.ret((r, num))));
assert_eq!(d.into_inner(), (&b""[..], Ok((&b" "[..], (123, 4567)))));
}
#[test]
fn parse_remainder_empty() {
assert_eq!(
take_remainder(&b""[..]).into_inner(),
(&b""[..], Ok(&b""[..]))
);
}
#[test]
fn take_while1_empty() {
assert_eq!(
take_while1(&b""[..], |_| true).into_inner(),
(&b""[..], Err(Error::unexpected()))
);
}
#[test]
fn token_test() {
assert_eq!(
token(&b""[..], b'a').into_inner(),
(&b""[..], Err(Error::expected(b'a')))
);
assert_eq!(token(&b"ab"[..], b'a').into_inner(), (&b"b"[..], Ok(b'a')));
assert_eq!(
token(&b"bb"[..], b'a').into_inner(),
(&b"bb"[..], Err(Error::expected(b'a')))
);
}
#[test]
fn take_test() {
assert_eq!(take(&b""[..], 0).into_inner(), (&b""[..], Ok(&b""[..])));
assert_eq!(take(&b"a"[..], 0).into_inner(), (&b"a"[..], Ok(&b""[..])));
assert_eq!(take(&b"a"[..], 1).into_inner(), (&b""[..], Ok(&b"a"[..])));
assert_eq!(
take(&b"a"[..], 2).into_inner(),
(&b"a"[..], Err(Error::unexpected()))
);
assert_eq!(
take(&b"a"[..], 3).into_inner(),
(&b"a"[..], Err(Error::unexpected()))
);
assert_eq!(take(&b"ab"[..], 1).into_inner(), (&b"b"[..], Ok(&b"a"[..])));
assert_eq!(take(&b"ab"[..], 2).into_inner(), (&b""[..], Ok(&b"ab"[..])));
}
#[test]
fn take_while_test() {
assert_eq!(
take_while(&b""[..], |c| c != b'b').into_inner(),
(&b""[..], Ok(&b""[..]))
);
assert_eq!(
take_while(&b"a"[..], |c| c != b'b').into_inner(),
(&b""[..], Ok(&b"a"[..]))
);
assert_eq!(
take_while(&b"b"[..], |c| c != b'b').into_inner(),
(&b"b"[..], Ok(&b""[..]))
);
assert_eq!(
take_while(&b"abc"[..], |c| c != b'b').into_inner(),
(&b"bc"[..], Ok(&b"a"[..]))
);
assert_eq!(
take_while(&b"bbc"[..], |c| c != b'b').into_inner(),
(&b"bbc"[..], Ok(&b""[..]))
);
assert_eq!(
take_while(&b"bbc"[..], |c| c != b'b').into_inner(),
(&b"bbc"[..], Ok(&b""[..]))
);
assert_eq!(
take_while(&b"abc"[..], |c| c != b'b').into_inner(),
(&b"bc"[..], Ok(&b"a"[..]))
);
assert_eq!(
take_while(&b"acc"[..], |c| c != b'b').into_inner(),
(&b""[..], Ok(&b"acc"[..]))
);
}
#[test]
fn take_while1_test() {
assert_eq!(
take_while1(&b""[..], |c| c != b'b').into_inner(),
(&b""[..], Err(Error::unexpected()))
);
assert_eq!(
take_while1(&b"a"[..], |c| c != b'b').into_inner(),
(&b""[..], Ok(&b"a"[..]))
);
assert_eq!(
take_while1(&b"b"[..], |c| c != b'b').into_inner(),
(&b"b"[..], Err(Error::unexpected()))
);
assert_eq!(
take_while1(&b"ab"[..], |c| c != b'b').into_inner(),
(&b"b"[..], Ok(&b"a"[..]))
);
assert_eq!(
take_while1(&b"abc"[..], |c| c != b'b').into_inner(),
(&b"bc"[..], Ok(&b"a"[..]))
);
assert_eq!(
take_while1(&b"bbc"[..], |c| c != b'b').into_inner(),
(&b"bbc"[..], Err(Error::unexpected()))
);
assert_eq!(
take_while1(&b"bbc"[..], |c| c != b'b').into_inner(),
(&b"bbc"[..], Err(Error::unexpected()))
);
assert_eq!(
take_while1(&b"abc"[..], |c| c != b'b').into_inner(),
(&b"bc"[..], Ok(&b"a"[..]))
);
assert_eq!(
take_while1(&b"acc"[..], |c| c != b'b').into_inner(),
(&b""[..], Ok(&b"acc"[..]))
);
}
#[test]
fn peek_next_test() {
assert_eq!(peek_next(&b"abc"[..]).into_inner(), (&b"abc"[..], Ok(b'a')));
assert_eq!(peek_next(&b"abc"[..]).into_inner(), (&b"abc"[..], Ok(b'a')));
assert_eq!(
peek_next(&b""[..]).into_inner(),
(&b""[..], Err(Error::unexpected()))
);
assert_eq!(
peek_next(&b""[..]).into_inner(),
(&b""[..], Err(Error::unexpected()))
);
}
#[test]
fn satisfy_with_test() {
let mut m1 = 0;
let mut n1 = 0;
assert_eq!(
satisfy_with(
&b"abc"[..],
|m| {
m1 += 1;
m % 8
},
|n| {
n1 += 1;
n == 1
}
)
.into_inner(),
(&b"bc"[..], Ok(1))
);
assert_eq!(m1, 1);
assert_eq!(n1, 1);
let mut m2 = 0;
let mut n2 = 0;
assert_eq!(
satisfy_with(
&b""[..],
|m| {
m2 += 1;
m % 8
},
|n| {
n2 += 1;
n == 1
}
)
.into_inner(),
(&b""[..], Err(Error::unexpected()))
);
assert_eq!(m2, 0);
assert_eq!(n2, 0);
}
#[test]
fn string_test() {
assert_eq!(string(&b""[..], b"").into_inner(), (&b""[..], Ok(&b""[..])));
assert_eq!(
string(&b""[..], b"a").into_inner(),
(&b""[..], Err(Error::expected(b'a')))
);
assert_eq!(
string(&b"a"[..], b"a").into_inner(),
(&b""[..], Ok(&b"a"[..]))
);
assert_eq!(
string(&b"b"[..], b"a").into_inner(),
(&b"b"[..], Err(Error::expected(b'a')))
);
assert_eq!(
string(&b"abc"[..], b"a").into_inner(),
(&b"bc"[..], Ok(&b"a"[..]))
);
assert_eq!(
string(&b"abc"[..], b"ab").into_inner(),
(&b"c"[..], Ok(&b"ab"[..]))
);
assert_eq!(
string(&b"abc"[..], b"abc").into_inner(),
(&b""[..], Ok(&b"abc"[..]))
);
assert_eq!(
string(&b"abc"[..], b"abcd").into_inner(),
(&b""[..], Err(Error::expected(b'd')))
);
assert_eq!(
string(&b"abc"[..], b"abcde").into_inner(),
(&b""[..], Err(Error::expected(b'd')))
);
assert_eq!(
string(&b"abc"[..], b"ac").into_inner(),
(&b"bc"[..], Err(Error::expected(b'c')))
);
}
#[test]
fn skip_while1_test() {
assert_eq!(
skip_while1(&b"aaabc"[..], |c| c == b'a').into_inner(),
(&b"bc"[..], Ok(()))
);
assert_eq!(
skip_while1(&b"aabc"[..], |c| c == b'a').into_inner(),
(&b"bc"[..], Ok(()))
);
assert_eq!(
skip_while1(&b"abc"[..], |c| c == b'a').into_inner(),
(&b"bc"[..], Ok(()))
);
assert_eq!(
skip_while1(&b"bc"[..], |c| c == b'a').into_inner(),
(&b"bc"[..], Err(Error::unexpected()))
);
}
#[test]
#[cfg(not(feature = "noop_error"))]
fn error_test() {
let e = Error::<()>::new();
assert_eq!(e.expected_token(), None);
let e = Error::<()>::unexpected();
assert_eq!(e.expected_token(), None);
let e = Error::expected(b'a');
assert_eq!(e.expected_token(), Some(&b'a'));
}
#[test]
#[cfg(feature = "noop_error")]
fn noop_error_test() {
let e = Error::<()>::new();
assert_eq!(e.expected_token(), None);
let e = Error::<()>::unexpected();
assert_eq!(e.expected_token(), None);
let e = Error::expected(b'a');
assert_eq!(e.expected_token(), None);
}
#[test]
#[cfg(feature = "backtrace")]
fn backtrace_test() {
let e = Error::<()>::new();
let trace = e.trace();
let this = &trace[0];
assert!(
this.name
.as_ref()
.map(|n| n.contains("parsers::test::backtrace_test"))
.unwrap_or(false),
"Expected trace to contain \"parsers::test::backtrace_test\", got: {:?}",
this.name.as_ref()
);
}
}