(root)/
gcc-13.2.0/
gcc/
rust/
ast/
rust-stmt.h
       1  // Copyright (C) 2020-2023 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 "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