// 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 "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/common/arena.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Compiler.h" namespace Carbon { class Statement { public: enum class Kind { ExpressionStatement, Assign, VariableDefinition, If, Return, Sequence, Block, While, Break, Continue, Match, Continuation, // Create a first-class continuation. Run, // Run a continuation to the next await or until it finishes. Await, // Pause execution of the continuation. }; void Print(llvm::raw_ostream& out) const { PrintDepth(-1, out); } void PrintDepth(int depth, llvm::raw_ostream& out) const; LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); } // Returns the enumerator corresponding to the most-derived type of this // object. auto kind() const -> Kind { return kind_; } auto source_loc() const -> SourceLocation { return source_loc_; } protected: // Constructs an Statement representing syntax at the given line number. // `kind` must be the enumerator corresponding to the most-derived type being // constructed. Statement(Kind kind, SourceLocation source_loc) : kind_(kind), source_loc_(source_loc) {} private: const Kind kind_; SourceLocation source_loc_; }; class ExpressionStatement : public Statement { public: ExpressionStatement(SourceLocation source_loc, Nonnull exp) : Statement(Kind::ExpressionStatement, source_loc), exp(exp) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::ExpressionStatement; } auto Exp() const -> Nonnull { return exp; } auto Exp() -> Nonnull { return exp; } private: Nonnull exp; }; class Assign : public Statement { public: Assign(SourceLocation source_loc, Nonnull lhs, Nonnull rhs) : Statement(Kind::Assign, source_loc), lhs(lhs), rhs(rhs) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Assign; } auto Lhs() const -> Nonnull { return lhs; } auto Lhs() -> Nonnull { return lhs; } auto Rhs() const -> Nonnull { return rhs; } auto Rhs() -> Nonnull { return rhs; } private: Nonnull lhs; Nonnull rhs; }; class VariableDefinition : public Statement { public: VariableDefinition(SourceLocation source_loc, Nonnull pat, Nonnull init) : Statement(Kind::VariableDefinition, source_loc), pat(pat), init(init) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::VariableDefinition; } auto Pat() const -> Nonnull { return pat; } auto Pat() -> Nonnull { return pat; } auto Init() const -> Nonnull { return init; } auto Init() -> Nonnull { return init; } private: Nonnull pat; Nonnull init; }; class If : public Statement { public: If(SourceLocation source_loc, Nonnull cond, Nonnull then_stmt, std::optional> else_stmt) : Statement(Kind::If, source_loc), cond(cond), then_stmt(then_stmt), else_stmt(else_stmt) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::If; } auto Cond() const -> Nonnull { return cond; } auto Cond() -> Nonnull { return cond; } auto ThenStmt() const -> Nonnull { return then_stmt; } auto ThenStmt() -> Nonnull { return then_stmt; } auto ElseStmt() const -> std::optional> { return else_stmt; } auto ElseStmt() -> std::optional> { return else_stmt; } private: Nonnull cond; Nonnull then_stmt; std::optional> else_stmt; }; class Return : public Statement { public: Return(Nonnull arena, SourceLocation source_loc) : Return(source_loc, arena->New(source_loc), true) {} Return(SourceLocation source_loc, Nonnull exp, bool is_omitted_exp) : Statement(Kind::Return, source_loc), exp(exp), is_omitted_exp(is_omitted_exp) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Return; } auto Exp() const -> Nonnull { return exp; } auto Exp() -> Nonnull { return exp; } auto IsOmittedExp() const -> bool { return is_omitted_exp; } private: Nonnull exp; bool is_omitted_exp; }; class Sequence : public Statement { public: Sequence(SourceLocation source_loc, Nonnull stmt, std::optional> next) : Statement(Kind::Sequence, source_loc), stmt(stmt), next(next) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Sequence; } auto Stmt() const -> Nonnull { return stmt; } auto Stmt() -> Nonnull { return stmt; } auto Next() const -> std::optional> { return next; } auto Next() -> std::optional> { return next; } private: Nonnull stmt; std::optional> next; }; class Block : public Statement { public: Block(SourceLocation source_loc, std::optional> stmt) : Statement(Kind::Block, source_loc), stmt(stmt) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Block; } auto Stmt() const -> std::optional> { return stmt; } auto Stmt() -> std::optional> { return stmt; } private: std::optional> stmt; }; class While : public Statement { public: While(SourceLocation source_loc, Nonnull cond, Nonnull body) : Statement(Kind::While, source_loc), cond(cond), body(body) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::While; } auto Cond() const -> Nonnull { return cond; } auto Cond() -> Nonnull { return cond; } auto Body() const -> Nonnull { return body; } auto Body() -> Nonnull { return body; } private: Nonnull cond; Nonnull body; }; class Break : public Statement { public: explicit Break(SourceLocation source_loc) : Statement(Kind::Break, source_loc) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Break; } }; class Continue : public Statement { public: explicit Continue(SourceLocation source_loc) : Statement(Kind::Continue, source_loc) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Continue; } }; 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(Kind::Match, source_loc), expression_(expression), clauses_(std::move(clauses)) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Match; } 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: Continuation(SourceLocation source_loc, std::string continuation_variable, Nonnull body) : Statement(Kind::Continuation, source_loc), continuation_variable(std::move(continuation_variable)), body(body) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Continuation; } auto ContinuationVariable() const -> const std::string& { return continuation_variable; } auto Body() const -> Nonnull { return body; } auto Body() -> Nonnull { return body; } private: std::string continuation_variable; Nonnull body; }; // A run statement. // // __run ; class Run : public Statement { public: Run(SourceLocation source_loc, Nonnull argument) : Statement(Kind::Run, source_loc), argument(argument) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Run; } auto Argument() const -> Nonnull { return argument; } auto Argument() -> Nonnull { return argument; } private: Nonnull argument; }; // An await statement. // // __await; class Await : public Statement { public: explicit Await(SourceLocation source_loc) : Statement(Kind::Await, source_loc) {} static auto classof(const Statement* stmt) -> bool { return stmt->kind() == Kind::Await; } }; } // namespace Carbon #endif // EXECUTABLE_SEMANTICS_AST_STATEMENT_H_