]> git.lizzy.rs Git - rust.git/blob - src/libproc_macro/rustc.rs
mv FileMap SourceFile
[rust.git] / src / libproc_macro / rustc.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use {Delimiter, Level, Spacing, Span, __internal};
12 use {Group, Ident, Literal, Punct, TokenTree};
13
14 use rustc_errors as errors;
15 use syntax::ast;
16 use syntax::parse::lexer::comments;
17 use syntax::parse::token;
18 use syntax::tokenstream;
19 use syntax_pos::symbol::{keywords, Symbol};
20
21 impl Ident {
22     pub(crate) fn new_maybe_raw(string: &str, span: Span, is_raw: bool) -> Ident {
23         let sym = Symbol::intern(string);
24         if is_raw
25             && (sym == keywords::Underscore.name()
26                 || ast::Ident::with_empty_ctxt(sym).is_path_segment_keyword())
27         {
28             panic!("`{:?}` is not a valid raw identifier", string)
29         }
30         Ident { sym, span, is_raw }
31     }
32 }
33
34 impl Delimiter {
35     pub(crate) fn from_internal(delim: token::DelimToken) -> Delimiter {
36         match delim {
37             token::Paren => Delimiter::Parenthesis,
38             token::Brace => Delimiter::Brace,
39             token::Bracket => Delimiter::Bracket,
40             token::NoDelim => Delimiter::None,
41         }
42     }
43
44     pub(crate) fn to_internal(self) -> token::DelimToken {
45         match self {
46             Delimiter::Parenthesis => token::Paren,
47             Delimiter::Brace => token::Brace,
48             Delimiter::Bracket => token::Bracket,
49             Delimiter::None => token::NoDelim,
50         }
51     }
52 }
53
54 impl TokenTree {
55     pub(crate) fn from_internal(
56         stream: tokenstream::TokenStream,
57         stack: &mut Vec<TokenTree>,
58     ) -> TokenTree {
59         use syntax::parse::token::*;
60
61         let (tree, is_joint) = stream.as_tree();
62         let (span, token) = match tree {
63             tokenstream::TokenTree::Token(span, token) => (span, token),
64             tokenstream::TokenTree::Delimited(span, delimed) => {
65                 let delimiter = Delimiter::from_internal(delimed.delim);
66                 let mut g = Group::new(delimiter, ::TokenStream(delimed.tts.into()));
67                 g.set_span(Span(span));
68                 return g.into();
69             }
70         };
71
72         let op_kind = if is_joint {
73             Spacing::Joint
74         } else {
75             Spacing::Alone
76         };
77         macro_rules! tt {
78             ($e:expr) => {{
79                 let mut x = TokenTree::from($e);
80                 x.set_span(Span(span));
81                 x
82             }};
83         }
84         macro_rules! op {
85             ($a:expr) => {
86                 tt!(Punct::new($a, op_kind))
87             };
88             ($a:expr, $b:expr) => {{
89                 stack.push(tt!(Punct::new($b, op_kind)));
90                 tt!(Punct::new($a, Spacing::Joint))
91             }};
92             ($a:expr, $b:expr, $c:expr) => {{
93                 stack.push(tt!(Punct::new($c, op_kind)));
94                 stack.push(tt!(Punct::new($b, Spacing::Joint)));
95                 tt!(Punct::new($a, Spacing::Joint))
96             }};
97         }
98
99         match token {
100             Eq => op!('='),
101             Lt => op!('<'),
102             Le => op!('<', '='),
103             EqEq => op!('=', '='),
104             Ne => op!('!', '='),
105             Ge => op!('>', '='),
106             Gt => op!('>'),
107             AndAnd => op!('&', '&'),
108             OrOr => op!('|', '|'),
109             Not => op!('!'),
110             Tilde => op!('~'),
111             BinOp(Plus) => op!('+'),
112             BinOp(Minus) => op!('-'),
113             BinOp(Star) => op!('*'),
114             BinOp(Slash) => op!('/'),
115             BinOp(Percent) => op!('%'),
116             BinOp(Caret) => op!('^'),
117             BinOp(And) => op!('&'),
118             BinOp(Or) => op!('|'),
119             BinOp(Shl) => op!('<', '<'),
120             BinOp(Shr) => op!('>', '>'),
121             BinOpEq(Plus) => op!('+', '='),
122             BinOpEq(Minus) => op!('-', '='),
123             BinOpEq(Star) => op!('*', '='),
124             BinOpEq(Slash) => op!('/', '='),
125             BinOpEq(Percent) => op!('%', '='),
126             BinOpEq(Caret) => op!('^', '='),
127             BinOpEq(And) => op!('&', '='),
128             BinOpEq(Or) => op!('|', '='),
129             BinOpEq(Shl) => op!('<', '<', '='),
130             BinOpEq(Shr) => op!('>', '>', '='),
131             At => op!('@'),
132             Dot => op!('.'),
133             DotDot => op!('.', '.'),
134             DotDotDot => op!('.', '.', '.'),
135             DotDotEq => op!('.', '.', '='),
136             Comma => op!(','),
137             Semi => op!(';'),
138             Colon => op!(':'),
139             ModSep => op!(':', ':'),
140             RArrow => op!('-', '>'),
141             LArrow => op!('<', '-'),
142             FatArrow => op!('=', '>'),
143             Pound => op!('#'),
144             Dollar => op!('$'),
145             Question => op!('?'),
146             SingleQuote => op!('\''),
147
148             Ident(ident, false) => tt!(self::Ident::new(&ident.as_str(), Span(span))),
149             Ident(ident, true) => tt!(self::Ident::new_raw(&ident.as_str(), Span(span))),
150             Lifetime(ident) => {
151                 let ident = ident.without_first_quote();
152                 stack.push(tt!(self::Ident::new(&ident.as_str(), Span(span))));
153                 tt!(Punct::new('\'', Spacing::Joint))
154             }
155             Literal(lit, suffix) => tt!(self::Literal {
156                 lit,
157                 suffix,
158                 span: Span(span)
159             }),
160             DocComment(c) => {
161                 let style = comments::doc_comment_style(&c.as_str());
162                 let stripped = comments::strip_doc_comment_decoration(&c.as_str());
163                 let stream = vec![
164                     tt!(self::Ident::new("doc", Span(span))),
165                     tt!(Punct::new('=', Spacing::Alone)),
166                     tt!(self::Literal::string(&stripped)),
167                 ].into_iter()
168                     .collect();
169                 stack.push(tt!(Group::new(Delimiter::Bracket, stream)));
170                 if style == ast::AttrStyle::Inner {
171                     stack.push(tt!(Punct::new('!', Spacing::Alone)));
172                 }
173                 tt!(Punct::new('#', Spacing::Alone))
174             }
175
176             Interpolated(_) => __internal::with_sess(|sess, _| {
177                 let tts = token.interpolated_to_tokenstream(sess, span);
178                 tt!(Group::new(Delimiter::None, ::TokenStream(tts)))
179             }),
180
181             DotEq => op!('.', '='),
182             OpenDelim(..) | CloseDelim(..) => unreachable!(),
183             Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
184         }
185     }
186
187     pub(crate) fn to_internal(self) -> tokenstream::TokenStream {
188         use syntax::parse::token::*;
189         use syntax::tokenstream::{Delimited, TokenTree};
190
191         let (ch, kind, span) = match self {
192             self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()),
193             self::TokenTree::Group(tt) => {
194                 return TokenTree::Delimited(
195                     tt.span.0,
196                     Delimited {
197                         delim: tt.delimiter.to_internal(),
198                         tts: tt.stream.0.into(),
199                     },
200                 ).into();
201             }
202             self::TokenTree::Ident(tt) => {
203                 let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw);
204                 return TokenTree::Token(tt.span.0, token).into();
205             }
206             self::TokenTree::Literal(self::Literal {
207                 lit: Lit::Integer(ref a),
208                 suffix,
209                 span,
210             })
211                 if a.as_str().starts_with("-") =>
212             {
213                 let minus = BinOp(BinOpToken::Minus);
214                 let integer = Symbol::intern(&a.as_str()[1..]);
215                 let integer = Literal(Lit::Integer(integer), suffix);
216                 let a = TokenTree::Token(span.0, minus);
217                 let b = TokenTree::Token(span.0, integer);
218                 return vec![a, b].into_iter().collect();
219             }
220             self::TokenTree::Literal(self::Literal {
221                 lit: Lit::Float(ref a),
222                 suffix,
223                 span,
224             })
225                 if a.as_str().starts_with("-") =>
226             {
227                 let minus = BinOp(BinOpToken::Minus);
228                 let float = Symbol::intern(&a.as_str()[1..]);
229                 let float = Literal(Lit::Float(float), suffix);
230                 let a = TokenTree::Token(span.0, minus);
231                 let b = TokenTree::Token(span.0, float);
232                 return vec![a, b].into_iter().collect();
233             }
234             self::TokenTree::Literal(tt) => {
235                 let token = Literal(tt.lit, tt.suffix);
236                 return TokenTree::Token(tt.span.0, token).into();
237             }
238         };
239
240         let token = match ch {
241             '=' => Eq,
242             '<' => Lt,
243             '>' => Gt,
244             '!' => Not,
245             '~' => Tilde,
246             '+' => BinOp(Plus),
247             '-' => BinOp(Minus),
248             '*' => BinOp(Star),
249             '/' => BinOp(Slash),
250             '%' => BinOp(Percent),
251             '^' => BinOp(Caret),
252             '&' => BinOp(And),
253             '|' => BinOp(Or),
254             '@' => At,
255             '.' => Dot,
256             ',' => Comma,
257             ';' => Semi,
258             ':' => Colon,
259             '#' => Pound,
260             '$' => Dollar,
261             '?' => Question,
262             '\'' => SingleQuote,
263             _ => unreachable!(),
264         };
265
266         let tree = TokenTree::Token(span.0, token);
267         match kind {
268             Spacing::Alone => tree.into(),
269             Spacing::Joint => tree.joint(),
270         }
271     }
272 }
273
274 impl Level {
275     pub(crate) fn to_internal(self) -> errors::Level {
276         match self {
277             Level::Error => errors::Level::Error,
278             Level::Warning => errors::Level::Warning,
279             Level::Note => errors::Level::Note,
280             Level::Help => errors::Level::Help,
281         }
282     }
283 }