]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/assert.rs
Rollup merge of #58273 - taiki-e:rename-dependency, r=matthewjasper
[rust.git] / src / libsyntax_ext / assert.rs
1 use errors::DiagnosticBuilder;
2
3 use syntax::ast::{self, *};
4 use syntax::source_map::Spanned;
5 use syntax::ext::base::*;
6 use syntax::ext::build::AstBuilder;
7 use syntax::parse::token;
8 use syntax::print::pprust;
9 use syntax::ptr::P;
10 use syntax::symbol::Symbol;
11 use syntax::tokenstream::{TokenStream, TokenTree};
12 use syntax_pos::{Span, DUMMY_SP};
13
14 pub fn expand_assert<'cx>(
15     cx: &'cx mut ExtCtxt<'_>,
16     sp: Span,
17     tts: &[TokenTree],
18 ) -> Box<dyn MacResult + 'cx> {
19     let Assert { cond_expr, custom_message } = match parse_assert(cx, sp, tts) {
20         Ok(assert) => assert,
21         Err(mut err) => {
22             err.emit();
23             return DummyResult::expr(sp);
24         }
25     };
26
27     let sp = sp.apply_mark(cx.current_expansion.mark);
28     let panic_call = Mac_ {
29         path: Path::from_ident(Ident::new(Symbol::intern("panic"), sp)),
30         tts: custom_message.unwrap_or_else(|| {
31             TokenStream::from(TokenTree::Token(
32                 DUMMY_SP,
33                 token::Literal(
34                     token::Lit::Str_(Name::intern(&format!(
35                         "assertion failed: {}",
36                         pprust::expr_to_string(&cond_expr).escape_debug()
37                     ))),
38                     None,
39                 ),
40             ))
41         }).into(),
42         delim: MacDelimiter::Parenthesis,
43     };
44     let if_expr = cx.expr_if(
45         sp,
46         cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)),
47         cx.expr(
48             sp,
49             ExprKind::Mac(Spanned {
50                 span: sp,
51                 node: panic_call,
52             }),
53         ),
54         None,
55     );
56     MacEager::expr(if_expr)
57 }
58
59 struct Assert {
60     cond_expr: P<ast::Expr>,
61     custom_message: Option<TokenStream>,
62 }
63
64 fn parse_assert<'a>(
65     cx: &mut ExtCtxt<'a>,
66     sp: Span,
67     tts: &[TokenTree]
68 ) -> Result<Assert, DiagnosticBuilder<'a>> {
69     let mut parser = cx.new_parser_from_tts(tts);
70
71     if parser.token == token::Eof {
72         let mut err = cx.struct_span_err(sp, "macro requires a boolean expression as an argument");
73         err.span_label(sp, "boolean expression required");
74         return Err(err);
75     }
76
77     Ok(Assert {
78         cond_expr: parser.parse_expr()?,
79         custom_message: if parser.eat(&token::Comma) {
80             let ts = parser.parse_tokens();
81             if !ts.is_empty() {
82                 Some(ts)
83             } else {
84                 None
85             }
86         } else {
87             None
88         },
89     })
90 }