combine_proc_macro/
parser.rs

1//! A collection of parsers for `Token`s (similar to `combine::parser::{char, byte, item}`).
2
3use crate::input::Token;
4use combine::{ParseError, Parser, Stream, StreamOnce};
5use combine::error::{ConsumedResult, FastResult::*, Info, Tracked};
6use combine::stream::uncons;
7use std::marker::PhantomData;
8
9/// Parses an ident token and returns the inner `proc_macro::Ident`.
10pub fn ident<I>() -> Ident<I>
11where
12    I: Stream<Item = Token>,
13    I::Error: ParseError<I::Item, I::Range, I::Position>,
14{
15    Ident(PhantomData)
16}
17
18#[derive(Copy, Clone)]
19/// Represents the return type of `ident`.
20pub struct Ident<I>(PhantomData<fn(I) -> I>)
21where
22    I: Stream<Item = Token>,
23    I::Error: ParseError<I::Item, I::Range, I::Position>;
24
25impl<I> Parser for Ident<I>
26where
27    I: Stream<Item = Token>,
28    I::Error: ParseError<I::Item, I::Range, I::Position>,
29{
30    type Input = I;
31    type Output = proc_macro2::Ident;
32    type PartialState = ();
33
34    fn parse_lazy(&mut self, input: &mut Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
35        let position = input.position();
36        match uncons(input) {
37            EmptyOk(tok) | ConsumedOk(tok) => match tok {
38                Token::Ident(ident) => ConsumedOk(ident),
39                _ => EmptyErr(I::Error::empty(position).into()),
40            },
41            EmptyErr(err) => EmptyErr(err),
42            ConsumedErr(err) => ConsumedErr(err),
43        }
44    }
45
46    fn add_error(&mut self, errors: &mut Tracked<<Self::Input as StreamOnce>::Error>) {
47        errors.error.add_expected(Info::Borrowed("IDENT"));
48    }
49}
50
51/// Parses an ident token and succeeds if the ident is equal to `word`.
52pub fn keyword<I>(word: &'static str) -> Keyword<I>
53where
54    I: Stream<Item = Token>,
55    I::Error: ParseError<I::Item, I::Range, I::Position>,
56{
57    Keyword(word, PhantomData)
58}
59
60#[derive(Copy, Clone)]
61/// Represents the return type of `keyword`.
62pub struct Keyword<I>(&'static str, PhantomData<fn(I) -> I>)
63where
64    I: Stream<Item = Token>,
65    I::Error: ParseError<I::Item, I::Range, I::Position>;
66
67impl<I> Parser for Keyword<I>
68where
69    I: Stream<Item = Token>,
70    I::Error: ParseError<I::Item, I::Range, I::Position>,
71{
72    type Input = I;
73    type Output = Token;
74    type PartialState = ();
75
76    fn parse_lazy(&mut self, input: &mut Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
77        let position = input.position();
78        match uncons(input) {
79            EmptyOk(tok) | ConsumedOk(tok) => match tok {
80                Token::Ident(ref ident) if ident.to_string() == self.0 => ConsumedOk(tok),
81                _ => EmptyErr(I::Error::empty(position).into()),
82            },
83            EmptyErr(err) => EmptyErr(err),
84            ConsumedErr(err) => ConsumedErr(err),
85        }
86    }
87
88    fn add_error(&mut self, errors: &mut Tracked<<Self::Input as StreamOnce>::Error>) {
89        errors.error.add_expected(Info::Borrowed(self.0));
90    }
91}
92
93/// Parses a literal token (e.g. string, number, etc) and returns the inner `proc_macro::Literal`.
94pub fn literal<I>() -> Literal<I>
95where
96    I: Stream<Item = Token>,
97    I::Error: ParseError<I::Item, I::Range, I::Position>,
98{
99    Literal(PhantomData)
100}
101
102#[derive(Copy, Clone)]
103/// Represents the return type of `literal`.
104pub struct Literal<I>(PhantomData<fn(I) -> I>)
105where
106    I: Stream<Item = Token>,
107    I::Error: ParseError<I::Item, I::Range, I::Position>;
108
109impl<I> Parser for Literal<I>
110where
111    I: Stream<Item = Token>,
112    I::Error: ParseError<I::Item, I::Range, I::Position>,
113{
114    type Input = I;
115    type Output = proc_macro2::Literal;
116    type PartialState = ();
117
118    fn parse_lazy(&mut self, input: &mut Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
119        let position = input.position();
120        match uncons(input) {
121            EmptyOk(tok) | ConsumedOk(tok) => match tok {
122                Token::Literal(lit) => ConsumedOk(lit),
123                _ => EmptyErr(I::Error::empty(position).into()),
124            },
125            EmptyErr(err) => EmptyErr(err),
126            ConsumedErr(err) => ConsumedErr(err),
127        }
128    }
129
130    fn add_error(&mut self, errors: &mut Tracked<<Self::Input as StreamOnce>::Error>) {
131        errors.error.add_expected(Info::Borrowed("LITERAL"));
132    }
133}
134
135/// Parses a punctuation token and succeeds if it's char representation is equal to `c`.
136///
137/// Cannot match delimiter characters (i.e. `(`, `)`, `{`, `}`, `[, `]`).
138/// To match a delimiter use `delim` instead.
139pub fn punct<I>(c: char) -> Punct<I>
140where
141    I: Stream<Item = Token>,
142    I::Error: ParseError<I::Item, I::Range, I::Position>,
143{
144    Punct(c, PhantomData)
145}
146
147#[derive(Copy, Clone)]
148/// Represents the return type of `punct`.
149pub struct Punct<I>(char, PhantomData<fn(I) -> I>)
150where
151    I: Stream<Item = Token>,
152    I::Error: ParseError<I::Item, I::Range, I::Position>;
153
154impl<I> Parser for Punct<I>
155where
156    I: Stream<Item = Token>,
157    I::Error: ParseError<I::Item, I::Range, I::Position>,
158{
159    type Input = I;
160    type Output = Token;
161    type PartialState = ();
162
163    fn parse_lazy(&mut self, input: &mut Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
164        let position = input.position();
165        match uncons(input) {
166            EmptyOk(tok) | ConsumedOk(tok) => match tok {
167                Token::Punct(ref punct) if punct.as_char() == self.0 => ConsumedOk(tok),
168                _ => EmptyErr(I::Error::empty(position).into()),
169            },
170            EmptyErr(err) => EmptyErr(err),
171            ConsumedErr(err) => ConsumedErr(err),
172        }
173    }
174
175    fn add_error(&mut self, errors: &mut Tracked<<Self::Input as StreamOnce>::Error>) {
176        errors.error.add_expected(Info::Token(Token::Punct(proc_macro2::Punct::new(self.0, proc_macro2::Spacing::Alone))));
177    }
178}
179
180
181/// Parses a delimiter if it's char representation is equal to `c`.
182pub fn delim<I>(c: char) -> Delim<I>
183where
184    I: Stream<Item = Token>,
185    I::Error: ParseError<I::Item, I::Range, I::Position>,
186{
187    Delim(c, PhantomData)
188}
189
190#[derive(Copy, Clone)]
191/// Represents the return type of `delim`.
192pub struct Delim<I>(char, PhantomData<fn(I) -> I>)
193where
194    I: Stream<Item = Token>,
195    I::Error: ParseError<I::Item, I::Range, I::Position>;
196
197impl<I> Parser for Delim<I>
198where
199    I: Stream<Item = Token>,
200    I::Error: ParseError<I::Item, I::Range, I::Position>,
201{
202    type Input = I;
203    type Output = Token;
204    type PartialState = ();
205
206    fn parse_lazy(&mut self, input: &mut Self::Input) -> ConsumedResult<Self::Output, Self::Input> {
207        let position = input.position();
208        match uncons(input) {
209            EmptyOk(tok) | ConsumedOk(tok) => match tok {
210                Token::Delim(ch, _) if ch == self.0 => ConsumedOk(tok),
211                _ => EmptyErr(I::Error::empty(position).into()),
212            },
213            EmptyErr(err) => EmptyErr(err),
214            ConsumedErr(err) => ConsumedErr(err),
215        }
216    }
217
218    fn add_error(&mut self, errors: &mut Tracked<<Self::Input as StreamOnce>::Error>) {
219        errors.error.add_expected(Info::Token(Token::Delim(self.0, proc_macro2::Span::call_site())));
220    }
221}