Files
carbon-lang/explorer/ast/statement.h
T
Richard Smith 782bd87316 AST cloning mechanism (#2699)
This is intended to be used for template instantiation, but for now takes no stance as to what it's cloning.

This is tested by parsing and cloning all of our test files, and checking that the result of converting each AST to proto is the same as the result of cloning and then converting each AST to proto.
2023-03-21 12:36:05 -07:00

681 lines
22 KiB
C++

// 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 <utility>
#include <vector>
#include "common/ostream.h"
#include "explorer/ast/ast_node.h"
#include "explorer/ast/clone_context.h"
#include "explorer/ast/expression.h"
#include "explorer/ast/pattern.h"
#include "explorer/ast/return_term.h"
#include "explorer/ast/value_category.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<StatementKind>(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<Nonnull<Statement*>> 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<Nonnull<const Statement*>> {
return statements_;
}
auto statements() -> llvm::MutableArrayRef<Nonnull<Statement*>> {
return statements_;
}
private:
std::vector<Nonnull<Statement*>> statements_;
};
class ExpressionStatement : public Statement {
public:
ExpressionStatement(SourceLocation source_loc,
Nonnull<Expression*> 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*> 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<Expression*> lhs, AssignOperator op,
Nonnull<Expression*> 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<Expression*> rhs) { rhs_ = rhs; }
// Set the rewritten form of this statement. Can only be called during type
// checking.
auto set_rewritten_form(Nonnull<const Expression*> 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<Nonnull<const Expression*>> {
return rewritten_form_;
}
private:
Nonnull<Expression*> lhs_;
Nonnull<Expression*> rhs_;
AssignOperator op_;
std::optional<Nonnull<const Expression*>> rewritten_form_;
};
class IncrementDecrement : public Statement {
public:
IncrementDecrement(SourceLocation source_loc, Nonnull<Expression*> 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<const Expression*> 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<Nonnull<const Expression*>> {
return rewritten_form_;
}
private:
Nonnull<Expression*> argument_;
bool is_increment_;
std::optional<Nonnull<const Expression*>> rewritten_form_;
};
class VariableDefinition : public Statement {
public:
enum DefinitionType {
Var,
Returned,
};
VariableDefinition(SourceLocation source_loc, Nonnull<Pattern*> pattern,
std::optional<Nonnull<Expression*>> init,
ValueCategory value_category, DefinitionType def_type)
: Statement(AstNodeKind::VariableDefinition, source_loc),
pattern_(pattern),
init_(init),
value_category_(value_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_)),
value_category_(other.value_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<Expression*> init) {
CARBON_CHECK(has_init()) << "should not add a new initializer";
init_ = init;
}
auto value_category() const -> ValueCategory { return value_category_; }
auto is_returned() const -> bool { return def_type_ == Returned; };
private:
Nonnull<Pattern*> pattern_;
std::optional<Nonnull<Expression*>> init_;
ValueCategory value_category_;
const DefinitionType def_type_;
};
class If : public Statement {
public:
If(SourceLocation source_loc, Nonnull<Expression*> condition,
Nonnull<Block*> then_block, std::optional<Nonnull<Block*>> 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<Nonnull<const Block*>> {
return else_block_;
}
auto else_block() -> std::optional<Nonnull<Block*>> { return else_block_; }
// Can only be called by type-checking, if a conversion was required.
void set_condition(Nonnull<Expression*> condition) { condition_ = condition; }
private:
Nonnull<Expression*> condition_;
Nonnull<Block*> then_block_;
std::optional<Nonnull<Block*>> 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<CallableDeclaration*> 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<Nonnull<CallableDeclaration*>> 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<ValueNodeView> value_node_;
};
class ReturnExpression : public Return {
public:
ReturnExpression(Nonnull<Arena*> arena, SourceLocation source_loc)
: ReturnExpression(source_loc, arena->New<TupleLiteral>(source_loc),
true) {}
ReturnExpression(SourceLocation source_loc, Nonnull<Expression*> 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_ = expression;
}
private:
Nonnull<Expression*> expression_;
bool is_omitted_expression_;
};
class While : public Statement {
public:
While(SourceLocation source_loc, Nonnull<Expression*> condition,
Nonnull<Block*> 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<Expression*> condition) { condition_ = condition; }
private:
Nonnull<Expression*> condition_;
Nonnull<Block*> body_;
};
class For : public Statement {
public:
For(SourceLocation source_loc, Nonnull<BindingPattern*> variable_declaration,
Nonnull<Expression*> loop_target, Nonnull<Block*> 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<BindingPattern*> variable_declaration_;
Nonnull<Expression*> loop_target_;
Nonnull<Block*> 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<const Statement*> loop) {
CARBON_CHECK(!loop_.has_value());
loop_ = loop;
}
private:
std::optional<Nonnull<const Statement*>> 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<const Statement*> loop) {
CARBON_CHECK(!loop_.has_value());
loop_ = loop;
}
private:
std::optional<Nonnull<const Statement*>> loop_;
};
class Match : public Statement {
public:
class Clause {
public:
explicit Clause(Nonnull<Pattern*> pattern, Nonnull<Statement*> 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*> pattern_;
Nonnull<Statement*> statement_;
};
Match(SourceLocation source_loc, Nonnull<Expression*> expression,
std::vector<Clause> 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<Clause> { return clauses_; }
auto clauses() -> llvm::MutableArrayRef<Clause> { return clauses_; }
// Can only be called by type-checking, if a conversion was required.
void set_expression(Nonnull<Expression*> expression) {
expression_ = expression;
}
private:
Nonnull<Expression*> expression_;
std::vector<Clause> clauses_;
};
// A continuation statement.
//
// __continuation <continuation_variable> {
// <body>
// }
class Continuation : public Statement {
public:
using ImplementsCarbonValueNode = void;
Continuation(SourceLocation source_loc, std::string name,
Nonnull<Block*> body)
: Statement(AstNodeKind::Continuation, source_loc),
name_(std::move(name)),
body_(body) {}
explicit Continuation(CloneContext& context, const Continuation& other)
: Statement(context, other),
name_(other.name_),
body_(context.Clone(other.body_)),
static_type_(context.Clone(other.static_type_)) {}
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<const Value*> type) {
CARBON_CHECK(!static_type_.has_value());
static_type_ = type;
}
auto value_category() const -> ValueCategory { return ValueCategory::Var; }
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return std::nullopt;
}
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
return std::nullopt;
}
private:
std::string name_;
Nonnull<Block*> body_;
std::optional<Nonnull<const Value*>> static_type_;
};
// A run statement.
//
// __run <argument>;
class Run : public Statement {
public:
Run(SourceLocation source_loc, Nonnull<Expression*> argument)
: Statement(AstNodeKind::Run, source_loc), argument_(argument) {}
explicit Run(CloneContext& context, const Run& other)
: Statement(context, other), argument_(context.Clone(other.argument_)) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromRun(node->kind());
}
auto argument() const -> const Expression& { return *argument_; }
auto argument() -> Expression& { return *argument_; }
// Can only be called by type-checking, if a conversion was required.
void set_argument(Nonnull<Expression*> argument) { argument_ = argument; }
private:
Nonnull<Expression*> argument_;
};
// An await statement.
//
// __await;
class Await : public Statement {
public:
explicit Await(SourceLocation source_loc)
: Statement(AstNodeKind::Await, source_loc) {}
explicit Await(CloneContext& context, const Await& other)
: Statement(context, other) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromAwait(node->kind());
}
};
} // namespace Carbon
#endif // CARBON_EXPLORER_AST_STATEMENT_H_