// 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 EXECUTABLE_SEMANTICS_AST_STATEMENT_H_ #define EXECUTABLE_SEMANTICS_AST_STATEMENT_H_ #include #include #include "common/ostream.h" #include "executable_semantics/ast/expression.h" #include "executable_semantics/ast/pattern.h" #include "executable_semantics/ast/source_location.h" #include "executable_semantics/ast/static_scope.h" #include "executable_semantics/ast/value_category.h" #include "executable_semantics/common/arena.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Compiler.h" namespace Carbon { class FunctionDeclaration; class Statement : public AstNode { public: ~Statement() override = 0; void Print(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: Statement(AstNodeKind kind, SourceLocation source_loc) : AstNode(kind, source_loc) {} }; class Block : public Statement { public: Block(SourceLocation source_loc, std::vector> statements) : Statement(AstNodeKind::Block, source_loc), statements_(std::move(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) {} 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_; }; class Assign : public Statement { public: Assign(SourceLocation source_loc, Nonnull lhs, Nonnull rhs) : Statement(AstNodeKind::Assign, source_loc), lhs_(lhs), rhs_(rhs) {} 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_; } private: Nonnull lhs_; Nonnull rhs_; }; class VariableDefinition : public Statement { public: VariableDefinition(SourceLocation source_loc, Nonnull pattern, Nonnull init) : Statement(AstNodeKind::VariableDefinition, source_loc), pattern_(pattern), init_(init) {} 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& { return *init_; } auto init() -> Expression& { return *init_; } private: Nonnull pattern_; Nonnull init_; }; 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) {} 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_; } private: Nonnull condition_; Nonnull then_block_; std::optional> else_block_; }; class Return : public Statement { public: Return(Nonnull arena, SourceLocation source_loc) : Return(source_loc, arena->New(source_loc), true) {} Return(SourceLocation source_loc, Nonnull expression, bool is_omitted_expression) : Statement(AstNodeKind::Return, source_loc), expression_(expression), is_omitted_expression_(is_omitted_expression) {} static auto classof(const AstNode* node) -> bool { return InheritsFromReturn(node->kind()); } auto expression() const -> const Expression& { return *expression_; } auto expression() -> Expression& { return *expression_; } auto is_omitted_expression() const -> bool { return is_omitted_expression_; } // 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 FunctionDeclaration& { return **function_; } auto function() -> FunctionDeclaration& { return **function_; } // Can only be called once, by ResolveControlFlow. void set_function(Nonnull function) { CHECK(!function_.has_value()); function_ = function; } private: Nonnull expression_; bool is_omitted_expression_; std::optional> function_; }; class While : public Statement { public: While(SourceLocation source_loc, Nonnull condition, Nonnull body) : Statement(AstNodeKind::While, source_loc), condition_(condition), body_(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_; } private: Nonnull condition_; Nonnull body_; }; class Break : public Statement { public: explicit Break(SourceLocation source_loc) : Statement(AstNodeKind::Break, source_loc) {} 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) { 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) {} 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) { CHECK(!loop_.has_value()); loop_ = loop; } private: std::optional> loop_; }; class Match : public Statement { public: class Clause { public: Clause(Nonnull pattern, Nonnull statement) : pattern_(pattern), statement_(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)) {} 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_; } private: Nonnull expression_; std::vector clauses_; }; // A continuation statement. // // __continuation { // // } class Continuation : public Statement { public: using ImplementsCarbonNamedEntity = void; Continuation(SourceLocation source_loc, std::string name, Nonnull body) : Statement(AstNodeKind::Continuation, source_loc), name_(std::move(name)), body_(body) {} static auto classof(const AstNode* node) -> bool { return InheritsFromContinuation(node->kind()); } auto name() const -> const std::string& { return name_; } auto body() const -> const Block& { return *body_; } auto body() -> Block& { return *body_; } // The static type of the continuation. Cannot be called before typechecking. // // This will always be ContinuationType, but we must set it dynamically in // the typechecker because this code can't depend on ContinuationType. auto static_type() const -> const Value& { return **static_type_; } // Sets the static type of the continuation. Can only be called once, // during typechecking. void set_static_type(Nonnull type) { static_type_ = type; } // Returns whether the static type has been set. Should only be called // during typechecking: before typechecking it's guaranteed to be false, // and after typechecking it's guaranteed to be true. auto has_static_type() const -> bool { return static_type_.has_value(); } auto value_category() const -> ValueCategory { return ValueCategory::Var; } auto constant_value() const -> std::optional> { return std::nullopt; } private: std::string name_; Nonnull body_; std::optional> static_type_; }; // A run statement. // // __run ; class Run : public Statement { public: Run(SourceLocation source_loc, Nonnull argument) : Statement(AstNodeKind::Run, source_loc), argument_(argument) {} static auto classof(const AstNode* node) -> bool { return InheritsFromRun(node->kind()); } auto argument() const -> const Expression& { return *argument_; } auto argument() -> Expression& { return *argument_; } private: Nonnull argument_; }; // An await statement. // // __await; class Await : public Statement { public: explicit Await(SourceLocation source_loc) : Statement(AstNodeKind::Await, source_loc) {} static auto classof(const AstNode* node) -> bool { return InheritsFromAwait(node->kind()); } }; } // namespace Carbon #endif // EXECUTABLE_SEMANTICS_AST_STATEMENT_H_