combine/parser/function.rs
1//! Parsers constructor from regular functions
2
3use crate::{
4 error::{ParseResult, StdParseResult},
5 lib::marker::PhantomData,
6 stream::Stream,
7 Parser,
8};
9
10impl<'a, Input: Stream, O> Parser<Input>
11 for dyn FnMut(&mut Input) -> StdParseResult<O, Input> + 'a
12{
13 type Output = O;
14 type PartialState = ();
15
16 #[inline]
17 fn parse_lazy(&mut self, input: &mut Input) -> ParseResult<O, Input::Error> {
18 self(input).into()
19 }
20}
21
22#[derive(Copy, Clone)]
23pub struct FnParser<Input, F>(F, PhantomData<fn(Input) -> Input>);
24
25/// Wraps a function, turning it into a parser.
26///
27/// Mainly needed to turn closures into parsers as function types can be casted to function pointers
28/// to make them usable as a parser.
29///
30/// ```
31/// extern crate combine;
32/// # use combine::*;
33/// # use combine::parser::char::digit;
34/// # use combine::error::{Commit, StreamError};
35/// # use combine::stream::easy;
36/// # fn main() {
37/// let mut even_digit = parser(|input| {
38/// // Help type inference out
39/// let _: &mut easy::Stream<&str> = input;
40/// let position = input.position();
41/// let (char_digit, committed) = digit().parse_stream(input).into_result()?;
42/// let d = (char_digit as i32) - ('0' as i32);
43/// if d % 2 == 0 {
44/// Ok((d, committed))
45/// }
46/// else {
47/// //Return an empty error since we only tested the first token of the stream
48/// let errors = easy::Errors::new(
49/// position,
50/// StreamError::expected("even number")
51/// );
52/// Err(Commit::Peek(errors.into()))
53/// }
54/// });
55/// let result = even_digit
56/// .easy_parse("8")
57/// .map(|x| x.0);
58/// assert_eq!(result, Ok(8));
59/// # }
60/// ```
61pub fn parser<Input, O, F>(f: F) -> FnParser<Input, F>
62where
63 Input: Stream,
64 F: FnMut(&mut Input) -> StdParseResult<O, Input>,
65{
66 FnParser(f, PhantomData)
67}
68
69impl<Input, O, F> Parser<Input> for FnParser<Input, F>
70where
71 Input: Stream,
72 F: FnMut(&mut Input) -> StdParseResult<O, Input>,
73{
74 type Output = O;
75 type PartialState = ();
76
77 #[inline]
78 fn parse_lazy(&mut self, input: &mut Input) -> ParseResult<O, Input::Error> {
79 (self.0)(input).into()
80 }
81}
82
83impl<Input, O> Parser<Input> for fn(&mut Input) -> StdParseResult<O, Input>
84where
85 Input: Stream,
86{
87 type Output = O;
88 type PartialState = ();
89
90 #[inline]
91 fn parse_lazy(&mut self, input: &mut Input) -> ParseResult<O, Input::Error> {
92 self(input).into()
93 }
94}
95
96#[derive(Copy)]
97pub struct EnvParser<E, Input, T>
98where
99 Input: Stream,
100{
101 env: E,
102 parser: fn(E, &mut Input) -> StdParseResult<T, Input>,
103}
104
105impl<E, Input, T> Clone for EnvParser<E, Input, T>
106where
107 Input: Stream,
108 E: Clone,
109{
110 fn clone(&self) -> Self {
111 EnvParser {
112 env: self.env.clone(),
113 parser: self.parser,
114 }
115 }
116}
117
118impl<Input, E, O> Parser<Input> for EnvParser<E, Input, O>
119where
120 E: Clone,
121 Input: Stream,
122{
123 type Output = O;
124 type PartialState = ();
125
126 #[inline]
127 fn parse_lazy(&mut self, input: &mut Input) -> ParseResult<O, Input::Error> {
128 (self.parser)(self.env.clone(), input).into()
129 }
130}
131
132/// Constructs a parser out of an environment and a function which needs the given environment to
133/// do the parsing. This is commonly useful to allow multiple parsers to share some environment
134/// while still allowing the parsers to be written in separate functions.
135///
136/// ```
137/// # extern crate combine;
138/// # use std::collections::HashMap;
139/// # use combine::*;
140/// # use combine::parser::function::env_parser;
141/// # use combine::parser::char::letter;
142/// # fn main() {
143/// struct Interner(HashMap<String, u32>);
144/// impl Interner {
145/// fn string<Input>(&self, input: &mut Input) -> StdParseResult<u32, Input>
146/// where Input: Stream<Token = char>,
147/// {
148/// many(letter())
149/// .map(|s: String| self.0.get(&s).cloned().unwrap_or(0))
150/// .parse_stream(input)
151/// .into_result()
152/// }
153/// }
154///
155/// let mut map = HashMap::new();
156/// map.insert("hello".into(), 1);
157/// map.insert("test".into(), 2);
158///
159/// let env = Interner(map);
160/// let mut parser = env_parser(&env, Interner::string);
161///
162/// let result = parser.parse("hello");
163/// assert_eq!(result, Ok((1, "")));
164///
165/// let result = parser.parse("world");
166/// assert_eq!(result, Ok((0, "")));
167/// # }
168/// ```
169pub fn env_parser<E, Input, O>(
170 env: E,
171 parser: fn(E, &mut Input) -> StdParseResult<O, Input>,
172) -> EnvParser<E, Input, O>
173where
174 E: Clone,
175 Input: Stream,
176{
177 EnvParser { env, parser }
178}