1use primitives::{Consumed, Parser, ParseError, Error, State, Stream};
2use combinator::{Expected, satisfy, Satisfy, skip_many, SkipMany, token, Token, ParserExt, With};
3use std::marker::PhantomData;
4
5pub type ParseResult<O, I> = ::primitives::ParseResult<O, I, char>;
6
7macro_rules! impl_char_parser {
8 ($name: ident ($($ty_var: ident),*), $inner_type: ty) => {
9 #[derive(Clone)]
10 pub struct $name<I $(,$ty_var)*>($inner_type, PhantomData<fn (I) -> I>)
11 where I: Stream<Item=char> $(, $ty_var : Parser<Input=I>)*;
12 impl <I $(,$ty_var)*> Parser for $name<I $(,$ty_var)*>
13 where I: Stream<Item=char> $(, $ty_var : Parser<Input=I>)* {
14 type Input = I;
15 type Output = <$inner_type as Parser>::Output;
16 fn parse_lazy(&mut self, input: State<<Self as Parser>::Input>) -> ParseResult<<Self as Parser>::Output, <Self as Parser>::Input> {
17 self.0.parse_lazy(input)
18 }
19 fn add_error(&mut self, errors: &mut ParseError<<Self::Input as Stream>::Item>) {
20 self.0.add_error(errors)
21 }
22 }
23}
24}
25
26pub fn char<I>(c: char) -> Token<I>
39 where I: Stream<Item=char> {
40 token(c)
41}
42
43impl_char_parser! { Digit(), Expected<Satisfy<I, fn (char) -> bool>> }
44pub fn digit<I>() -> Digit<I>
46 where I: Stream<Item=char> {
47 Digit(satisfy(static_fn!((c, char) -> bool { c.is_digit(10) }))
48 .expected("digit"), PhantomData)
49}
50
51impl_char_parser! { Space(), Expected<Satisfy<I, fn (char) -> bool>> }
52pub fn space<I>() -> Space<I>
54 where I: Stream<Item=char> {
55 let f: fn (char) -> bool = char::is_whitespace;
56 Space(satisfy(f)
57 .expected("whitespace"), PhantomData)
58}
59impl_char_parser! { Spaces(), Expected<SkipMany<Space<I>>> }
60pub fn spaces<I>() -> Spaces<I>
62 where I: Stream<Item=char> {
63 Spaces(skip_many(space())
64 .expected("whitespaces"), PhantomData)
65}
66
67impl_char_parser! { NewLine(), Expected<Satisfy<I, fn (char) -> bool>> }
68pub fn newline<I>() -> NewLine<I>
70 where I: Stream<Item=char> {
71 NewLine(satisfy(static_fn!((ch, char) -> bool { ch == '\n' }))
72 .expected("lf newline"), PhantomData)
73}
74
75impl_char_parser! { CrLf(), Expected<With<Satisfy<I, fn (char) -> bool>, NewLine<I>>> }
76pub fn crlf<I>() -> CrLf<I>
78 where I: Stream<Item=char> {
79 CrLf(satisfy(static_fn!((ch, char) -> bool { ch == '\r' }))
80 .with(newline())
81 .expected("crlf newline"), PhantomData)
82}
83
84impl_char_parser! { Tab(), Expected<Satisfy<I, fn (char) -> bool>> }
85pub fn tab<I>() -> Tab<I>
87 where I: Stream<Item=char> {
88 Tab(satisfy(static_fn!((ch, char) -> bool { ch == '\t' }))
89 .expected("tab"), PhantomData)
90}
91
92impl_char_parser! { Upper(), Expected<Satisfy<I, fn (char) -> bool>> }
93pub fn upper<I>() -> Upper<I>
95 where I: Stream<Item=char> {
96 Upper(satisfy(static_fn!((ch, char) -> bool { ch.is_uppercase()}))
97 .expected("uppercase letter"), PhantomData)
98}
99
100impl_char_parser! { Lower(), Expected<Satisfy<I, fn (char) -> bool>> }
101pub fn lower<I>() -> Lower<I>
103 where I: Stream<Item=char> {
104 Lower(satisfy(static_fn!((ch, char) -> bool { ch.is_lowercase() }))
105 .expected("lowercase letter"), PhantomData)
106}
107
108impl_char_parser! { AlphaNum(), Expected<Satisfy<I, fn (char) -> bool>> }
109pub fn alpha_num<I>() -> AlphaNum<I>
111 where I: Stream<Item=char> {
112 AlphaNum(satisfy(static_fn!((ch, char) -> bool { ch.is_alphanumeric() }))
113 .expected("letter or digit"), PhantomData)
114}
115
116impl_char_parser! { Letter(), Expected<Satisfy<I, fn (char) -> bool>> }
117pub fn letter<I>() -> Letter<I>
119 where I: Stream<Item=char> {
120 Letter(satisfy(static_fn!((ch, char) -> bool { ch.is_alphabetic() }))
121 .expected("letter"), PhantomData)
122}
123
124impl_char_parser! { OctDigit(), Expected<Satisfy<I, fn (char) -> bool>> }
125pub fn oct_digit<I>() -> OctDigit<I>
127 where I: Stream<Item=char> {
128 OctDigit(satisfy(static_fn!((ch, char) -> bool { ch.is_digit(8) }))
129 .expected("octal digit"), PhantomData)
130}
131
132impl_char_parser! { HexDigit(), Expected<Satisfy<I, fn (char) -> bool>> }
133pub fn hex_digit<I>() -> HexDigit<I>
135 where I: Stream<Item=char> {
136 HexDigit(satisfy(static_fn!((ch, char) -> bool { ch.is_digit(0x10) }))
137 .expected("hexadecimal digit"), PhantomData)
138}
139
140
141#[derive(Clone)]
142pub struct String<I>(&'static str, PhantomData<I>);
143impl <I> Parser for String<I>
144 where I: Stream<Item=char> {
145 type Input = I;
146 type Output = &'static str;
147 fn parse_lazy(&mut self, mut input: State<I>) -> ParseResult<&'static str, I> {
148 let start = input.position;
149 let mut consumed = false;
150 for c in self.0.chars() {
151 match input.uncons() {
152 Ok((other, rest)) => {
153 if c != other {
154 return Err(if consumed {
155 let errors = vec![Error::Unexpected(other), Error::Expected(self.0.into())];
156 let error = ParseError::from_errors(start, errors);
157 Consumed::Consumed(error)
158 } else {
159 Consumed::Empty(ParseError::empty(start))
160 })
161 }
162 consumed = true;
163 input = rest.into_inner();
164 }
165 Err(error) => {
166 return error.combine(|mut error| {
167 error.position = start;
168 Err(if consumed { Consumed::Consumed(error) } else { Consumed::Empty(error) })
169 })
170 }
171 }
172 }
173 Ok((self.0, if consumed { Consumed::Consumed(input) } else { Consumed::Empty(input) }))
174 }
175 fn add_error(&mut self, errors: &mut ParseError<<Self::Input as Stream>::Item>) {
176 errors.add_error(Error::Expected(self.0.into()));
177 }
178}
179
180pub fn string<I>(s: &'static str) -> String<I>
193 where I: Stream<Item=char> {
194 String(s, PhantomData)
195}
196
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201 use primitives::{Error, ParseError, Parser, SourcePosition};
202
203 #[test]
204 fn space_error() {
205 let result = space()
206 .parse("");
207 assert!(result.is_err());
208 assert_eq!(result.unwrap_err().errors, vec![Error::Message("End of input".into()), Error::Expected("whitespace".into())]);
209
210 }
211
212 #[test]
213 fn string_consumed() {
214 let result = string("a").parse("b");
215 assert!(result.is_err());
216 assert_eq!(result.unwrap_err().position, SourcePosition { line: 1, column: 1 });
217 }
218
219 #[test]
220 fn string_error() {
221 let result = string("abc").parse("bc");
222 assert_eq!(result, Err(ParseError {
223 position: SourcePosition { line: 1, column: 1 },
224 errors: vec![Error::Unexpected('b'), Error::Expected("abc".into())]
225 }));
226 }
227}