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}