rustc_builtin_macros/
concat_idents.rs
1use rustc_ast::ptr::P;
2use rustc_ast::token::{self, Token};
3use rustc_ast::tokenstream::{TokenStream, TokenTree};
4use rustc_ast::{AttrVec, DUMMY_NODE_ID, Expr, ExprKind, Path, Ty, TyKind};
5use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
6use rustc_span::{Ident, Span, Symbol};
7
8use crate::errors;
9
10pub(crate) fn expand_concat_idents<'cx>(
11 cx: &'cx mut ExtCtxt<'_>,
12 sp: Span,
13 tts: TokenStream,
14) -> MacroExpanderResult<'cx> {
15 if tts.is_empty() {
16 let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
17 return ExpandResult::Ready(DummyResult::any(sp, guar));
18 }
19
20 let mut res_str = String::new();
21 for (i, e) in tts.iter().enumerate() {
22 if i & 1 == 1 {
23 match e {
24 TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
25 _ => {
26 let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
27 return ExpandResult::Ready(DummyResult::any(sp, guar));
28 }
29 }
30 } else {
31 if let TokenTree::Token(token, _) = e {
32 if let Some((ident, _)) = token.ident() {
33 res_str.push_str(ident.name.as_str());
34 continue;
35 }
36 }
37
38 let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp });
39 return ExpandResult::Ready(DummyResult::any(sp, guar));
40 }
41 }
42
43 let ident = Ident::new(Symbol::intern(&res_str), cx.with_call_site_ctxt(sp));
44
45 struct ConcatIdentsResult {
46 ident: Ident,
47 }
48
49 impl MacResult for ConcatIdentsResult {
50 fn make_expr(self: Box<Self>) -> Option<P<Expr>> {
51 Some(P(Expr {
52 id: DUMMY_NODE_ID,
53 kind: ExprKind::Path(None, Path::from_ident(self.ident)),
54 span: self.ident.span,
55 attrs: AttrVec::new(),
56 tokens: None,
57 }))
58 }
59
60 fn make_ty(self: Box<Self>) -> Option<P<Ty>> {
61 Some(P(Ty {
62 id: DUMMY_NODE_ID,
63 kind: TyKind::Path(None, Path::from_ident(self.ident)),
64 span: self.ident.span,
65 tokens: None,
66 }))
67 }
68 }
69
70 ExpandResult::Ready(Box::new(ConcatIdentsResult { ident }))
71}