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