]>
Commit | Line | Data |
---|---|---|
3c0e092e | 1 | use crate::base::ExtCtxt; |
2b03887a FG |
2 | use pm::bridge::{ |
3 | server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree, | |
4 | }; | |
5 | use pm::{Delimiter, Level, LineColumn}; | |
3dfed10e | 6 | use rustc_ast as ast; |
5e7ed085 | 7 | use rustc_ast::token; |
064997fb | 8 | use rustc_ast::tokenstream::{self, Spacing::*, TokenStream}; |
74b04a01 | 9 | use rustc_ast_pretty::pprust; |
17df50a5 | 10 | use rustc_data_structures::fx::FxHashMap; |
dfeec247 | 11 | use rustc_data_structures::sync::Lrc; |
f2b60f7d | 12 | use rustc_errors::{MultiSpan, PResult}; |
dfeec247 | 13 | use rustc_parse::lexer::nfc_normalize; |
923072b8 | 14 | use rustc_parse::parse_stream_from_source_str; |
74b04a01 | 15 | use rustc_session::parse::ParseSess; |
17df50a5 | 16 | use rustc_span::def_id::CrateNum; |
064997fb | 17 | use rustc_span::symbol::{self, sym, Symbol}; |
04454e1e | 18 | use rustc_span::{BytePos, FileName, Pos, SourceFile, Span}; |
2b03887a | 19 | use smallvec::{smallvec, SmallVec}; |
416331ca | 20 | use std::ops::Bound; |
a1dfa0c6 XL |
21 | |
22 | trait FromInternal<T> { | |
23 | fn from_internal(x: T) -> Self; | |
24 | } | |
25 | ||
26 | trait ToInternal<T> { | |
27 | fn to_internal(self) -> T; | |
28 | } | |
29 | ||
04454e1e FG |
30 | impl FromInternal<token::Delimiter> for Delimiter { |
31 | fn from_internal(delim: token::Delimiter) -> Delimiter { | |
a1dfa0c6 | 32 | match delim { |
04454e1e FG |
33 | token::Delimiter::Parenthesis => Delimiter::Parenthesis, |
34 | token::Delimiter::Brace => Delimiter::Brace, | |
35 | token::Delimiter::Bracket => Delimiter::Bracket, | |
36 | token::Delimiter::Invisible => Delimiter::None, | |
a1dfa0c6 XL |
37 | } |
38 | } | |
39 | } | |
40 | ||
04454e1e FG |
41 | impl ToInternal<token::Delimiter> for Delimiter { |
42 | fn to_internal(self) -> token::Delimiter { | |
a1dfa0c6 | 43 | match self { |
04454e1e FG |
44 | Delimiter::Parenthesis => token::Delimiter::Parenthesis, |
45 | Delimiter::Brace => token::Delimiter::Brace, | |
46 | Delimiter::Bracket => token::Delimiter::Bracket, | |
47 | Delimiter::None => token::Delimiter::Invisible, | |
a1dfa0c6 XL |
48 | } |
49 | } | |
50 | } | |
51 | ||
064997fb FG |
52 | impl FromInternal<token::LitKind> for LitKind { |
53 | fn from_internal(kind: token::LitKind) -> Self { | |
54 | match kind { | |
55 | token::Byte => LitKind::Byte, | |
56 | token::Char => LitKind::Char, | |
57 | token::Integer => LitKind::Integer, | |
58 | token::Float => LitKind::Float, | |
59 | token::Str => LitKind::Str, | |
60 | token::StrRaw(n) => LitKind::StrRaw(n), | |
61 | token::ByteStr => LitKind::ByteStr, | |
62 | token::ByteStrRaw(n) => LitKind::ByteStrRaw(n), | |
63 | token::Err => LitKind::Err, | |
64 | token::Bool => unreachable!(), | |
65 | } | |
66 | } | |
67 | } | |
68 | ||
69 | impl ToInternal<token::LitKind> for LitKind { | |
70 | fn to_internal(self) -> token::LitKind { | |
71 | match self { | |
72 | LitKind::Byte => token::Byte, | |
73 | LitKind::Char => token::Char, | |
74 | LitKind::Integer => token::Integer, | |
75 | LitKind::Float => token::Float, | |
76 | LitKind::Str => token::Str, | |
77 | LitKind::StrRaw(n) => token::StrRaw(n), | |
78 | LitKind::ByteStr => token::ByteStr, | |
79 | LitKind::ByteStrRaw(n) => token::ByteStrRaw(n), | |
80 | LitKind::Err => token::Err, | |
81 | } | |
82 | } | |
83 | } | |
84 | ||
85 | impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStream, Span, Symbol>> { | |
86 | fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self { | |
74b04a01 | 87 | use rustc_ast::token::*; |
a1dfa0c6 | 88 | |
064997fb FG |
89 | // Estimate the capacity as `stream.len()` rounded up to the next power |
90 | // of two to limit the number of required reallocations. | |
91 | let mut trees = Vec::with_capacity(stream.len().next_power_of_two()); | |
92 | let mut cursor = stream.into_trees(); | |
a1dfa0c6 | 93 | |
064997fb FG |
94 | while let Some(tree) = cursor.next() { |
95 | let (Token { kind, span }, joint) = match tree { | |
96 | tokenstream::TokenTree::Delimited(span, delim, tts) => { | |
97 | let delimiter = pm::Delimiter::from_internal(delim); | |
98 | trees.push(TokenTree::Group(Group { | |
99 | delimiter, | |
100 | stream: Some(tts), | |
101 | span: DelimSpan { | |
102 | open: span.open, | |
103 | close: span.close, | |
104 | entire: span.entire(), | |
105 | }, | |
106 | })); | |
107 | continue; | |
108 | } | |
109 | tokenstream::TokenTree::Token(token, spacing) => (token, spacing == Joint), | |
a1dfa0c6 | 110 | }; |
a1dfa0c6 | 111 | |
2b03887a FG |
112 | // Split the operator into one or more `Punct`s, one per character. |
113 | // The final one inherits the jointness of the original token. Any | |
114 | // before that get `joint = true`. | |
064997fb FG |
115 | let mut op = |s: &str| { |
116 | assert!(s.is_ascii()); | |
2b03887a FG |
117 | trees.extend(s.bytes().enumerate().map(|(i, ch)| { |
118 | let is_final = i == s.len() - 1; | |
119 | // Split the token span into single chars. Unless the span | |
120 | // is an unusual one, e.g. due to proc macro expansion. We | |
121 | // determine this by assuming any span with a length that | |
122 | // matches the operator length is a normal one, and any | |
123 | // span with a different length is an unusual one. | |
124 | let span = if (span.hi() - span.lo()).to_usize() == s.len() { | |
125 | let lo = span.lo() + BytePos::from_usize(i); | |
126 | let hi = lo + BytePos::from_usize(1); | |
127 | span.with_lo(lo).with_hi(hi) | |
128 | } else { | |
129 | span | |
130 | }; | |
131 | TokenTree::Punct(Punct { ch, joint: if is_final { joint } else { true }, span }) | |
a1dfa0c6 | 132 | })); |
064997fb FG |
133 | }; |
134 | ||
135 | match kind { | |
136 | Eq => op("="), | |
137 | Lt => op("<"), | |
138 | Le => op("<="), | |
139 | EqEq => op("=="), | |
140 | Ne => op("!="), | |
141 | Ge => op(">="), | |
142 | Gt => op(">"), | |
143 | AndAnd => op("&&"), | |
144 | OrOr => op("||"), | |
145 | Not => op("!"), | |
146 | Tilde => op("~"), | |
147 | BinOp(Plus) => op("+"), | |
148 | BinOp(Minus) => op("-"), | |
149 | BinOp(Star) => op("*"), | |
150 | BinOp(Slash) => op("/"), | |
151 | BinOp(Percent) => op("%"), | |
152 | BinOp(Caret) => op("^"), | |
153 | BinOp(And) => op("&"), | |
154 | BinOp(Or) => op("|"), | |
155 | BinOp(Shl) => op("<<"), | |
156 | BinOp(Shr) => op(">>"), | |
157 | BinOpEq(Plus) => op("+="), | |
158 | BinOpEq(Minus) => op("-="), | |
159 | BinOpEq(Star) => op("*="), | |
160 | BinOpEq(Slash) => op("/="), | |
161 | BinOpEq(Percent) => op("%="), | |
162 | BinOpEq(Caret) => op("^="), | |
163 | BinOpEq(And) => op("&="), | |
164 | BinOpEq(Or) => op("|="), | |
165 | BinOpEq(Shl) => op("<<="), | |
166 | BinOpEq(Shr) => op(">>="), | |
167 | At => op("@"), | |
168 | Dot => op("."), | |
169 | DotDot => op(".."), | |
170 | DotDotDot => op("..."), | |
171 | DotDotEq => op("..="), | |
172 | Comma => op(","), | |
173 | Semi => op(";"), | |
174 | Colon => op(":"), | |
175 | ModSep => op("::"), | |
176 | RArrow => op("->"), | |
177 | LArrow => op("<-"), | |
178 | FatArrow => op("=>"), | |
179 | Pound => op("#"), | |
180 | Dollar => op("$"), | |
181 | Question => op("?"), | |
182 | SingleQuote => op("'"), | |
183 | ||
184 | Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident { sym, is_raw, span })), | |
185 | Lifetime(name) => { | |
186 | let ident = symbol::Ident::new(name, span).without_first_quote(); | |
187 | trees.extend([ | |
188 | TokenTree::Punct(Punct { ch: b'\'', joint: true, span }), | |
189 | TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }), | |
190 | ]); | |
191 | } | |
192 | Literal(token::Lit { kind, symbol, suffix }) => { | |
193 | trees.push(TokenTree::Literal(self::Literal { | |
194 | kind: FromInternal::from_internal(kind), | |
195 | symbol, | |
196 | suffix, | |
197 | span, | |
198 | })); | |
199 | } | |
200 | DocComment(_, attr_style, data) => { | |
201 | let mut escaped = String::new(); | |
202 | for ch in data.as_str().chars() { | |
203 | escaped.extend(ch.escape_debug()); | |
204 | } | |
205 | let stream = [ | |
206 | Ident(sym::doc, false), | |
207 | Eq, | |
208 | TokenKind::lit(token::Str, Symbol::intern(&escaped), None), | |
209 | ] | |
210 | .into_iter() | |
211 | .map(|kind| tokenstream::TokenTree::token_alone(kind, span)) | |
212 | .collect(); | |
213 | trees.push(TokenTree::Punct(Punct { ch: b'#', joint: false, span })); | |
214 | if attr_style == ast::AttrStyle::Inner { | |
215 | trees.push(TokenTree::Punct(Punct { ch: b'!', joint: false, span })); | |
216 | } | |
217 | trees.push(TokenTree::Group(Group { | |
218 | delimiter: pm::Delimiter::Bracket, | |
219 | stream: Some(stream), | |
220 | span: DelimSpan::from_single(span), | |
221 | })); | |
a1dfa0c6 | 222 | } |
a1dfa0c6 | 223 | |
064997fb FG |
224 | Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => { |
225 | trees.push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })) | |
226 | } | |
227 | ||
228 | Interpolated(nt) => { | |
229 | let stream = TokenStream::from_nonterminal_ast(&nt); | |
230 | // A hack used to pass AST fragments to attribute and derive | |
231 | // macros as a single nonterminal token instead of a token | |
232 | // stream. Such token needs to be "unwrapped" and not | |
233 | // represented as a delimited group. | |
234 | // FIXME: It needs to be removed, but there are some | |
235 | // compatibility issues (see #73345). | |
236 | if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()) { | |
237 | trees.extend(Self::from_internal((stream, rustc))); | |
238 | } else { | |
239 | trees.push(TokenTree::Group(Group { | |
240 | delimiter: pm::Delimiter::None, | |
241 | stream: Some(stream), | |
242 | span: DelimSpan::from_single(span), | |
243 | })) | |
244 | } | |
245 | } | |
a1dfa0c6 | 246 | |
064997fb FG |
247 | OpenDelim(..) | CloseDelim(..) => unreachable!(), |
248 | Eof => unreachable!(), | |
249 | } | |
a1dfa0c6 | 250 | } |
064997fb | 251 | trees |
a1dfa0c6 XL |
252 | } |
253 | } | |
254 | ||
2b03887a FG |
255 | // We use a `SmallVec` because the output size is always one or two `TokenTree`s. |
256 | impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>> | |
257 | for (TokenTree<TokenStream, Span, Symbol>, &mut Rustc<'_, '_>) | |
258 | { | |
259 | fn to_internal(self) -> SmallVec<[tokenstream::TokenTree; 2]> { | |
74b04a01 | 260 | use rustc_ast::token::*; |
a1dfa0c6 | 261 | |
064997fb | 262 | let (tree, rustc) = self; |
2b03887a FG |
263 | match tree { |
264 | TokenTree::Punct(Punct { ch, joint, span }) => { | |
265 | let kind = match ch { | |
266 | b'=' => Eq, | |
267 | b'<' => Lt, | |
268 | b'>' => Gt, | |
269 | b'!' => Not, | |
270 | b'~' => Tilde, | |
271 | b'+' => BinOp(Plus), | |
272 | b'-' => BinOp(Minus), | |
273 | b'*' => BinOp(Star), | |
274 | b'/' => BinOp(Slash), | |
275 | b'%' => BinOp(Percent), | |
276 | b'^' => BinOp(Caret), | |
277 | b'&' => BinOp(And), | |
278 | b'|' => BinOp(Or), | |
279 | b'@' => At, | |
280 | b'.' => Dot, | |
281 | b',' => Comma, | |
282 | b';' => Semi, | |
283 | b':' => Colon, | |
284 | b'#' => Pound, | |
285 | b'$' => Dollar, | |
286 | b'?' => Question, | |
287 | b'\'' => SingleQuote, | |
288 | _ => unreachable!(), | |
289 | }; | |
290 | smallvec![if joint { | |
291 | tokenstream::TokenTree::token_joint(kind, span) | |
292 | } else { | |
293 | tokenstream::TokenTree::token_alone(kind, span) | |
294 | }] | |
295 | } | |
064997fb | 296 | TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => { |
2b03887a | 297 | smallvec![tokenstream::TokenTree::Delimited( |
064997fb FG |
298 | tokenstream::DelimSpan { open, close }, |
299 | delimiter.to_internal(), | |
300 | stream.unwrap_or_default(), | |
2b03887a | 301 | )] |
a1dfa0c6 | 302 | } |
0731742a | 303 | TokenTree::Ident(self::Ident { sym, is_raw, span }) => { |
064997fb | 304 | rustc.sess().symbol_gallery.insert(sym, span); |
2b03887a | 305 | smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw), span)] |
a1dfa0c6 XL |
306 | } |
307 | TokenTree::Literal(self::Literal { | |
064997fb FG |
308 | kind: self::LitKind::Integer, |
309 | symbol, | |
310 | suffix, | |
a1dfa0c6 | 311 | span, |
74b04a01 | 312 | }) if symbol.as_str().starts_with('-') => { |
a1dfa0c6 | 313 | let minus = BinOp(BinOpToken::Minus); |
dc9dc135 XL |
314 | let symbol = Symbol::intern(&symbol.as_str()[1..]); |
315 | let integer = TokenKind::lit(token::Integer, symbol, suffix); | |
064997fb FG |
316 | let a = tokenstream::TokenTree::token_alone(minus, span); |
317 | let b = tokenstream::TokenTree::token_alone(integer, span); | |
2b03887a | 318 | smallvec![a, b] |
a1dfa0c6 XL |
319 | } |
320 | TokenTree::Literal(self::Literal { | |
064997fb FG |
321 | kind: self::LitKind::Float, |
322 | symbol, | |
323 | suffix, | |
a1dfa0c6 | 324 | span, |
74b04a01 | 325 | }) if symbol.as_str().starts_with('-') => { |
a1dfa0c6 | 326 | let minus = BinOp(BinOpToken::Minus); |
dc9dc135 XL |
327 | let symbol = Symbol::intern(&symbol.as_str()[1..]); |
328 | let float = TokenKind::lit(token::Float, symbol, suffix); | |
064997fb FG |
329 | let a = tokenstream::TokenTree::token_alone(minus, span); |
330 | let b = tokenstream::TokenTree::token_alone(float, span); | |
2b03887a | 331 | smallvec![a, b] |
a1dfa0c6 | 332 | } |
064997fb | 333 | TokenTree::Literal(self::Literal { kind, symbol, suffix, span }) => { |
2b03887a | 334 | smallvec![tokenstream::TokenTree::token_alone( |
064997fb FG |
335 | TokenKind::lit(kind.to_internal(), symbol, suffix), |
336 | span, | |
2b03887a | 337 | )] |
a1dfa0c6 | 338 | } |
064997fb | 339 | } |
a1dfa0c6 XL |
340 | } |
341 | } | |
342 | ||
dfeec247 XL |
343 | impl ToInternal<rustc_errors::Level> for Level { |
344 | fn to_internal(self) -> rustc_errors::Level { | |
a1dfa0c6 | 345 | match self { |
3c0e092e | 346 | Level::Error => rustc_errors::Level::Error { lint: false }, |
923072b8 | 347 | Level::Warning => rustc_errors::Level::Warning(None), |
dfeec247 XL |
348 | Level::Note => rustc_errors::Level::Note, |
349 | Level::Help => rustc_errors::Level::Help, | |
a1dfa0c6 XL |
350 | _ => unreachable!("unknown proc_macro::Level variant: {:?}", self), |
351 | } | |
352 | } | |
353 | } | |
354 | ||
3dfed10e XL |
355 | pub struct FreeFunctions; |
356 | ||
3c0e092e XL |
357 | pub(crate) struct Rustc<'a, 'b> { |
358 | ecx: &'a mut ExtCtxt<'b>, | |
a1dfa0c6 XL |
359 | def_site: Span, |
360 | call_site: Span, | |
e74abb32 | 361 | mixed_site: Span, |
17df50a5 | 362 | krate: CrateNum, |
17df50a5 | 363 | rebased_spans: FxHashMap<usize, Span>, |
a1dfa0c6 XL |
364 | } |
365 | ||
3c0e092e XL |
366 | impl<'a, 'b> Rustc<'a, 'b> { |
367 | pub fn new(ecx: &'a mut ExtCtxt<'b>) -> Self { | |
368 | let expn_data = ecx.current_expansion.id.expn_data(); | |
a1dfa0c6 | 369 | Rustc { |
3c0e092e XL |
370 | def_site: ecx.with_def_site_ctxt(expn_data.def_site), |
371 | call_site: ecx.with_call_site_ctxt(expn_data.call_site), | |
372 | mixed_site: ecx.with_mixed_site_ctxt(expn_data.call_site), | |
136023e0 | 373 | krate: expn_data.macro_def_id.unwrap().krate, |
17df50a5 | 374 | rebased_spans: FxHashMap::default(), |
3c0e092e | 375 | ecx, |
a1dfa0c6 XL |
376 | } |
377 | } | |
dc9dc135 | 378 | |
3c0e092e XL |
379 | fn sess(&self) -> &ParseSess { |
380 | self.ecx.parse_sess() | |
381 | } | |
a1dfa0c6 XL |
382 | } |
383 | ||
3c0e092e | 384 | impl server::Types for Rustc<'_, '_> { |
3dfed10e | 385 | type FreeFunctions = FreeFunctions; |
a1dfa0c6 | 386 | type TokenStream = TokenStream; |
a1dfa0c6 | 387 | type SourceFile = Lrc<SourceFile>; |
a1dfa0c6 | 388 | type Span = Span; |
064997fb | 389 | type Symbol = Symbol; |
a1dfa0c6 XL |
390 | } |
391 | ||
3c0e092e | 392 | impl server::FreeFunctions for Rustc<'_, '_> { |
3dfed10e | 393 | fn track_env_var(&mut self, var: &str, value: Option<&str>) { |
3c0e092e XL |
394 | self.sess() |
395 | .env_depinfo | |
396 | .borrow_mut() | |
397 | .insert((Symbol::intern(var), value.map(Symbol::intern))); | |
3dfed10e | 398 | } |
136023e0 XL |
399 | |
400 | fn track_path(&mut self, path: &str) { | |
3c0e092e | 401 | self.sess().file_depinfo.borrow_mut().insert(Symbol::intern(path)); |
136023e0 | 402 | } |
064997fb FG |
403 | |
404 | fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> { | |
405 | let name = FileName::proc_macro_source_code(s); | |
406 | let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned()); | |
407 | ||
408 | let first_span = parser.token.span.data(); | |
409 | let minus_present = parser.eat(&token::BinOp(token::Minus)); | |
410 | ||
411 | let lit_span = parser.token.span.data(); | |
412 | let token::Literal(mut lit) = parser.token.kind else { | |
413 | return Err(()); | |
414 | }; | |
415 | ||
416 | // Check no comment or whitespace surrounding the (possibly negative) | |
417 | // literal, or more tokens after it. | |
418 | if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() { | |
419 | return Err(()); | |
420 | } | |
421 | ||
422 | if minus_present { | |
423 | // If minus is present, check no comment or whitespace in between it | |
424 | // and the literal token. | |
425 | if first_span.hi.0 != lit_span.lo.0 { | |
426 | return Err(()); | |
427 | } | |
428 | ||
429 | // Check literal is a kind we allow to be negated in a proc macro token. | |
430 | match lit.kind { | |
431 | token::LitKind::Bool | |
432 | | token::LitKind::Byte | |
433 | | token::LitKind::Char | |
434 | | token::LitKind::Str | |
435 | | token::LitKind::StrRaw(_) | |
436 | | token::LitKind::ByteStr | |
437 | | token::LitKind::ByteStrRaw(_) | |
438 | | token::LitKind::Err => return Err(()), | |
439 | token::LitKind::Integer | token::LitKind::Float => {} | |
440 | } | |
441 | ||
442 | // Synthesize a new symbol that includes the minus sign. | |
443 | let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]); | |
444 | lit = token::Lit::new(lit.kind, symbol, lit.suffix); | |
445 | } | |
446 | let token::Lit { kind, symbol, suffix } = lit; | |
447 | Ok(Literal { | |
448 | kind: FromInternal::from_internal(kind), | |
449 | symbol, | |
450 | suffix, | |
451 | span: self.call_site, | |
452 | }) | |
453 | } | |
f2b60f7d FG |
454 | |
455 | fn emit_diagnostic(&mut self, diagnostic: Diagnostic<Self::Span>) { | |
456 | let mut diag = | |
457 | rustc_errors::Diagnostic::new(diagnostic.level.to_internal(), diagnostic.message); | |
458 | diag.set_span(MultiSpan::from_spans(diagnostic.spans)); | |
459 | for child in diagnostic.children { | |
460 | diag.sub( | |
461 | child.level.to_internal(), | |
462 | child.message, | |
463 | MultiSpan::from_spans(child.spans), | |
464 | None, | |
465 | ); | |
466 | } | |
467 | self.sess().span_diagnostic.emit_diagnostic(&mut diag); | |
468 | } | |
3dfed10e XL |
469 | } |
470 | ||
3c0e092e | 471 | impl server::TokenStream for Rustc<'_, '_> { |
a1dfa0c6 XL |
472 | fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { |
473 | stream.is_empty() | |
474 | } | |
923072b8 | 475 | |
a1dfa0c6 | 476 | fn from_str(&mut self, src: &str) -> Self::TokenStream { |
60c5eb7d | 477 | parse_stream_from_source_str( |
dc9dc135 | 478 | FileName::proc_macro_source_code(src), |
a1dfa0c6 | 479 | src.to_string(), |
3c0e092e | 480 | self.sess(), |
a1dfa0c6 XL |
481 | Some(self.call_site), |
482 | ) | |
483 | } | |
923072b8 | 484 | |
a1dfa0c6 | 485 | fn to_string(&mut self, stream: &Self::TokenStream) -> String { |
f035d41b | 486 | pprust::tts_to_string(stream) |
a1dfa0c6 | 487 | } |
923072b8 | 488 | |
3c0e092e XL |
489 | fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> { |
490 | // Parse the expression from our tokenstream. | |
491 | let expr: PResult<'_, _> = try { | |
492 | let mut p = rustc_parse::stream_to_parser( | |
493 | self.sess(), | |
494 | stream.clone(), | |
495 | Some("proc_macro expand expr"), | |
496 | ); | |
497 | let expr = p.parse_expr()?; | |
498 | if p.token != token::Eof { | |
499 | p.unexpected()?; | |
500 | } | |
501 | expr | |
502 | }; | |
5e7ed085 FG |
503 | let expr = expr.map_err(|mut err| { |
504 | err.emit(); | |
505 | })?; | |
3c0e092e XL |
506 | |
507 | // Perform eager expansion on the expression. | |
508 | let expr = self | |
509 | .ecx | |
510 | .expander() | |
511 | .fully_expand_fragment(crate::expand::AstFragment::Expr(expr)) | |
512 | .make_expr(); | |
513 | ||
514 | // NOTE: For now, limit `expand_expr` to exclusively expand to literals. | |
515 | // This may be relaxed in the future. | |
923072b8 | 516 | // We don't use `TokenStream::from_ast` as the tokenstream currently cannot |
3c0e092e XL |
517 | // be recovered in the general case. |
518 | match &expr.kind { | |
487cf647 | 519 | ast::ExprKind::Lit(token_lit) if token_lit.kind == token::Bool => { |
f2b60f7d | 520 | Ok(tokenstream::TokenStream::token_alone( |
487cf647 FG |
521 | token::Ident(token_lit.symbol, false), |
522 | expr.span, | |
f2b60f7d FG |
523 | )) |
524 | } | |
487cf647 FG |
525 | ast::ExprKind::Lit(token_lit) => { |
526 | Ok(tokenstream::TokenStream::token_alone(token::Literal(*token_lit), expr.span)) | |
527 | } | |
528 | ast::ExprKind::IncludedBytes(bytes) => { | |
529 | let lit = ast::LitKind::ByteStr(bytes.clone()).to_token_lit(); | |
530 | Ok(tokenstream::TokenStream::token_alone(token::TokenKind::Literal(lit), expr.span)) | |
3c0e092e XL |
531 | } |
532 | ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind { | |
487cf647 | 533 | ast::ExprKind::Lit(token_lit) => match token_lit { |
3c0e092e | 534 | token::Lit { kind: token::Integer | token::Float, .. } => { |
a2a8927a | 535 | Ok(Self::TokenStream::from_iter([ |
3c0e092e XL |
536 | // FIXME: The span of the `-` token is lost when |
537 | // parsing, so we cannot faithfully recover it here. | |
064997fb | 538 | tokenstream::TokenTree::token_alone(token::BinOp(token::Minus), e.span), |
487cf647 | 539 | tokenstream::TokenTree::token_alone(token::Literal(*token_lit), e.span), |
a2a8927a | 540 | ])) |
3c0e092e XL |
541 | } |
542 | _ => Err(()), | |
543 | }, | |
544 | _ => Err(()), | |
545 | }, | |
546 | _ => Err(()), | |
547 | } | |
548 | } | |
923072b8 | 549 | |
a1dfa0c6 XL |
550 | fn from_token_tree( |
551 | &mut self, | |
064997fb | 552 | tree: TokenTree<Self::TokenStream, Self::Span, Self::Symbol>, |
a1dfa0c6 | 553 | ) -> Self::TokenStream { |
2b03887a | 554 | Self::TokenStream::new((tree, &mut *self).to_internal().into_iter().collect::<Vec<_>>()) |
a1dfa0c6 | 555 | } |
a1dfa0c6 | 556 | |
923072b8 FG |
557 | fn concat_trees( |
558 | &mut self, | |
559 | base: Option<Self::TokenStream>, | |
064997fb | 560 | trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>, |
923072b8 | 561 | ) -> Self::TokenStream { |
2b03887a FG |
562 | let mut stream = |
563 | if let Some(base) = base { base } else { tokenstream::TokenStream::default() }; | |
923072b8 | 564 | for tree in trees { |
2b03887a FG |
565 | for tt in (tree, &mut *self).to_internal() { |
566 | stream.push_tree(tt); | |
567 | } | |
923072b8 | 568 | } |
2b03887a | 569 | stream |
a1dfa0c6 | 570 | } |
923072b8 FG |
571 | |
572 | fn concat_streams( | |
573 | &mut self, | |
574 | base: Option<Self::TokenStream>, | |
575 | streams: Vec<Self::TokenStream>, | |
576 | ) -> Self::TokenStream { | |
2b03887a FG |
577 | let mut stream = |
578 | if let Some(base) = base { base } else { tokenstream::TokenStream::default() }; | |
579 | for s in streams { | |
580 | stream.push_stream(s); | |
923072b8 | 581 | } |
2b03887a | 582 | stream |
a1dfa0c6 | 583 | } |
a1dfa0c6 | 584 | |
923072b8 | 585 | fn into_trees( |
a1dfa0c6 | 586 | &mut self, |
923072b8 | 587 | stream: Self::TokenStream, |
064997fb FG |
588 | ) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> { |
589 | FromInternal::from_internal((stream, self)) | |
a1dfa0c6 XL |
590 | } |
591 | } | |
592 | ||
3c0e092e | 593 | impl server::SourceFile for Rustc<'_, '_> { |
a1dfa0c6 XL |
594 | fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool { |
595 | Lrc::ptr_eq(file1, file2) | |
596 | } | |
923072b8 | 597 | |
a1dfa0c6 XL |
598 | fn path(&mut self, file: &Self::SourceFile) -> String { |
599 | match file.name { | |
ba9703b0 XL |
600 | FileName::Real(ref name) => name |
601 | .local_path() | |
17df50a5 | 602 | .expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`") |
a1dfa0c6 XL |
603 | .to_str() |
604 | .expect("non-UTF8 file path in `proc_macro::SourceFile::path`") | |
605 | .to_string(), | |
17df50a5 | 606 | _ => file.name.prefer_local().to_string(), |
a1dfa0c6 XL |
607 | } |
608 | } | |
923072b8 | 609 | |
a1dfa0c6 XL |
610 | fn is_real(&mut self, file: &Self::SourceFile) -> bool { |
611 | file.is_real_file() | |
612 | } | |
613 | } | |
614 | ||
3c0e092e | 615 | impl server::Span for Rustc<'_, '_> { |
a1dfa0c6 | 616 | fn debug(&mut self, span: Self::Span) -> String { |
3c0e092e | 617 | if self.ecx.ecfg.span_debug { |
f035d41b XL |
618 | format!("{:?}", span) |
619 | } else { | |
620 | format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0) | |
621 | } | |
a1dfa0c6 | 622 | } |
923072b8 | 623 | |
a1dfa0c6 | 624 | fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { |
3c0e092e | 625 | self.sess().source_map().lookup_char_pos(span.lo()).file |
a1dfa0c6 | 626 | } |
923072b8 | 627 | |
a1dfa0c6 | 628 | fn parent(&mut self, span: Self::Span) -> Option<Self::Span> { |
c295e0f8 | 629 | span.parent_callsite() |
a1dfa0c6 | 630 | } |
923072b8 | 631 | |
a1dfa0c6 XL |
632 | fn source(&mut self, span: Self::Span) -> Self::Span { |
633 | span.source_callsite() | |
634 | } | |
923072b8 | 635 | |
a1dfa0c6 | 636 | fn start(&mut self, span: Self::Span) -> LineColumn { |
3c0e092e | 637 | let loc = self.sess().source_map().lookup_char_pos(span.lo()); |
dfeec247 | 638 | LineColumn { line: loc.line, column: loc.col.to_usize() } |
a1dfa0c6 | 639 | } |
923072b8 | 640 | |
a1dfa0c6 | 641 | fn end(&mut self, span: Self::Span) -> LineColumn { |
3c0e092e | 642 | let loc = self.sess().source_map().lookup_char_pos(span.hi()); |
dfeec247 | 643 | LineColumn { line: loc.line, column: loc.col.to_usize() } |
a1dfa0c6 | 644 | } |
923072b8 | 645 | |
c295e0f8 XL |
646 | fn before(&mut self, span: Self::Span) -> Self::Span { |
647 | span.shrink_to_lo() | |
648 | } | |
923072b8 | 649 | |
c295e0f8 XL |
650 | fn after(&mut self, span: Self::Span) -> Self::Span { |
651 | span.shrink_to_hi() | |
652 | } | |
923072b8 | 653 | |
a1dfa0c6 | 654 | fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> { |
3c0e092e XL |
655 | let self_loc = self.sess().source_map().lookup_char_pos(first.lo()); |
656 | let other_loc = self.sess().source_map().lookup_char_pos(second.lo()); | |
a1dfa0c6 XL |
657 | |
658 | if self_loc.file.name != other_loc.file.name { | |
659 | return None; | |
660 | } | |
661 | ||
662 | Some(first.to(second)) | |
663 | } | |
923072b8 | 664 | |
064997fb FG |
665 | fn subspan( |
666 | &mut self, | |
667 | span: Self::Span, | |
668 | start: Bound<usize>, | |
669 | end: Bound<usize>, | |
670 | ) -> Option<Self::Span> { | |
671 | let length = span.hi().to_usize() - span.lo().to_usize(); | |
672 | ||
673 | let start = match start { | |
674 | Bound::Included(lo) => lo, | |
675 | Bound::Excluded(lo) => lo.checked_add(1)?, | |
676 | Bound::Unbounded => 0, | |
677 | }; | |
678 | ||
679 | let end = match end { | |
680 | Bound::Included(hi) => hi.checked_add(1)?, | |
681 | Bound::Excluded(hi) => hi, | |
682 | Bound::Unbounded => length, | |
683 | }; | |
684 | ||
685 | // Bounds check the values, preventing addition overflow and OOB spans. | |
686 | if start > u32::MAX as usize | |
687 | || end > u32::MAX as usize | |
688 | || (u32::MAX - start as u32) < span.lo().to_u32() | |
689 | || (u32::MAX - end as u32) < span.lo().to_u32() | |
690 | || start >= end | |
691 | || end > length | |
692 | { | |
693 | return None; | |
694 | } | |
695 | ||
696 | let new_lo = span.lo() + BytePos::from_usize(start); | |
697 | let new_hi = span.lo() + BytePos::from_usize(end); | |
698 | Some(span.with_lo(new_lo).with_hi(new_hi)) | |
699 | } | |
700 | ||
a1dfa0c6 XL |
701 | fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span { |
702 | span.with_ctxt(at.ctxt()) | |
703 | } | |
923072b8 | 704 | |
dfeec247 | 705 | fn source_text(&mut self, span: Self::Span) -> Option<String> { |
3c0e092e | 706 | self.sess().source_map().span_to_snippet(span).ok() |
532ac7d7 | 707 | } |
2b03887a | 708 | |
17df50a5 XL |
709 | /// Saves the provided span into the metadata of |
710 | /// *the crate we are currently compiling*, which must | |
711 | /// be a proc-macro crate. This id can be passed to | |
712 | /// `recover_proc_macro_span` when our current crate | |
713 | /// is *run* as a proc-macro. | |
714 | /// | |
715 | /// Let's suppose that we have two crates - `my_client` | |
716 | /// and `my_proc_macro`. The `my_proc_macro` crate | |
717 | /// contains a procedural macro `my_macro`, which | |
718 | /// is implemented as: `quote! { "hello" }` | |
719 | /// | |
720 | /// When we *compile* `my_proc_macro`, we will execute | |
721 | /// the `quote` proc-macro. This will save the span of | |
722 | /// "hello" into the metadata of `my_proc_macro`. As a result, | |
723 | /// the body of `my_proc_macro` (after expansion) will end | |
5e7ed085 | 724 | /// up containing a call that looks like this: |
17df50a5 XL |
725 | /// `proc_macro::Ident::new("hello", proc_macro::Span::recover_proc_macro_span(0))` |
726 | /// | |
727 | /// where `0` is the id returned by this function. | |
728 | /// When `my_proc_macro` *executes* (during the compilation of `my_client`), | |
729 | /// the call to `recover_proc_macro_span` will load the corresponding | |
730 | /// span from the metadata of `my_proc_macro` (which we have access to, | |
731 | /// since we've loaded `my_proc_macro` from disk in order to execute it). | |
732 | /// In this way, we have obtained a span pointing into `my_proc_macro` | |
136023e0 | 733 | fn save_span(&mut self, span: Self::Span) -> usize { |
3c0e092e | 734 | self.sess().save_proc_macro_span(span) |
17df50a5 | 735 | } |
923072b8 | 736 | |
17df50a5 | 737 | fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span { |
3c0e092e | 738 | let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site); |
17df50a5 | 739 | *self.rebased_spans.entry(id).or_insert_with(|| { |
136023e0 XL |
740 | // FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding, |
741 | // replace it with a def-site context until we are encoding it properly. | |
742 | resolver.get_proc_macro_quoted_span(krate, id).with_ctxt(def_site.ctxt()) | |
17df50a5 XL |
743 | }) |
744 | } | |
a1dfa0c6 | 745 | } |
064997fb FG |
746 | |
747 | impl server::Symbol for Rustc<'_, '_> { | |
748 | fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> { | |
749 | let sym = nfc_normalize(string); | |
750 | if rustc_lexer::is_ident(sym.as_str()) { Ok(sym) } else { Err(()) } | |
751 | } | |
752 | } | |
753 | ||
754 | impl server::Server for Rustc<'_, '_> { | |
755 | fn globals(&mut self) -> ExpnGlobals<Self::Span> { | |
756 | ExpnGlobals { | |
757 | def_site: self.def_site, | |
758 | call_site: self.call_site, | |
759 | mixed_site: self.mixed_site, | |
760 | } | |
761 | } | |
762 | ||
763 | fn intern_symbol(string: &str) -> Self::Symbol { | |
764 | Symbol::intern(string) | |
765 | } | |
766 | ||
767 | fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { | |
768 | f(&symbol.as_str()) | |
769 | } | |
770 | } |