| // Copyright (C) 2025 Free Software Foundation, Inc. |
| |
| // This file is part of GCC. |
| |
| // GCC is free software; you can redistribute it and/or modify it under |
| // the terms of the GNU General Public License as published by the Free |
| // Software Foundation; either version 3, or (at your option) any later |
| // version. |
| |
| // GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| // WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| // for more details. |
| |
| // You should have received a copy of the GNU General Public License |
| // along with GCC; see the file COPYING3. If not see |
| // <http://www.gnu.org/licenses/>. |
| |
| #ifndef RUST_DESUGAR_FOR_LOOPS_H |
| #define RUST_DESUGAR_FOR_LOOPS_H |
| |
| #include "rust-ast-builder.h" |
| #include "rust-expr.h" |
| |
| namespace Rust { |
| namespace AST { |
| |
| // Desugar for-loops into a set of other AST nodes. The desugar is of the |
| // following form: |
| // |
| // ``` |
| // for <pat> in <head> <body> |
| // ``` |
| // |
| // becomes: |
| // |
| // ``` |
| // { |
| // let result = match ::std::iter::IntoIterator::into_iter(<head>) { |
| // mut iter => { |
| // loop { |
| // let mut __next; |
| // match ::std::iter::Iterator::next(&mut iter) { |
| // ::std::option::Option::Some(val) => __next = val, |
| // ::std::option::Option::None => break |
| // }; |
| // let <pat> = __next; |
| // |
| // <body>; |
| // } |
| // } |
| // }; |
| // result |
| // } |
| // ``` |
| // |
| // NOTE: In a perfect world, this would be an immutable visitor which would take |
| // ownership of the AST node and return a new one, instead of mutating this one |
| // in place. Nevertheless, this isn't Rust, and doing immutable visitors in C++ |
| // sucks, and the world isn't perfect, so we are impure and sad. |
| // |
| // NOTE: This class could eventually be removed in favor of |
| // an HIR desugar. This would avoid mutating the AST and would be cleaner. |
| // However, it requires multiple changes in the way we do typechecking and name |
| // resolution, as this desugar creates new bindings. Because of this, these new |
| // bindings need to be inserted into the name-resolution context outside of the |
| // name resolution pass, which is difficult. Those bindings are needed because |
| // of the way the typechecker is currently structured, where it will fetch name |
| // resolution information in order to typecheck paths - which technically isn't |
| // necessary. |
| class DesugarForLoops |
| { |
| public: |
| static void go (std::unique_ptr<Expr> &ptr); |
| |
| private: |
| DesugarForLoops (); |
| |
| struct DesugarCtx |
| { |
| DesugarCtx (location_t loc) : builder (Builder (loc)), loc (loc) {} |
| |
| Builder builder; |
| location_t loc; |
| |
| MatchCase make_break_arm (); |
| MatchCase make_continue_arm (); |
| |
| constexpr static const char *continue_pattern_id = "#val"; |
| constexpr static const char *next_value_id = "#__next"; |
| constexpr static const char *iter_id = "#iter"; |
| constexpr static const char *result_id = "#result"; |
| }; |
| |
| std::unique_ptr<Expr> desugar (ForLoopExpr &expr); |
| }; |
| |
| } // namespace AST |
| } // namespace Rust |
| |
| #endif // ! RUST_DESUGAR_FOR_LOOPS_H |