]>
Commit | Line | Data |
---|---|---|
83ffe9cd | 1 | // Copyright (C) 2020-2023 Free Software Foundation, Inc. |
d588754c JP |
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 "rust-ast.h" | |
23 | #include "rust-path.h" | |
24 | #include "rust-expr.h" | |
25 | ||
26 | namespace Rust { | |
27 | namespace AST { | |
28 | // Just a semi-colon, which apparently is a statement. | |
29 | class EmptyStmt : public Stmt | |
30 | { | |
31 | Location locus; | |
32 | ||
33 | // TODO: find another way to store this to save memory? | |
34 | bool marked_for_strip = false; | |
35 | ||
36 | public: | |
37 | std::string as_string () const override { return std::string (1, ';'); } | |
38 | ||
39 | EmptyStmt (Location locus) : locus (locus) {} | |
40 | ||
41 | Location get_locus () const override final { return locus; } | |
42 | ||
43 | void accept_vis (ASTVisitor &vis) override; | |
44 | ||
45 | // Can't think of any invalid invariants, so store boolean. | |
46 | void mark_for_strip () override { marked_for_strip = true; } | |
47 | bool is_marked_for_strip () const override { return marked_for_strip; } | |
48 | ||
49 | bool is_item () const override final { return false; } | |
50 | ||
51 | protected: | |
52 | /* Use covariance to implement clone function as returning this object rather | |
53 | * than base */ | |
54 | EmptyStmt *clone_stmt_impl () const override { return new EmptyStmt (*this); } | |
55 | }; | |
56 | ||
57 | /* Variable assignment let statement - type of "declaration statement" as it | |
58 | * introduces new name into scope */ | |
59 | class LetStmt : public Stmt | |
60 | { | |
61 | // bool has_outer_attrs; | |
62 | std::vector<Attribute> outer_attrs; | |
63 | ||
64 | std::unique_ptr<Pattern> variables_pattern; | |
65 | ||
66 | // bool has_type; | |
67 | std::unique_ptr<Type> type; | |
68 | ||
69 | // bool has_init_expr; | |
70 | std::unique_ptr<Expr> init_expr; | |
71 | ||
72 | Location locus; | |
73 | ||
74 | public: | |
75 | Type *inferedType; | |
76 | ||
77 | // Returns whether let statement has outer attributes. | |
78 | bool has_outer_attrs () const { return !outer_attrs.empty (); } | |
79 | ||
80 | // Returns whether let statement has a given return type. | |
81 | bool has_type () const { return type != nullptr; } | |
82 | ||
83 | // Returns whether let statement has an initialisation expression. | |
84 | bool has_init_expr () const { return init_expr != nullptr; } | |
85 | ||
86 | std::string as_string () const override; | |
87 | ||
88 | LetStmt (std::unique_ptr<Pattern> variables_pattern, | |
89 | std::unique_ptr<Expr> init_expr, std::unique_ptr<Type> type, | |
90 | std::vector<Attribute> outer_attrs, Location locus) | |
91 | : outer_attrs (std::move (outer_attrs)), | |
92 | variables_pattern (std::move (variables_pattern)), | |
93 | type (std::move (type)), init_expr (std::move (init_expr)), locus (locus) | |
94 | {} | |
95 | ||
96 | // Copy constructor with clone | |
97 | LetStmt (LetStmt const &other) | |
98 | : outer_attrs (other.outer_attrs), locus (other.locus) | |
99 | { | |
100 | // guard to prevent null dereference (only required if error state) | |
101 | if (other.variables_pattern != nullptr) | |
102 | variables_pattern = other.variables_pattern->clone_pattern (); | |
103 | ||
104 | // guard to prevent null dereference (always required) | |
105 | if (other.init_expr != nullptr) | |
106 | init_expr = other.init_expr->clone_expr (); | |
107 | if (other.type != nullptr) | |
108 | type = other.type->clone_type (); | |
109 | } | |
110 | ||
111 | // Overloaded assignment operator to clone | |
112 | LetStmt &operator= (LetStmt const &other) | |
113 | { | |
114 | outer_attrs = other.outer_attrs; | |
115 | locus = other.locus; | |
116 | ||
117 | // guard to prevent null dereference (only required if error state) | |
118 | if (other.variables_pattern != nullptr) | |
119 | variables_pattern = other.variables_pattern->clone_pattern (); | |
120 | else | |
121 | variables_pattern = nullptr; | |
122 | ||
123 | // guard to prevent null dereference (always required) | |
124 | if (other.init_expr != nullptr) | |
125 | init_expr = other.init_expr->clone_expr (); | |
126 | else | |
127 | init_expr = nullptr; | |
128 | if (other.type != nullptr) | |
129 | type = other.type->clone_type (); | |
130 | else | |
131 | type = nullptr; | |
132 | ||
133 | return *this; | |
134 | } | |
135 | ||
136 | // move constructors | |
137 | LetStmt (LetStmt &&other) = default; | |
138 | LetStmt &operator= (LetStmt &&other) = default; | |
139 | ||
140 | Location get_locus () const override final { return locus; } | |
141 | ||
142 | void accept_vis (ASTVisitor &vis) override; | |
143 | ||
144 | // Invalid if pattern is null, so base stripping on that. | |
145 | void mark_for_strip () override { variables_pattern = nullptr; } | |
146 | bool is_marked_for_strip () const override | |
147 | { | |
148 | return variables_pattern == nullptr; | |
149 | } | |
150 | ||
151 | // TODO: this mutable getter seems really dodgy. Think up better way. | |
152 | std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } | |
153 | const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } | |
154 | ||
155 | // TODO: is this better? Or is a "vis_block" better? | |
156 | std::unique_ptr<Expr> &get_init_expr () | |
157 | { | |
158 | rust_assert (has_init_expr ()); | |
159 | return init_expr; | |
160 | } | |
161 | ||
162 | std::unique_ptr<Pattern> &get_pattern () | |
163 | { | |
164 | rust_assert (variables_pattern != nullptr); | |
165 | return variables_pattern; | |
166 | } | |
167 | ||
168 | std::unique_ptr<Type> &get_type () | |
169 | { | |
170 | rust_assert (has_type ()); | |
171 | return type; | |
172 | } | |
173 | ||
174 | bool is_item () const override final { return false; } | |
175 | ||
176 | protected: | |
177 | /* Use covariance to implement clone function as returning this object rather | |
178 | * than base */ | |
179 | LetStmt *clone_stmt_impl () const override { return new LetStmt (*this); } | |
180 | }; | |
181 | ||
182 | /* Abstract base class for expression statements (statements containing an | |
183 | * expression) */ | |
184 | class ExprStmt : public Stmt | |
185 | { | |
186 | public: | |
187 | enum ExprStmtType | |
188 | { | |
189 | WITH_BLOCK, | |
190 | WITHOUT_BLOCK | |
191 | }; | |
192 | ||
193 | protected: | |
194 | Location locus; | |
195 | ||
196 | public: | |
197 | Location get_locus () const override final { return locus; } | |
198 | ||
199 | bool is_item () const override final { return false; } | |
200 | ||
201 | virtual ExprStmtType get_type () const = 0; | |
202 | ||
203 | protected: | |
204 | ExprStmt (Location locus) : locus (locus) {} | |
205 | }; | |
206 | ||
207 | /* Statement containing an expression without a block (or, due to technical | |
208 | * difficulties, can only be guaranteed to hold an expression). */ | |
209 | class ExprStmtWithoutBlock : public ExprStmt | |
210 | { | |
211 | // TODO: ensure that this works | |
212 | std::unique_ptr<ExprWithoutBlock> expr; | |
213 | /* HACK: cannot ensure type safety of ExprWithoutBlock due to Pratt parsing, | |
214 | * so have to store more general type of Expr. FIXME: fix this issue somehow | |
215 | * or redesign AST. */ | |
216 | // std::unique_ptr<Expr> expr; | |
217 | ||
218 | public: | |
219 | std::string as_string () const override; | |
220 | ||
221 | ExprStmtWithoutBlock (std::unique_ptr<ExprWithoutBlock> expr, Location locus) | |
222 | : ExprStmt (locus), expr (std::move (expr->to_stmt ())) | |
223 | {} | |
224 | ||
225 | /*ExprStmtWithoutBlock (std::unique_ptr<Expr> expr, Location locus) | |
226 | : ExprStmt (locus), expr (std::move (expr)) | |
227 | {}*/ | |
228 | ||
229 | // Copy constructor with clone | |
230 | ExprStmtWithoutBlock (ExprStmtWithoutBlock const &other) : ExprStmt (other) | |
231 | { | |
232 | // guard to prevent null dereference (only required if error state) | |
233 | if (other.expr != nullptr) | |
234 | expr = other.expr->clone_expr_without_block (); | |
235 | } | |
236 | /*ExprStmtWithoutBlock (ExprStmtWithoutBlock const &other) | |
237 | : ExprStmt (other), expr (other.expr->clone_expr ()) | |
238 | {}*/ | |
239 | ||
240 | // Overloaded assignment operator to clone | |
241 | ExprStmtWithoutBlock &operator= (ExprStmtWithoutBlock const &other) | |
242 | { | |
243 | ExprStmt::operator= (other); | |
244 | // expr = other.expr->clone_expr (); | |
245 | ||
246 | // guard to prevent null dereference (only required if error state) | |
247 | if (other.expr != nullptr) | |
248 | expr = other.expr->clone_expr_without_block (); | |
249 | else | |
250 | expr = nullptr; | |
251 | ||
252 | return *this; | |
253 | } | |
254 | ||
255 | // move constructors | |
256 | ExprStmtWithoutBlock (ExprStmtWithoutBlock &&other) = default; | |
257 | ExprStmtWithoutBlock &operator= (ExprStmtWithoutBlock &&other) = default; | |
258 | ||
259 | void accept_vis (ASTVisitor &vis) override; | |
260 | ||
261 | // Invalid if expr is null, so base stripping on that. | |
262 | void mark_for_strip () override { expr = nullptr; } | |
263 | bool is_marked_for_strip () const override { return expr == nullptr; } | |
264 | ||
265 | // TODO: is this better? Or is a "vis_block" better? | |
266 | std::unique_ptr<ExprWithoutBlock> &get_expr () | |
267 | { | |
268 | rust_assert (expr != nullptr); | |
269 | return expr; | |
270 | } | |
271 | ||
272 | ExprStmtType get_type () const override | |
273 | { | |
274 | return ExprStmtType::WITHOUT_BLOCK; | |
275 | }; | |
276 | ||
277 | protected: | |
278 | /* Use covariance to implement clone function as returning this object rather | |
279 | * than base */ | |
280 | ExprStmtWithoutBlock *clone_stmt_impl () const override | |
281 | { | |
282 | return new ExprStmtWithoutBlock (*this); | |
283 | } | |
284 | }; | |
285 | ||
286 | // Statement containing an expression with a block | |
287 | class ExprStmtWithBlock : public ExprStmt | |
288 | { | |
289 | std::unique_ptr<ExprWithBlock> expr; | |
290 | bool semicolon_followed; | |
291 | ||
292 | public: | |
293 | std::string as_string () const override; | |
294 | ||
295 | std::vector<LetStmt *> locals; | |
296 | ||
297 | ExprStmtWithBlock (std::unique_ptr<ExprWithBlock> expr, Location locus, | |
298 | bool semicolon_followed) | |
299 | : ExprStmt (locus), expr (std::move (expr)), | |
300 | semicolon_followed (semicolon_followed) | |
301 | {} | |
302 | ||
303 | // Copy constructor with clone | |
304 | ExprStmtWithBlock (ExprStmtWithBlock const &other) : ExprStmt (other) | |
305 | { | |
306 | // guard to prevent null dereference (only required if error state) | |
307 | if (other.expr != nullptr) | |
308 | expr = other.expr->clone_expr_with_block (); | |
309 | } | |
310 | ||
311 | // Overloaded assignment operator to clone | |
312 | ExprStmtWithBlock &operator= (ExprStmtWithBlock const &other) | |
313 | { | |
314 | ExprStmt::operator= (other); | |
315 | ||
316 | // guard to prevent null dereference (only required if error state) | |
317 | if (other.expr != nullptr) | |
318 | expr = other.expr->clone_expr_with_block (); | |
319 | else | |
320 | expr = nullptr; | |
321 | ||
322 | return *this; | |
323 | } | |
324 | ||
325 | // move constructors | |
326 | ExprStmtWithBlock (ExprStmtWithBlock &&other) = default; | |
327 | ExprStmtWithBlock &operator= (ExprStmtWithBlock &&other) = default; | |
328 | ||
329 | void accept_vis (ASTVisitor &vis) override; | |
330 | ||
331 | // Invalid if expr is null, so base stripping on that. | |
332 | void mark_for_strip () override { expr = nullptr; } | |
333 | bool is_marked_for_strip () const override { return expr == nullptr; } | |
334 | ||
335 | // TODO: is this better? Or is a "vis_block" better? | |
336 | std::unique_ptr<ExprWithBlock> &get_expr () | |
337 | { | |
338 | rust_assert (expr != nullptr); | |
339 | return expr; | |
340 | } | |
341 | ||
342 | bool is_semicolon_followed () const { return semicolon_followed; } | |
343 | ||
344 | ExprStmtType get_type () const override { return ExprStmtType::WITH_BLOCK; }; | |
345 | ||
346 | protected: | |
347 | /* Use covariance to implement clone function as returning this object rather | |
348 | * than base */ | |
349 | ExprStmtWithBlock *clone_stmt_impl () const override | |
350 | { | |
351 | return new ExprStmtWithBlock (*this); | |
352 | } | |
353 | }; | |
354 | ||
355 | } // namespace AST | |
356 | } // namespace Rust | |
357 | ||
358 | #endif |