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