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