Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-ast-fragment.h"
20 : #include "rust-macro-builtins.h"
21 : #include "rust-macro-builtins-helpers.h"
22 : #include "rust-ast-builder.h"
23 : #include "optional.h"
24 : #include "rust-ast-collector.h"
25 :
26 : namespace Rust {
27 : tl::optional<AST::Fragment>
28 2 : MacroBuiltin::assert_handler (location_t invoc_locus,
29 : AST::MacroInvocData &invoc,
30 : AST::InvocKind semicolon)
31 : {
32 2 : rust_debug ("assert!() called");
33 2 : auto tt = invoc.get_delim_tok_tree ();
34 2 : MacroInvocLexer lex (tt.to_token_stream ());
35 2 : Parser<MacroInvocLexer> parser (lex);
36 :
37 2 : auto last_token_id = macro_end_token (tt, parser);
38 :
39 : // TODO: less args?
40 2 : auto expr_to_assert = parser.parse_expr ();
41 2 : if (!expr_to_assert.has_value ())
42 : {
43 0 : rust_error_at (invoc_locus,
44 : "macro requires a boolean expression as an argument");
45 0 : return AST::Fragment::create_error ();
46 : }
47 :
48 : // don't need to expand macros -- panic! will handle it
49 :
50 2 : AST::Builder b (invoc_locus);
51 :
52 2 : std::vector<std::unique_ptr<AST::TokenTree>> panic_tree;
53 2 : const_TokenPtr open = Token::make (TokenId::LEFT_PAREN, invoc_locus);
54 2 : panic_tree.push_back (std::make_unique<AST::Token> (std::move (open)));
55 :
56 2 : if (parser.maybe_skip_token (COMMA))
57 : {
58 4 : bool needs_stringify = true;
59 8 : while (parser.peek_current_token ()->get_id () != last_token_id
60 14 : && parser.peek_current_token ()->get_id () != END_OF_FILE)
61 : {
62 3 : needs_stringify = false;
63 3 : auto token_tree = parser.parse_token_tree ();
64 3 : if (!token_tree.has_value ())
65 : {
66 : // error already emitted (?)
67 0 : return AST::Fragment::create_error ();
68 : }
69 3 : panic_tree.push_back (std::move (token_tree.value ()));
70 3 : }
71 : if (needs_stringify)
72 : {
73 : // TODO: insert stringify invocation
74 : (void) 0;
75 : }
76 : }
77 :
78 2 : const_TokenPtr close = Token::make (TokenId::RIGHT_PAREN, invoc_locus);
79 2 : panic_tree.push_back (std::make_unique<AST::Token> (std::move (close)));
80 :
81 2 : auto panic = AST::MacroInvocation::Regular (
82 6 : AST::MacroInvocData (AST::SimplePath (Identifier ("panic")),
83 4 : AST::DelimTokenTree (AST::DelimType::PARENS,
84 : std::move (panic_tree),
85 6 : invoc_locus)),
86 2 : {} /* outer attributes */, invoc_locus, true /* semicoloned */);
87 4 : auto stmt = b.statementify (std::move (panic));
88 2 : std::vector<std::unique_ptr<AST::Stmt>> stmts;
89 2 : stmts.push_back (std::move (stmt));
90 2 : auto block = b.block (std::move (stmts));
91 2 : auto negated_condition = std::unique_ptr<AST::NegationExpr> (
92 2 : new AST::NegationExpr (std::move (expr_to_assert.value ()),
93 2 : AST::NegationExpr::ExprType::NOT, {}, invoc_locus));
94 :
95 2 : auto if_expr = std::make_unique<AST::IfExpr> (
96 : std::move (negated_condition) /* condition*/, std::move (block),
97 2 : std::vector<AST::Attribute>{}, invoc_locus);
98 :
99 2 : auto node = AST::SingleASTNode (std::move (if_expr));
100 :
101 2 : AST::TokenCollector collector;
102 2 : collector.visit (node);
103 2 : std::vector<std::unique_ptr<AST::Token>> tokens;
104 27 : for (auto &&token : collector.collect_tokens ())
105 27 : tokens.push_back (std::make_unique<AST::Token> (token));
106 :
107 6 : return AST::Fragment ({node}, std::move (tokens));
108 :
109 : return AST::Fragment::create_error ();
110 6 : }
111 : } // namespace Rust
|