Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : : #ifndef RUST_AST_STATEMENT_H
20 : : #define RUST_AST_STATEMENT_H
21 : :
22 : : #include "optional.h"
23 : : #include "rust-ast.h"
24 : : #include "rust-path.h"
25 : : #include "rust-expr.h"
26 : : #include "rust-system.h"
27 : :
28 : : namespace Rust {
29 : : namespace AST {
30 : : // Just a semi-colon, which apparently is a statement.
31 : 160 : class EmptyStmt : public Stmt
32 : : {
33 : : location_t locus;
34 : :
35 : : // TODO: find another way to store this to save memory?
36 : : bool marked_for_strip = false;
37 : :
38 : : public:
39 : 0 : std::string as_string () const override { return std::string (1, ';'); }
40 : :
41 : 58 : EmptyStmt (location_t locus) : locus (locus) {}
42 : :
43 : 54 : location_t get_locus () const override final { return locus; }
44 : :
45 : : void accept_vis (ASTVisitor &vis) override;
46 : :
47 : : // Can't think of any invalid invariants, so store boolean.
48 : 0 : void mark_for_strip () override { marked_for_strip = true; }
49 : 188 : bool is_marked_for_strip () const override { return marked_for_strip; }
50 : :
51 : 90 : bool is_item () const override final { return false; }
52 : :
53 : 273 : Stmt::Kind get_stmt_kind () final { return Stmt::Kind::Empty; }
54 : :
55 : : protected:
56 : : /* Use covariance to implement clone function as returning this object rather
57 : : * than base */
58 : 160 : EmptyStmt *clone_stmt_impl () const override { return new EmptyStmt (*this); }
59 : : };
60 : :
61 : : /* Variable assignment let statement - type of "declaration statement" as it
62 : : * introduces new name into scope */
63 : : class LetStmt : public Stmt
64 : : {
65 : : // bool has_outer_attrs;
66 : : std::vector<Attribute> outer_attrs;
67 : :
68 : : std::unique_ptr<Pattern> variables_pattern;
69 : :
70 : : // bool has_type;
71 : : std::unique_ptr<Type> type;
72 : :
73 : : // bool has_init_expr;
74 : : std::unique_ptr<Expr> init_expr;
75 : :
76 : : tl::optional<std::unique_ptr<Expr>> else_expr;
77 : :
78 : : location_t locus;
79 : :
80 : : public:
81 : : Type *inferedType;
82 : :
83 : : // Returns whether let statement has outer attributes.
84 : : bool has_outer_attrs () const { return !outer_attrs.empty (); }
85 : :
86 : : // Returns whether let statement has a given return type.
87 : 212525 : bool has_type () const { return type != nullptr; }
88 : :
89 : : // Returns whether let statement has an initialisation expression.
90 : 225335 : bool has_init_expr () const { return init_expr != nullptr; }
91 : 27083 : bool has_else_expr () const { return else_expr.has_value (); }
92 : :
93 : : std::string as_string () const override;
94 : :
95 : 13407 : LetStmt (std::unique_ptr<Pattern> variables_pattern,
96 : : std::unique_ptr<Expr> init_expr, std::unique_ptr<Type> type,
97 : : tl::optional<std::unique_ptr<Expr>> else_expr,
98 : : std::vector<Attribute> outer_attrs, location_t locus)
99 : 26814 : : outer_attrs (std::move (outer_attrs)),
100 : 13407 : variables_pattern (std::move (variables_pattern)),
101 : 13407 : type (std::move (type)), init_expr (std::move (init_expr)),
102 : 13407 : else_expr (std::move (else_expr)), locus (locus)
103 : 13407 : {}
104 : :
105 : : // Copy constructor with clone
106 : 1736 : LetStmt (LetStmt const &other)
107 : 1736 : : outer_attrs (other.outer_attrs), locus (other.locus)
108 : : {
109 : : // guard to prevent null dereference (only required if error state)
110 : 1736 : if (other.variables_pattern != nullptr)
111 : 1736 : variables_pattern = other.variables_pattern->clone_pattern ();
112 : :
113 : : // guard to prevent null dereference (always required)
114 : 1736 : if (other.init_expr != nullptr)
115 : 1707 : init_expr = other.init_expr->clone_expr ();
116 : 1736 : if (other.else_expr.has_value ())
117 : 0 : else_expr = other.else_expr.value ()->clone_expr ();
118 : :
119 : 1736 : if (other.type != nullptr)
120 : 11 : type = other.type->clone_type ();
121 : 1736 : }
122 : :
123 : : // Overloaded assignment operator to clone
124 : : LetStmt &operator= (LetStmt const &other)
125 : : {
126 : : outer_attrs = other.outer_attrs;
127 : : locus = other.locus;
128 : :
129 : : // guard to prevent null dereference (only required if error state)
130 : : if (other.variables_pattern != nullptr)
131 : : variables_pattern = other.variables_pattern->clone_pattern ();
132 : : else
133 : : variables_pattern = nullptr;
134 : :
135 : : // guard to prevent null dereference (always required)
136 : : if (other.init_expr != nullptr)
137 : : init_expr = other.init_expr->clone_expr ();
138 : : else
139 : : init_expr = nullptr;
140 : :
141 : : if (other.else_expr != nullptr)
142 : : else_expr = other.else_expr.value ()->clone_expr ();
143 : : else
144 : : else_expr = tl::nullopt;
145 : :
146 : : if (other.type != nullptr)
147 : : type = other.type->clone_type ();
148 : : else
149 : : type = nullptr;
150 : :
151 : : return *this;
152 : : }
153 : :
154 : : // move constructors
155 : : LetStmt (LetStmt &&other) = default;
156 : : LetStmt &operator= (LetStmt &&other) = default;
157 : :
158 : 14307 : location_t get_locus () const override final { return locus; }
159 : :
160 : : void accept_vis (ASTVisitor &vis) override;
161 : :
162 : : // Invalid if pattern is null, so base stripping on that.
163 : 0 : void mark_for_strip () override { variables_pattern = nullptr; }
164 : 32840 : bool is_marked_for_strip () const override
165 : : {
166 : 32840 : return variables_pattern == nullptr;
167 : : }
168 : :
169 : : // TODO: this mutable getter seems really dodgy. Think up better way.
170 : 183143 : std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
171 : : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
172 : :
173 : : // TODO: is this better? Or is a "vis_block" better?
174 : 191087 : Expr &get_init_expr ()
175 : : {
176 : 191087 : rust_assert (has_init_expr ());
177 : 191087 : return *init_expr;
178 : : }
179 : :
180 : 0 : Expr &get_else_expr ()
181 : : {
182 : 0 : rust_assert (has_else_expr ());
183 : 0 : return *else_expr.value ();
184 : : }
185 : :
186 : 14956 : std::unique_ptr<Expr> &get_init_expr_ptr ()
187 : : {
188 : 14956 : rust_assert (has_init_expr ());
189 : 14956 : return init_expr;
190 : : }
191 : :
192 : : std::unique_ptr<Expr> &get_else_expr_ptr ()
193 : : {
194 : : rust_assert (has_else_expr ());
195 : : return else_expr.value ();
196 : : }
197 : :
198 : 212525 : Pattern &get_pattern ()
199 : : {
200 : 212525 : rust_assert (variables_pattern != nullptr);
201 : 212525 : return *variables_pattern;
202 : : }
203 : :
204 : 32992 : Type &get_type ()
205 : : {
206 : 32992 : rust_assert (has_type ());
207 : 32992 : return *type;
208 : : }
209 : :
210 : 2974 : std::unique_ptr<Type> &get_type_ptr ()
211 : : {
212 : 2974 : rust_assert (has_type ());
213 : 2974 : return type;
214 : : }
215 : :
216 : 22736 : bool is_item () const override final { return false; }
217 : 51692 : Stmt::Kind get_stmt_kind () final { return Stmt::Kind::Let; }
218 : :
219 : : protected:
220 : : /* Use covariance to implement clone function as returning this object rather
221 : : * than base */
222 : 1736 : LetStmt *clone_stmt_impl () const override { return new LetStmt (*this); }
223 : : };
224 : :
225 : : // Expression statements (statements containing an expression)
226 : : class ExprStmt : public Stmt
227 : : {
228 : : std::unique_ptr<Expr> expr;
229 : : location_t locus;
230 : : bool semicolon_followed;
231 : :
232 : : public:
233 : 7691 : location_t get_locus () const override final { return locus; }
234 : :
235 : 13776 : bool is_item () const override final { return false; }
236 : :
237 : 8292 : bool is_expr () const override final { return true; }
238 : :
239 : : // Used for the last statement for statement macros with a trailing
240 : : // semicolon.
241 : 188 : void add_semicolon () override final { semicolon_followed = true; }
242 : :
243 : : std::string as_string () const override;
244 : :
245 : 31031 : Stmt::Kind get_stmt_kind () final { return Stmt::Kind::Expr; }
246 : :
247 : : std::vector<LetStmt *> locals;
248 : :
249 : 7855 : ExprStmt (std::unique_ptr<Expr> &&expr, location_t locus,
250 : : bool semicolon_followed)
251 : 15710 : : expr (std::move (expr)), locus (locus),
252 : 7855 : semicolon_followed (semicolon_followed)
253 : : {}
254 : :
255 : : // Copy constructor with clone
256 : 1475 : ExprStmt (ExprStmt const &other)
257 : 1475 : : locus (other.locus), semicolon_followed (other.semicolon_followed)
258 : : {
259 : : // guard to prevent null dereference (only required if error state)
260 : 1475 : if (other.expr != nullptr)
261 : 1475 : expr = other.expr->clone_expr ();
262 : 1475 : }
263 : :
264 : : // Overloaded assignment operator to clone
265 : : ExprStmt &operator= (ExprStmt const &other)
266 : : {
267 : : Stmt::operator= (other);
268 : :
269 : : // guard to prevent null dereference (only required if error state)
270 : : if (other.expr != nullptr)
271 : : expr = other.expr->clone_expr ();
272 : : else
273 : : expr = nullptr;
274 : :
275 : : locus = other.locus;
276 : : semicolon_followed = other.semicolon_followed;
277 : :
278 : : return *this;
279 : : }
280 : :
281 : : // move constructors
282 : : ExprStmt (ExprStmt &&other) = default;
283 : : ExprStmt &operator= (ExprStmt &&other) = default;
284 : :
285 : : void accept_vis (ASTVisitor &vis) override;
286 : :
287 : : // Invalid if expr is null, so base stripping on that.
288 : 22 : void mark_for_strip () override { expr = nullptr; }
289 : 49331 : bool is_marked_for_strip () const override { return expr == nullptr; }
290 : :
291 : : // TODO: is this better? Or is a "vis_block" better?
292 : 131458 : Expr &get_expr ()
293 : : {
294 : 131458 : rust_assert (expr != nullptr);
295 : 131458 : return *expr;
296 : : }
297 : :
298 : 18141 : std::unique_ptr<Expr> &get_expr_ptr ()
299 : : {
300 : 18141 : rust_assert (expr != nullptr);
301 : 18141 : return expr;
302 : : }
303 : :
304 : 20 : std::unique_ptr<Expr> take_expr ()
305 : : {
306 : 20 : rust_assert (expr != nullptr);
307 : 20 : return std::move (expr);
308 : : }
309 : :
310 : 16926 : bool is_semicolon_followed () const { return semicolon_followed; }
311 : :
312 : : protected:
313 : : /* Use covariance to implement clone function as returning this object rather
314 : : * than base */
315 : 1475 : ExprStmt *clone_stmt_impl () const override { return new ExprStmt (*this); }
316 : : };
317 : :
318 : : } // namespace AST
319 : : } // namespace Rust
320 : :
321 : : #endif
|