//! Various combinators which do not fit anywhere else.
use crate::{
error::{
Info, ParseError,
ParseResult::{self, *},
ResultExt, StreamError, Tracked,
},
lib::{fmt, marker::PhantomData, mem, str},
parser::ParseMode,
stream::{input_at_eof, span::Span, ResetStream, Stream, StreamErrorFor, StreamOnce},
Parser,
};
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, string::String, vec::Vec};
#[cfg(feature = "alloc")]
use crate::lib::any::Any;
#[derive(Copy, Clone)]
pub struct NotFollowedBy
(P);
impl Parser for NotFollowedBy
where
Input: Stream,
P: Parser,
{
type Output = ();
type PartialState = P::PartialState;
parse_mode!(Input);
#[inline]
fn parse_mode_impl(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult::Error>
where
M: ParseMode,
{
let checkpoint = input.checkpoint();
let result = self.0.parse_mode(mode, input, state);
ctry!(input.reset(checkpoint).committed());
match result {
CommitOk(_) | PeekOk(_) => PeekErr(Input::Error::empty(input.position()).into()),
CommitErr(_) | PeekErr(_) => PeekOk(()),
}
}
#[inline]
fn add_error(&mut self, _errors: &mut Tracked<::Error>) {}
fn add_committed_expected_error(&mut self, _error: &mut Tracked<::Error>) {
}
forward_parser!(Input, parser_count, 0);
}
/// Succeeds only if `parser` fails.
/// Never consumes any input.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::parser::char::{alpha_num, string};
/// # fn main() {
/// let result = string("let")
/// .skip(not_followed_by(alpha_num()))
/// .parse("letx")
/// .map(|x| x.0);
/// assert!(result.is_err());
///
/// # }
/// ```
pub fn not_followed_by(parser: P) -> NotFollowedBy
where
Input: Stream,
P: Parser,
P::Output: Into::Token, ::Range, &'static str>>,
{
NotFollowedBy(parser)
}
/*
* TODO :: Rename `Try` to `Attempt`
* Because this is public, it's name cannot be changed without also making a breaking change.
*/
#[derive(Copy, Clone)]
pub struct Try
(P);
impl Parser for Try
where
Input: Stream,
P: Parser,
{
type Output = O;
type PartialState = P::PartialState;
#[inline]
fn parse_stream(&mut self, input: &mut Input) -> ParseResult::Error> {
self.parse_lazy(input)
}
parse_mode!(Input);
#[inline]
fn parse_committed_mode(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult::Error>
where
M: ParseMode,
{
self.parse_mode(mode, input, state)
}
#[inline]
fn parse_mode_impl(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult::Error>
where
M: ParseMode,
{
match self.0.parse_committed_mode(mode, input, state) {
v @ CommitOk(_) | v @ PeekOk(_) | v @ PeekErr(_) => v,
CommitErr(err) => {
if input.is_partial() && err.is_unexpected_end_of_input() {
CommitErr(err)
} else {
PeekErr(err.into())
}
}
}
}
forward_parser!(Input, add_error add_committed_expected_error parser_count, 0);
}
/// `attempt(p)` behaves as `p` except it always acts as `p` peeked instead of committed on its
/// parse.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::parser::char::string;
/// # fn main() {
/// let mut p = attempt(string("let"))
/// .or(string("lex"));
/// let result = p.parse("lex").map(|x| x.0);
/// assert_eq!(result, Ok("lex"));
/// let result = p.parse("aet").map(|x| x.0);
/// assert!(result.is_err());
/// # }
/// ```
pub fn attempt(p: P) -> Try
where
Input: Stream,
P: FnMut() -> R,
R: Parser,
{
type Output = O;
type PartialState = R::PartialState;
fn parse_stream(&mut self, input: &mut Input) -> ParseResult::Error> {
(self.0)().parse_stream(input)
}
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult::Error> {
(self.0)().parse_lazy(input)
}
parse_mode!(Input);
fn parse_committed_mode(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult::Error>
where
M: ParseMode,
{
(self.0)().parse_mode(mode, input, state)
}
fn parse_mode_impl(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult::Error>
where
M: ParseMode,
{
(self.0)().parse_mode_impl(mode, input, state)
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
(self.0)().add_error(errors);
}
fn add_committed_expected_error(&mut self, errors: &mut Tracked<::Error>) {
(self.0)().add_committed_expected_error(errors);
}
}
/// Constructs the parser lazily on each `parse_*` call. Can be used to effectively reduce the
/// size of deeply nested parsers as only the function producing the parser is stored.
///
/// NOTE: Expects that the parser returned is always the same one, if that is not the case the
/// reported error may be wrong. If different parsers may be returned, use the [`factory`][] parser
/// instead.
///
/// [`factory`]: fn.factory.html
pub fn lazy(p: P) -> Lazy
{
fn parser(&mut self, input: &mut Input) -> &mut R
where
P: FnMut(&mut Input) -> R,
{
if let Some(ref mut r) = self.1 {
return r;
}
self.1 = Some((self.0)(input));
self.1.as_mut().unwrap()
}
}
impl Parser for Factory
where
Input: Stream,
P: FnMut(&mut Input) -> R,
R: Parser,
{
type Output = O;
type PartialState = R::PartialState;
parse_mode!(Input);
fn parse_mode_impl(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult::Error>
where
M: ParseMode,
{
// Always ask for a new parser except if we are in a partial call being resumed as we want
// to resume the same parser then
if mode.is_first() {
self.1 = None;
}
self.parser(input).parse_mode_impl(mode, input, state)
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
if let Some(parser) = &mut self.1 {
parser.add_error(errors);
}
}
fn add_committed_expected_error(&mut self, errors: &mut Tracked<::Error>) {
if let Some(parser) = &mut self.1 {
parser.add_committed_expected_error(errors);
}
}
}
/// Constructs the parser lazily on each `parse_*` call. This is similar to [`lazy`][] but it
/// takes `Input` as an argument and allows different parsers to be returned on each call to
/// `p` while still reporting the correct errors.
///
/// [`lazy`]: fn.lazy.html
///
/// ```
/// # use combine::*;
/// # use combine::parser::char::{digit, letter};
/// # use combine::parser::combinator::{FnOpaque, opaque, factory};
///
/// let mut parsers: Vec> = vec![opaque(|f| f(&mut digit())), opaque(|f| f(&mut letter()))];
/// let mut iter = parsers.into_iter().cycle();
/// let mut parser = many(factory(move |_| iter.next().unwrap()));
/// assert_eq!(parser.parse("1a2b3cd"), Ok(("1a2b3c".to_string(), "d")));
/// ```
pub fn factory(p: P) -> Factory
where
Input: Stream,
P: FnMut(&mut Input) -> R,
R: Parser,
{
Factory(p, None)
}
mod internal {
pub trait Sealed {}
}
use self::internal::Sealed;
pub trait StrLike: Sealed {
fn from_utf8(&self) -> Option<&str>;
}
#[cfg(feature = "alloc")]
impl Sealed for String {}
#[cfg(feature = "alloc")]
impl StrLike for String {
fn from_utf8(&self) -> Option<&str> {
Some(self)
}
}
impl<'a> Sealed for &'a str {}
impl<'a> StrLike for &'a str {
fn from_utf8(&self) -> Option<&str> {
Some(*self)
}
}
impl Sealed for str {}
impl StrLike for str {
fn from_utf8(&self) -> Option<&str> {
Some(self)
}
}
#[cfg(feature = "alloc")]
impl Sealed for Vec {}
#[cfg(feature = "alloc")]
impl StrLike for Vec {
fn from_utf8(&self) -> Option<&str> {
(**self).from_utf8()
}
}
impl<'a> Sealed for &'a [u8] {}
impl<'a> StrLike for &'a [u8] {
fn from_utf8(&self) -> Option<&str> {
(**self).from_utf8()
}
}
impl Sealed for [u8] {}
impl StrLike for [u8] {
fn from_utf8(&self) -> Option<&str> {
str::from_utf8(self).ok()
}
}
parser! {
pub struct FromStr;
type PartialState = P::PartialState;
/// Takes a parser that outputs a string like value (`&str`, `String`, `&[u8]` or `Vec`) and parses it
/// using `std::str::FromStr`. Errors if the output of `parser` is not UTF-8 or if
/// `FromStr::from_str` returns an error.
///
/// ```
/// # extern crate combine;
/// # use combine::parser::range;
/// # use combine::parser::repeat::many1;
/// # use combine::parser::combinator::from_str;
/// # use combine::parser::char;
/// # use combine::parser::byte;
/// # use combine::*;
/// # fn main() {
/// let mut parser = from_str(many1::(char::digit()));
/// let result = parser.parse("12345\r\n");
/// assert_eq!(result, Ok((12345i32, "\r\n")));
///
/// // Range parsers work as well
/// let mut parser = from_str(range::take_while1(|c: char| c.is_digit(10)));
/// let result = parser.parse("12345\r\n");
/// assert_eq!(result, Ok((12345i32, "\r\n")));
///
/// // As do parsers that work with bytes
/// let digits = || range::take_while1(|b: u8| b >= b'0' && b <= b'9');
/// let mut parser = from_str(range::recognize((
/// digits(),
/// byte::byte(b'.'),
/// digits(),
/// )));
/// let result = parser.parse(&b"123.45\r\n"[..]);
/// assert_eq!(result, Ok((123.45f64, &b"\r\n"[..])));
/// # }
/// ```
pub fn from_str[Input, O, P](parser: P)(Input) -> O
where [
P: Parser,
P::Output: StrLike,
O: str::FromStr,
O::Err: fmt::Display,
]
{
parser.and_then(|r| {
r.from_utf8()
.ok_or_else(|| StreamErrorFor::::expected_static_message("UTF-8"))
.and_then(|s| s.parse().map_err(StreamErrorFor::::message_format))
})
}
}
#[derive(Copy, Clone)]
pub struct Opaque(F, PhantomData O>);
impl Parser for Opaque
where
Input: Stream,
S: Default,
F: FnMut(&mut dyn FnMut(&mut dyn Parser)),
{
type Output = O;
type PartialState = S;
fn parse_stream(&mut self, input: &mut Input) -> ParseResult::Error> {
let mut x = None;
(self.0)(&mut |parser| x = Some(parser.parse_stream(input)));
x.expect("Parser")
}
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult::Error> {
let mut x = None;
(self.0)(&mut |parser| x = Some(parser.parse_lazy(input)));
x.expect("Parser")
}
parse_mode!(Input);
fn parse_mode_impl(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult::Error>
where
M: ParseMode,
{
let mut x = None;
(self.0)(&mut |parser| {
x = Some(if mode.is_first() {
parser.parse_first(input, state)
} else {
parser.parse_partial(input, state)
})
});
x.expect("Parser")
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
(self.0)(&mut |parser| parser.add_error(errors));
}
fn add_committed_expected_error(&mut self, errors: &mut Tracked<::Error>) {
(self.0)(&mut |parser| parser.add_committed_expected_error(errors));
}
}
/// Alias over `Opaque` where the function can be a plain function pointer (does not need to
/// capture any values)
pub type FnOpaque =
Opaque)), Input, O, S>;
/// Creates a parser from a function which takes a function that are given the actual parser.
/// Though convoluted this makes it possible to hide the concrete parser type without `Box` or
/// losing the full information about the parser as is the case of [`parser`][].
///
/// Since this hides the type this can also be useful for writing mutually recursive `impl Parser`
/// parsers to break the otherwise arbitrarily large type that rustc creates internally.
///
/// If you need a more general version (that does not need trait objects) try the [`parser!`][]
/// macro.
///
/// ```
/// # #[macro_use]
/// # extern crate combine;
/// # use combine::parser::combinator::{FnOpaque, no_partial};
/// # use combine::parser::char::{char, digit};
/// # use combine::*;
///
/// # fn main() {
///
/// #[derive(PartialEq, Debug)]
/// enum Expr {
/// Number(i64),
/// Pair(Box, Box),
/// }
///
/// fn expr() -> FnOpaque
/// where
/// Input: Stream,
/// Input::Error: ParseError,
/// {
/// opaque!(
/// // `no_partial` disables partial parsing and replaces the partial state with `()`,
/// // letting us avoid naming that type
/// no_partial(choice((
/// from_str(many1::(digit()))
/// .map(Expr::Number),
/// (char('('), expr(), char(','), expr(), char(')'))
/// .map(|(_, l, _, r, _)| Expr::Pair(Box::new(l), Box::new(r)))
/// ))),
/// )
/// }
///
/// assert_eq!(
/// expr().easy_parse("123"),
/// Ok((Expr::Number(123), ""))
/// );
///
/// # }
/// ```
///
/// [`parser`]: ../function/fn.parser.html
/// [`parser!`]: ../../macro.parser.html
pub fn opaque(f: F) -> Opaque
where
Input: Stream,
S: Default,
F: FnMut(&mut dyn FnMut(&mut dyn Parser)),
{
Opaque(f, PhantomData)
}
/// Convenience macro over [`opaque`][].
///
/// [`opaque`]: parser/combinator/fn.opaque.html
#[macro_export]
macro_rules! opaque {
($e: expr) => {
$crate::opaque!($e,);
};
($e: expr,) => {
$crate::parser::combinator::opaque(
move |f: &mut dyn FnMut(&mut $crate::Parser<_, Output = _, PartialState = _>)| {
f(&mut $e)
},
)
};
}
pub struct InputConverter
where
InputInner: Stream,
{
pub parser: P,
pub converter: C,
pub _marker: PhantomData,
}
impl Parser for InputConverter
where
Input: Stream,
InputInner: Stream,
P: Parser,
for<'c> C: Converter<'c, Input, InputInner = InputInner>,
{
type Output = P::Output;
type PartialState = P::PartialState;
parse_mode!(Input);
fn parse_mode_impl(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult
where
M: ParseMode,
{
let mut input_inner = match self.converter.convert(input) {
Ok(x) => x,
Err(err) => return PeekErr(err.into()),
};
self.parser
.parse_mode(mode, &mut input_inner, state)
.map_err(|err| self.converter.convert_error(input, err))
}
}
pub trait Converter<'a, Input>
where
Input: Stream,
{
type InputInner: Stream + 'a;
fn convert(&mut self, input: &'a mut Input) -> Result;
fn convert_error(
&mut self,
input: &'a mut Input,
error: ::Error,
) -> Input::Error;
}
impl<'a, Input, InputInner> Converter<'a, Input>
for (
fn(&'a mut Input) -> Result,
fn(&'a mut Input, InputInner::Error) -> Input::Error,
)
where
Input: Stream,
InputInner: Stream + 'a,
{
type InputInner = InputInner;
fn convert(&mut self, input: &'a mut Input) -> Result {
(self.0)(input)
}
fn convert_error(&mut self, input: &'a mut Input, error: InputInner::Error) -> Input::Error {
(self.1)(input, error)
}
}
pub fn input_converter(
parser: P,
converter: C,
) -> InputConverter
where
Input: Stream,
InputInner: Stream,
P: Parser,
for<'c> C: Converter<'c, Input, InputInner = InputInner>,
{
InputConverter {
parser,
converter,
_marker: PhantomData,
}
}
#[derive(Clone)]
pub struct Spanned
(P);
impl Parser for Spanned
where
P: Parser,
Input: Stream>,
Input::Error: ParseError>,
Q: Ord + Clone,
{
type Output = P::Output;
type PartialState = P::PartialState;
parse_mode!(Input);
#[inline]
fn parse_mode_impl(
&mut self,
mode: M,
input: &mut Input,
state: &mut Self::PartialState,
) -> ParseResult::Error>
where
M: ParseMode,
{
let start = input.position().start;
self.0.parse_mode(mode, input, state).map_err(|mut err| {
let error_span = err.position();
// If an inner `spanned` combinator has already attached its span that will be more
// specific so only set a span if the current error has a position, not a span
if error_span.start == error_span.end {
let end = input.position().end;
err.set_position(Span { start, end });
}
err
})
}
forward_parser!(Input, add_error, add_committed_expected_error, 0);
}
/// Equivalent to [`p.spanned()`].
///
/// [`p.spanned()`]: ../trait.Parser.html#method.spanned
pub fn spanned(p: P) -> Spanned