// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef CARBON_EXPLORER_AST_STATEMENT_H_ #define CARBON_EXPLORER_AST_STATEMENT_H_ #include #include #include "common/ostream.h" #include "explorer/ast/ast_node.h" #include "explorer/ast/clone_context.h" #include "explorer/ast/expression.h" #include "explorer/ast/expression_category.h" #include "explorer/ast/pattern.h" #include "explorer/ast/return_term.h" #include "explorer/ast/value_node.h" #include "explorer/common/arena.h" #include "explorer/common/source_location.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Compiler.h" namespace Carbon { class CallableDeclaration; class Statement : public AstNode { public: ~Statement() override = 0; void Print(llvm::raw_ostream& out) const override { PrintDepth(-1, out); } void PrintID(llvm::raw_ostream& out) const override { PrintDepth(1, out); } void PrintDepth(int depth, llvm::raw_ostream& out) const; static auto classof(const AstNode* node) { return InheritsFromStatement(node->kind()); } // Returns the enumerator corresponding to the most-derived type of this // object. auto kind() const -> StatementKind { return static_cast(root_kind()); } protected: explicit Statement(AstNodeKind kind, SourceLocation source_loc) : AstNode(kind, source_loc) {} explicit Statement(CloneContext& context, const Statement& other) : AstNode(context, other) {} }; class Block : public Statement { public: Block(SourceLocation source_loc, std::vector> statements) : Statement(AstNodeKind::Block, source_loc), statements_(std::move(statements)) {} explicit Block(CloneContext& context, const Block& other) : Statement(context, other), statements_(context.Clone(other.statements_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromBlock(node->kind()); } auto statements() const -> llvm::ArrayRef> { return statements_; } auto statements() -> llvm::MutableArrayRef> { return statements_; } private: std::vector> statements_; }; class ExpressionStatement : public Statement { public: ExpressionStatement(SourceLocation source_loc, Nonnull expression) : Statement(AstNodeKind::ExpressionStatement, source_loc), expression_(expression) {} explicit ExpressionStatement(CloneContext& context, const ExpressionStatement& other) : Statement(context, other), expression_(context.Clone(other.expression_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromExpressionStatement(node->kind()); } auto expression() const -> const Expression& { return *expression_; } auto expression() -> Expression& { return *expression_; } private: Nonnull expression_; }; enum class AssignOperator { Plain, Add, Div, Mul, Mod, Sub, And, Or, Xor, ShiftLeft, ShiftRight, }; // Returns the spelling of this assignment operator token. auto AssignOperatorToString(AssignOperator op) -> std::string_view; class Assign : public Statement { public: Assign(SourceLocation source_loc, Nonnull lhs, AssignOperator op, Nonnull rhs) : Statement(AstNodeKind::Assign, source_loc), lhs_(lhs), rhs_(rhs), op_(op) {} explicit Assign(CloneContext& context, const Assign& other) : Statement(context, other), lhs_(context.Clone(other.lhs_)), rhs_(context.Clone(other.rhs_)), op_(other.op_), rewritten_form_(context.Clone(other.rewritten_form_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromAssign(node->kind()); } auto lhs() const -> const Expression& { return *lhs_; } auto lhs() -> Expression& { return *lhs_; } auto rhs() const -> const Expression& { return *rhs_; } auto rhs() -> Expression& { return *rhs_; } auto op() const -> AssignOperator { return op_; } // Can only be called by type-checking, if a conversion was required. void set_rhs(Nonnull rhs) { rhs_ = rhs; } // Set the rewritten form of this statement. Can only be called during type // checking. auto set_rewritten_form(Nonnull rewritten_form) -> void { CARBON_CHECK(!rewritten_form_.has_value()) << "rewritten form set twice"; rewritten_form_ = rewritten_form; } // Get the rewritten form of this statement. A rewritten form is used when // the statement is rewritten as a function call on an interface. A // rewritten form is not used when providing built-in operator semantics for // a plain assignment. auto rewritten_form() const -> std::optional> { return rewritten_form_; } private: Nonnull lhs_; Nonnull rhs_; AssignOperator op_; std::optional> rewritten_form_; }; class IncrementDecrement : public Statement { public: IncrementDecrement(SourceLocation source_loc, Nonnull argument, bool is_increment) : Statement(AstNodeKind::IncrementDecrement, source_loc), argument_(argument), is_increment_(is_increment) {} explicit IncrementDecrement(CloneContext& context, const IncrementDecrement& other) : Statement(context, other), argument_(context.Clone(other.argument_)), is_increment_(other.is_increment_), rewritten_form_(context.Clone(other.rewritten_form_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromIncrementDecrement(node->kind()); } auto argument() const -> const Expression& { return *argument_; } auto argument() -> Expression& { return *argument_; } auto is_increment() const -> bool { return is_increment_; } // Set the rewritten form of this statement. Can only be called during type // checking. auto set_rewritten_form(Nonnull rewritten_form) -> void { CARBON_CHECK(!rewritten_form_.has_value()) << "rewritten form set twice"; rewritten_form_ = rewritten_form; } // Get the rewritten form of this statement. auto rewritten_form() const -> std::optional> { return rewritten_form_; } private: Nonnull argument_; bool is_increment_; std::optional> rewritten_form_; }; class VariableDefinition : public Statement { public: enum DefinitionType { Var, Returned, }; VariableDefinition(SourceLocation source_loc, Nonnull pattern, std::optional> init, ExpressionCategory expression_category, DefinitionType def_type) : Statement(AstNodeKind::VariableDefinition, source_loc), pattern_(pattern), init_(init), expression_category_(expression_category), def_type_(def_type) {} explicit VariableDefinition(CloneContext& context, const VariableDefinition& other) : Statement(context, other), pattern_(context.Clone(other.pattern_)), init_(context.Clone(other.init_)), expression_category_(other.expression_category_), def_type_(other.def_type_) {} static auto classof(const AstNode* node) -> bool { return InheritsFromVariableDefinition(node->kind()); } auto pattern() const -> const Pattern& { return *pattern_; } auto pattern() -> Pattern& { return *pattern_; } auto init() const -> const Expression& { CARBON_CHECK(has_init()); return **init_; } auto init() -> Expression& { CARBON_CHECK(has_init()); return **init_; } auto has_init() const -> bool { return init_.has_value(); } // Can only be called by type-checking, if a conversion was required. void set_init(Nonnull init) { CARBON_CHECK(has_init()) << "should not add a new initializer"; init_ = init; } auto expression_category() const -> ExpressionCategory { return expression_category_; } auto is_returned() const -> bool { return def_type_ == Returned; }; private: Nonnull pattern_; std::optional> init_; ExpressionCategory expression_category_; const DefinitionType def_type_; }; class If : public Statement { public: If(SourceLocation source_loc, Nonnull condition, Nonnull then_block, std::optional> else_block) : Statement(AstNodeKind::If, source_loc), condition_(condition), then_block_(then_block), else_block_(else_block) {} explicit If(CloneContext& context, const If& other) : Statement(context, other), condition_(context.Clone(other.condition_)), then_block_(context.Clone(other.then_block_)), else_block_(context.Clone(other.else_block_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromIf(node->kind()); } auto condition() const -> const Expression& { return *condition_; } auto condition() -> Expression& { return *condition_; } auto then_block() const -> const Block& { return *then_block_; } auto then_block() -> Block& { return *then_block_; } auto else_block() const -> std::optional> { return else_block_; } auto else_block() -> std::optional> { return else_block_; } // Can only be called by type-checking, if a conversion was required. void set_condition(Nonnull condition) { condition_ = condition; } private: Nonnull condition_; Nonnull then_block_; std::optional> else_block_; }; class Return : public Statement { public: static auto classof(const AstNode* node) -> bool { return InheritsFromReturn(node->kind()); } // The AST node representing the function body this statement returns from. // Can only be called after ResolveControlFlow has visited this node. // // Note that this function does not represent an edge in the tree // structure of the AST: the return value is not a child of this node, // but an ancestor. auto function() const -> const CallableDeclaration& { return **function_; } auto function() -> CallableDeclaration& { return **function_; } // Can only be called once, by ResolveControlFlow. void set_function(Nonnull function) { CARBON_CHECK(!function_.has_value()); function_ = function; } protected: Return(AstNodeKind node_kind, SourceLocation source_loc) : Statement(node_kind, source_loc) {} explicit Return(CloneContext& context, const Return& other); private: std::optional> function_; }; class ReturnVar : public Return { public: explicit ReturnVar(SourceLocation source_loc) : Return(AstNodeKind::ReturnVar, source_loc) {} explicit ReturnVar(CloneContext& context, const ReturnVar& other) : Return(context, other), value_node_(context.Clone(other.value_node_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromReturnVar(node->kind()); } // Returns the value node of the BindingPattern of the returned var // definition. Cannot be called before name resolution. auto value_node() const -> const ValueNodeView& { return *value_node_; } // Can only be called once, by ResolveNames. void set_value_node(ValueNodeView value_node) { CARBON_CHECK(!value_node_.has_value()); value_node_ = value_node; } private: // The value node of the BindingPattern of the returned var definition. std::optional value_node_; }; class ReturnExpression : public Return { public: ReturnExpression(Nonnull arena, SourceLocation source_loc) : ReturnExpression(source_loc, arena->New(source_loc), true) {} ReturnExpression(SourceLocation source_loc, Nonnull expression, bool is_omitted_expression) : Return(AstNodeKind::ReturnExpression, source_loc), expression_(expression), is_omitted_expression_(is_omitted_expression) {} explicit ReturnExpression(CloneContext& context, const ReturnExpression& other) : Return(context, other), expression_(context.Clone(other.expression_)), is_omitted_expression_(other.is_omitted_expression_) {} static auto classof(const AstNode* node) -> bool { return InheritsFromReturnExpression(node->kind()); } auto expression() const -> const Expression& { return *expression_; } auto expression() -> Expression& { return *expression_; } auto is_omitted_expression() const -> bool { return is_omitted_expression_; } // Can only be called by type-checking, if a conversion was required. void set_expression(Nonnull expression) { expression_ = expression; } private: Nonnull expression_; bool is_omitted_expression_; }; class While : public Statement { public: While(SourceLocation source_loc, Nonnull condition, Nonnull body) : Statement(AstNodeKind::While, source_loc), condition_(condition), body_(body) {} explicit While(CloneContext& context, const While& other) : Statement(context, other), condition_(context.Clone(other.condition_)), body_(context.Clone(other.body_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromWhile(node->kind()); } auto condition() const -> const Expression& { return *condition_; } auto condition() -> Expression& { return *condition_; } auto body() const -> const Block& { return *body_; } auto body() -> Block& { return *body_; } // Can only be called by type-checking, if a conversion was required. void set_condition(Nonnull condition) { condition_ = condition; } private: Nonnull condition_; Nonnull body_; }; class For : public Statement { public: For(SourceLocation source_loc, Nonnull variable_declaration, Nonnull loop_target, Nonnull body) : Statement(AstNodeKind::For, source_loc), variable_declaration_(variable_declaration), loop_target_(loop_target), body_(body) {} explicit For(CloneContext& context, const For& other) : Statement(context, other), variable_declaration_(context.Clone(other.variable_declaration_)), loop_target_(context.Clone(other.loop_target_)), body_(context.Clone(other.body_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromFor(node->kind()); } auto variable_declaration() const -> const BindingPattern& { return *variable_declaration_; } auto variable_declaration() -> BindingPattern& { return *variable_declaration_; } auto loop_target() const -> const Expression& { return *loop_target_; } auto loop_target() -> Expression& { return *loop_target_; } auto body() const -> const Block& { return *body_; } auto body() -> Block& { return *body_; } private: Nonnull variable_declaration_; Nonnull loop_target_; Nonnull body_; }; class Break : public Statement { public: explicit Break(SourceLocation source_loc) : Statement(AstNodeKind::Break, source_loc) {} explicit Break(CloneContext& context, const Break& other) : Statement(context, other), loop_(context.Clone(other.loop_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromBreak(node->kind()); } // The AST node representing the loop this statement breaks out of. // Can only be called after ResolveControlFlow has visited this node. // // Note that this function does not represent an edge in the tree // structure of the AST: the return value is not a child of this node, // but an ancestor. auto loop() const -> const Statement& { return **loop_; } // Can only be called once, by ResolveControlFlow. void set_loop(Nonnull loop) { CARBON_CHECK(!loop_.has_value()); loop_ = loop; } private: std::optional> loop_; }; class Continue : public Statement { public: explicit Continue(SourceLocation source_loc) : Statement(AstNodeKind::Continue, source_loc) {} explicit Continue(CloneContext& context, const Continue& other) : Statement(context, other), loop_(context.Clone(other.loop_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromContinue(node->kind()); } // The AST node representing the loop this statement continues. // Can only be called after ResolveControlFlow has visited this node. // // Note that this function does not represent an edge in the tree // structure of the AST: the return value is not a child of this node, // but an ancestor. auto loop() const -> const Statement& { return **loop_; } // Can only be called once, by ResolveControlFlow. void set_loop(Nonnull loop) { CARBON_CHECK(!loop_.has_value()); loop_ = loop; } private: std::optional> loop_; }; class Match : public Statement { public: class Clause { public: explicit Clause(Nonnull pattern, Nonnull statement) : pattern_(pattern), statement_(statement) {} explicit Clause(CloneContext& context, const Clause& other) : pattern_(context.Clone(other.pattern_)), statement_(context.Clone(other.statement_)) {} auto pattern() const -> const Pattern& { return *pattern_; } auto pattern() -> Pattern& { return *pattern_; } auto statement() const -> const Statement& { return *statement_; } auto statement() -> Statement& { return *statement_; } private: Nonnull pattern_; Nonnull statement_; }; Match(SourceLocation source_loc, Nonnull expression, std::vector clauses) : Statement(AstNodeKind::Match, source_loc), expression_(expression), clauses_(std::move(clauses)) {} explicit Match(CloneContext& context, const Match& other) : Statement(context, other), expression_(context.Clone(other.expression_)), clauses_(context.Clone(other.clauses_)) {} static auto classof(const AstNode* node) -> bool { return InheritsFromMatch(node->kind()); } auto expression() const -> const Expression& { return *expression_; } auto expression() -> Expression& { return *expression_; } auto clauses() const -> llvm::ArrayRef { return clauses_; } auto clauses() -> llvm::MutableArrayRef { return clauses_; } // Can only be called by type-checking, if a conversion was required. void set_expression(Nonnull expression) { expression_ = expression; } private: Nonnull expression_; std::vector clauses_; }; } // namespace Carbon #endif // CARBON_EXPLORER_AST_STATEMENT_H_