blob: 595019d43879bc57358599dd3eba916201c1d5b7 [file] [log] [blame]
Alex Crichton954046c2017-05-30 21:49:42 -07001//! Discrete tokens that can be parsed out by synom.
2//!
3//! This module contains a number of useful tokens like `+=` and `/` along with
4//! keywords like `crate` and such. These structures are used to track the spans
5//! of these tokens and all implment the `ToTokens` and `Synom` traits when the
6//! corresponding feature is activated.
7
Alex Crichton7b9e02f2017-05-30 15:54:33 -07008use span::Span;
9
10macro_rules! tokens {
11 (
12 ops: {
13 $(($($op:tt)*),)*
14 }
15 delim: {
16 $(($($delim:tt)*),)*
17 }
18 syms: {
19 $(($($sym:tt)*),)*
20 }
21 ) => (
22 $(op! { $($op)* })*
23 $(delim! { $($delim)* })*
24 $(sym! { $($sym)* })*
25 )
26}
27
28macro_rules! op {
29 (pub struct $name:ident($($contents:tt)*) => $s:expr) => {
30 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
31 #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
32 #[derive(Default)]
33 pub struct $name(pub $($contents)*);
34
35 #[cfg(feature = "printing")]
36 impl ::quote::ToTokens for $name {
37 fn to_tokens(&self, tokens: &mut ::quote::Tokens) {
38 printing::op($s, &self.0, tokens);
39 }
40 }
41
42 #[cfg(feature = "parsing")]
43 impl ::Synom for $name {
44 fn parse(tokens: &[::proc_macro2::TokenTree])
45 -> ::IResult<&[::proc_macro2::TokenTree], $name>
46 {
47 parsing::op($s, tokens, $name)
48 }
49 }
50 }
51}
52
53macro_rules! sym {
54 (pub struct $name:ident => $s:expr) => {
55 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
56 #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
57 #[derive(Default)]
58 pub struct $name(pub Span);
59
60 #[cfg(feature = "printing")]
61 impl ::quote::ToTokens for $name {
62 fn to_tokens(&self, tokens: &mut ::quote::Tokens) {
63 printing::sym($s, &self.0, tokens);
64 }
65 }
66
67 #[cfg(feature = "parsing")]
68 impl ::Synom for $name {
69 fn parse(tokens: &[::proc_macro2::TokenTree])
70 -> ::IResult<&[::proc_macro2::TokenTree], $name>
71 {
72 parsing::sym($s, tokens, $name)
73 }
74 }
75 }
76}
77
78macro_rules! delim {
79 (pub struct $name:ident => $s:expr) => {
80 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
81 #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
82 #[derive(Default)]
83 pub struct $name(pub Span);
84
85 impl $name {
86 #[cfg(feature = "printing")]
87 pub fn surround<F>(&self,
88 tokens: &mut ::quote::Tokens,
89 f: F)
90 where F: FnOnce(&mut ::quote::Tokens)
91 {
92 printing::delim($s, &self.0, tokens, f);
93 }
94
95 #[cfg(feature = "parsing")]
96 pub fn parse<F, R>(tokens: &[::proc_macro2::TokenTree], f: F)
97 -> ::IResult<&[::proc_macro2::TokenTree], (R, $name)>
98 where F: FnOnce(&[::proc_macro2::TokenTree])
99 -> ::IResult<&[::proc_macro2::TokenTree], R>
100 {
101 parsing::delim($s, tokens, $name, f)
102 }
103 }
104 }
105}
106
107tokens! {
108 ops: {
109 (pub struct Add([Span; 1]) => "+"),
110 (pub struct AddEq([Span; 2]) => "+="),
111 (pub struct And([Span; 1]) => "&"),
112 (pub struct AndAnd([Span; 2]) => "&&"),
113 (pub struct AndEq([Span; 2]) => "&="),
114 (pub struct At([Span; 1]) => "@"),
115 (pub struct Bang([Span; 1]) => "!"),
116 (pub struct Caret([Span; 1]) => "^"),
117 (pub struct CaretEq([Span; 2]) => "^="),
118 (pub struct Colon([Span; 1]) => ":"),
119 (pub struct Colon2([Span; 2]) => "::"),
120 (pub struct Comma([Span; 1]) => ","),
121 (pub struct Div([Span; 1]) => "/"),
122 (pub struct DivEq([Span; 2]) => "/="),
123 (pub struct Dot([Span; 1]) => "."),
124 (pub struct Dot2([Span; 2]) => ".."),
125 (pub struct Dot3([Span; 3]) => "..."),
126 (pub struct Eq([Span; 1]) => "="),
127 (pub struct EqEq([Span; 2]) => "=="),
128 (pub struct Ge([Span; 2]) => ">="),
129 (pub struct Gt([Span; 1]) => ">"),
130 (pub struct Le([Span; 2]) => "<="),
131 (pub struct Lt([Span; 1]) => "<"),
132 (pub struct MulEq([Span; 2]) => "*="),
133 (pub struct Ne([Span; 2]) => "!="),
134 (pub struct Or([Span; 1]) => "|"),
135 (pub struct OrEq([Span; 2]) => "|="),
136 (pub struct OrOr([Span; 2]) => "||"),
137 (pub struct Pound([Span; 1]) => "#"),
138 (pub struct Question([Span; 1]) => "?"),
139 (pub struct RArrow([Span; 2]) => "->"),
140 (pub struct Rem([Span; 1]) => "%"),
141 (pub struct RemEq([Span; 2]) => "%="),
142 (pub struct Rocket([Span; 2]) => "=>"),
143 (pub struct Semi([Span; 1]) => ";"),
144 (pub struct Shl([Span; 2]) => "<<"),
145 (pub struct ShlEq([Span; 3]) => "<<="),
146 (pub struct Shr([Span; 2]) => ">>"),
147 (pub struct ShrEq([Span; 3]) => ">>="),
148 (pub struct Star([Span; 1]) => "*"),
149 (pub struct Sub([Span; 1]) => "-"),
150 (pub struct SubEq([Span; 2]) => "-="),
151 (pub struct Underscore([Span; 1]) => "_"),
152 }
153 delim: {
154 (pub struct Brace => "{"),
155 (pub struct Bracket => "["),
156 (pub struct Paren => "("),
157 }
158 syms: {
159 (pub struct As => "as"),
Alex Crichton954046c2017-05-30 21:49:42 -0700160 (pub struct Box_ => "box"),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700161 (pub struct Break => "break"),
Alex Crichton954046c2017-05-30 21:49:42 -0700162 (pub struct CapSelf => "Self"),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700163 (pub struct Catch => "catch"),
164 (pub struct Const => "const"),
165 (pub struct Continue => "continue"),
166 (pub struct Crate => "crate"),
Alex Crichton954046c2017-05-30 21:49:42 -0700167 (pub struct Default_ => "default"),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700168 (pub struct Do => "do"),
169 (pub struct Else => "else"),
170 (pub struct Enum => "enum"),
171 (pub struct Extern => "extern"),
Alex Crichton954046c2017-05-30 21:49:42 -0700172 (pub struct Fn_ => "fn"),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700173 (pub struct For => "for"),
174 (pub struct If => "if"),
175 (pub struct Impl => "impl"),
176 (pub struct In => "in"),
177 (pub struct Let => "let"),
178 (pub struct Loop => "loop"),
179 (pub struct Match => "match"),
180 (pub struct Mod => "mod"),
181 (pub struct Move => "move"),
182 (pub struct Mut => "mut"),
183 (pub struct Pub => "pub"),
184 (pub struct Ref => "ref"),
185 (pub struct Return => "return"),
186 (pub struct Self_ => "self"),
187 (pub struct Static => "static"),
188 (pub struct Struct => "struct"),
Alex Crichton954046c2017-05-30 21:49:42 -0700189 (pub struct Super => "super"),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700190 (pub struct Trait => "trait"),
191 (pub struct Type => "type"),
192 (pub struct Union => "union"),
193 (pub struct Unsafe => "unsafe"),
194 (pub struct Use => "use"),
195 (pub struct Where => "where"),
196 (pub struct While => "while"),
197 }
198}
199
200#[cfg(feature = "parsing")]
201mod parsing {
Alex Crichton954046c2017-05-30 21:49:42 -0700202 use proc_macro2::{TokenTree, TokenKind, Delimiter, OpKind};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700203
204 use IResult;
205 use span::Span;
206
207 pub trait FromSpans: Sized {
208 fn from_spans(spans: &[Span]) -> Self;
209 }
210
211 impl FromSpans for [Span; 1] {
212 fn from_spans(spans: &[Span]) -> Self {
213 [spans[0]]
214 }
215 }
216
217 impl FromSpans for [Span; 2] {
218 fn from_spans(spans: &[Span]) -> Self {
219 [spans[0], spans[1]]
220 }
221 }
222
223 impl FromSpans for [Span; 3] {
224 fn from_spans(spans: &[Span]) -> Self {
225 [spans[0], spans[1], spans[2]]
226 }
227 }
228
229 pub fn op<'a, T, R>(s: &str,
230 tokens: &'a [TokenTree],
231 new: fn(T) -> R)
232 -> IResult<&'a [TokenTree], R>
233 where T: FromSpans,
234 {
235 let mut spans = [Span::default(); 3];
Alex Crichton954046c2017-05-30 21:49:42 -0700236 assert!(s.len() <= spans.len());
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700237 let chars = s.chars();
238 let mut it = tokens.iter();
239
Alex Crichton954046c2017-05-30 21:49:42 -0700240 for (i, (ch, slot)) in chars.zip(&mut spans).enumerate() {
241 let tok = match it.next() {
242 Some(tok) => tok,
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700243 _ => return IResult::Error
244 };
Alex Crichton954046c2017-05-30 21:49:42 -0700245 let kind = match tok.kind {
246 TokenKind::Op(c, kind) if c == ch => kind,
247 _ => return IResult::Error
248 };
249 if i != s.len() - 1 {
250 match kind {
251 OpKind::Joint => {}
252 OpKind::Alone => return IResult::Error,
253 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700254 }
Alex Crichton954046c2017-05-30 21:49:42 -0700255 *slot = Span(tok.span);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700256 }
257 IResult::Done(it.as_slice(), new(T::from_spans(&spans)))
258 }
259
260 pub fn sym<'a, T>(sym: &str,
261 tokens: &'a [TokenTree],
262 new: fn(Span) -> T)
263 -> IResult<&'a [TokenTree], T>
264 {
265 let mut tokens = tokens.iter();
266 let (span, s) = match tokens.next() {
267 Some(&TokenTree { span, kind: TokenKind::Word(sym) }) => (span, sym),
268 _ => return IResult::Error,
269 };
270 if s.as_str() == sym {
271 IResult::Done(tokens.as_slice(), new(Span(span)))
272 } else {
273 IResult::Error
274 }
275 }
276
277 pub fn delim<'a, F, R, T>(delim: &str,
278 tokens: &'a [TokenTree],
279 new: fn(Span) -> T,
280 f: F)
281 -> ::IResult<&'a [TokenTree], (R, T)>
282 where F: FnOnce(&[TokenTree]) -> IResult<&[TokenTree], R>
283 {
284 let delim = match delim {
285 "(" => Delimiter::Parenthesis,
286 "{" => Delimiter::Brace,
287 "[" => Delimiter::Bracket,
288 _ => panic!("unknown delimiter: {}", delim),
289 };
290 let mut tokens = tokens.iter();
291 let (span, d, others) = match tokens.next() {
292 Some(&TokenTree { span, kind: TokenKind::Sequence(d, ref rest) }) => {
293 (span, d, rest)
294 }
295 _ => return IResult::Error,
296 };
297 match (delim, d) {
298 (Delimiter::Parenthesis, Delimiter::Parenthesis) |
299 (Delimiter::Brace, Delimiter::Brace) |
300 (Delimiter::Bracket, Delimiter::Bracket) => {}
301 _ => return IResult::Error,
302 }
303
304 // TODO: Need a custom type to avoid this allocation every time we try
305 // this branch
306 let rest = others.clone().into_iter().collect::<Vec<_>>();
307 match f(&rest) {
308 IResult::Done(remaining, ret) => {
Alex Crichton954046c2017-05-30 21:49:42 -0700309 if remaining.is_empty() {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700310 IResult::Done(tokens.as_slice(), (ret, new(Span(span))))
311 } else {
312 IResult::Error
313 }
314 }
315 IResult::Error => IResult::Error,
316 }
317 }
318}
319
320#[cfg(feature = "printing")]
321mod printing {
322 use proc_macro2::{TokenTree, TokenKind, OpKind};
323 use quote::Tokens;
324
325 use span::Span;
326
327 pub fn op(s: &str, spans: &[Span], tokens: &mut Tokens) {
328 assert_eq!(s.len(), spans.len());
329
330 let mut chars = s.chars();
331 let mut spans = spans.iter();
332 let ch = chars.next_back().unwrap();
333 let span = spans.next_back().unwrap();
334 for (ch, span) in chars.zip(spans) {
335 tokens.append(TokenTree {
336 span: span.0,
337 kind: TokenKind::Op(ch, OpKind::Joint),
338 });
339 }
340
341 tokens.append(TokenTree {
342 span: span.0,
343 kind: TokenKind::Op(ch, OpKind::Alone),
344 });
345 }
346
347 pub fn sym(s: &str, span: &Span, tokens: &mut Tokens) {
348 tokens.append(TokenTree {
349 span: span.0,
350 kind: TokenKind::Word(s.into()),
351 });
352 }
353
354 pub fn delim<F>(s: &str, span: &Span, tokens: &mut Tokens, f: F)
355 where F: FnOnce(&mut Tokens)
356 {
357 tokens.append_delimited(s, span.0, f)
358 }
359}