//! Parsers constructor from regular functions
use crate::{
error::{ParseResult, StdParseResult},
lib::marker::PhantomData,
stream::Stream,
Parser,
};
impl<'a, Input: Stream, O> Parser
for dyn FnMut(&mut Input) -> StdParseResult + 'a
{
type Output = O;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
self(input).into()
}
}
#[derive(Copy, Clone)]
pub struct FnParser(F, PhantomData Input>);
/// Wraps a function, turning it into a parser.
///
/// Mainly needed to turn closures into parsers as function types can be casted to function pointers
/// to make them usable as a parser.
///
/// ```
/// extern crate combine;
/// # use combine::*;
/// # use combine::parser::char::digit;
/// # use combine::error::{Commit, StreamError};
/// # use combine::stream::easy;
/// # fn main() {
/// let mut even_digit = parser(|input| {
/// // Help type inference out
/// let _: &mut easy::Stream<&str> = input;
/// let position = input.position();
/// let (char_digit, committed) = digit().parse_stream(input).into_result()?;
/// let d = (char_digit as i32) - ('0' as i32);
/// if d % 2 == 0 {
/// Ok((d, committed))
/// }
/// else {
/// //Return an empty error since we only tested the first token of the stream
/// let errors = easy::Errors::new(
/// position,
/// StreamError::expected("even number")
/// );
/// Err(Commit::Peek(errors.into()))
/// }
/// });
/// let result = even_digit
/// .easy_parse("8")
/// .map(|x| x.0);
/// assert_eq!(result, Ok(8));
/// # }
/// ```
pub fn parser(f: F) -> FnParser
where
Input: Stream,
F: FnMut(&mut Input) -> StdParseResult,
{
FnParser(f, PhantomData)
}
impl Parser for FnParser
where
Input: Stream,
F: FnMut(&mut Input) -> StdParseResult,
{
type Output = O;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
(self.0)(input).into()
}
}
impl Parser for fn(&mut Input) -> StdParseResult
where
Input: Stream,
{
type Output = O;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
self(input).into()
}
}
#[derive(Copy)]
pub struct EnvParser
where
Input: Stream,
{
env: E,
parser: fn(E, &mut Input) -> StdParseResult,
}
impl Clone for EnvParser
where
Input: Stream,
E: Clone,
{
fn clone(&self) -> Self {
EnvParser {
env: self.env.clone(),
parser: self.parser,
}
}
}
impl Parser for EnvParser
where
E: Clone,
Input: Stream,
{
type Output = O;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
(self.parser)(self.env.clone(), input).into()
}
}
/// Constructs a parser out of an environment and a function which needs the given environment to
/// do the parsing. This is commonly useful to allow multiple parsers to share some environment
/// while still allowing the parsers to be written in separate functions.
///
/// ```
/// # extern crate combine;
/// # use std::collections::HashMap;
/// # use combine::*;
/// # use combine::parser::function::env_parser;
/// # use combine::parser::char::letter;
/// # fn main() {
/// struct Interner(HashMap);
/// impl Interner {
/// fn string(&self, input: &mut Input) -> StdParseResult
/// where Input: Stream,
/// {
/// many(letter())
/// .map(|s: String| self.0.get(&s).cloned().unwrap_or(0))
/// .parse_stream(input)
/// .into_result()
/// }
/// }
///
/// let mut map = HashMap::new();
/// map.insert("hello".into(), 1);
/// map.insert("test".into(), 2);
///
/// let env = Interner(map);
/// let mut parser = env_parser(&env, Interner::string);
///
/// let result = parser.parse("hello");
/// assert_eq!(result, Ok((1, "")));
///
/// let result = parser.parse("world");
/// assert_eq!(result, Ok((0, "")));
/// # }
/// ```
pub fn env_parser(
env: E,
parser: fn(E, &mut Input) -> StdParseResult,
) -> EnvParser
where
E: Clone,
Input: Stream,
{
EnvParser { env, parser }
}