• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use rustc_ast as ast;
2 use rustc_ast::tokenstream::TokenStream;
3 use rustc_expand::base::{self, DummyResult};
4 use rustc_session::errors::report_lit_error;
5 use rustc_span::symbol::Symbol;
6 
7 use crate::errors;
8 
expand_concat( cx: &mut base::ExtCtxt<'_>, sp: rustc_span::Span, tts: TokenStream, ) -> Box<dyn base::MacResult + 'static>9 pub fn expand_concat(
10     cx: &mut base::ExtCtxt<'_>,
11     sp: rustc_span::Span,
12     tts: TokenStream,
13 ) -> Box<dyn base::MacResult + 'static> {
14     let Some(es) = base::get_exprs_from_tts(cx, tts) else {
15         return DummyResult::any(sp);
16     };
17     let mut accumulator = String::new();
18     let mut missing_literal = vec![];
19     let mut has_errors = false;
20     for e in es {
21         match e.kind {
22             ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
23                 Ok(ast::LitKind::Str(s, _) | ast::LitKind::Float(s, _)) => {
24                     accumulator.push_str(s.as_str());
25                 }
26                 Ok(ast::LitKind::Char(c)) => {
27                     accumulator.push(c);
28                 }
29                 Ok(ast::LitKind::Int(i, _)) => {
30                     accumulator.push_str(&i.to_string());
31                 }
32                 Ok(ast::LitKind::Bool(b)) => {
33                     accumulator.push_str(&b.to_string());
34                 }
35                 Ok(ast::LitKind::CStr(..)) => {
36                     cx.emit_err(errors::ConcatCStrLit{ span: e.span});
37                     has_errors = true;
38                 }
39                 Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
40                     cx.emit_err(errors::ConcatBytestr { span: e.span });
41                     has_errors = true;
42                 }
43                 Ok(ast::LitKind::Err) => {
44                     has_errors = true;
45                 }
46                 Err(err) => {
47                     report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span);
48                     has_errors = true;
49                 }
50             },
51             // We also want to allow negative numeric literals.
52             ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) if let ast::ExprKind::Lit(token_lit) = expr.kind => {
53                 match ast::LitKind::from_token_lit(token_lit) {
54                     Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")),
55                     Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")),
56                     Err(err) => {
57                         report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span);
58                         has_errors = true;
59                     }
60                     _ => missing_literal.push(e.span),
61                 }
62             }
63             ast::ExprKind::IncludedBytes(..) => {
64                 cx.emit_err(errors::ConcatBytestr { span: e.span });
65             }
66             ast::ExprKind::Err => {
67                 has_errors = true;
68             }
69             _ => {
70                 missing_literal.push(e.span);
71             }
72         }
73     }
74 
75     if !missing_literal.is_empty() {
76         cx.emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
77         return DummyResult::any(sp);
78     } else if has_errors {
79         return DummyResult::any(sp);
80     }
81     let sp = cx.with_def_site_ctxt(sp);
82     base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
83 }
84