mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Define a base class for all AST nodes. (#947)
Also implement code-generation to manage the resulting boilerplate.
This commit is contained in:
@@ -14,6 +14,27 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "ast_node",
|
||||
srcs = ["ast_node.cpp"],
|
||||
hdrs = [
|
||||
"ast_node.h",
|
||||
"ast_rtti.h",
|
||||
],
|
||||
deps = [
|
||||
":source_location",
|
||||
],
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "ast_rtti",
|
||||
srcs = ["ast_rtti.txt"],
|
||||
outs = ["ast_rtti.h"],
|
||||
cmd = "./$(location //executable_semantics:gen_rtti)" +
|
||||
" $(location ast_rtti.txt) > \"$@\"",
|
||||
tools = ["//executable_semantics:gen_rtti"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "declaration",
|
||||
srcs = ["declaration.cpp"],
|
||||
@@ -21,6 +42,7 @@ cc_library(
|
||||
"declaration.h",
|
||||
],
|
||||
deps = [
|
||||
":ast_node",
|
||||
":member",
|
||||
":pattern",
|
||||
":source_location",
|
||||
@@ -37,6 +59,7 @@ cc_library(
|
||||
srcs = ["expression.cpp"],
|
||||
hdrs = ["expression.h"],
|
||||
deps = [
|
||||
":ast_node",
|
||||
":paren_contents",
|
||||
"//common:indirect_value",
|
||||
"//common:ostream",
|
||||
@@ -86,6 +109,7 @@ cc_library(
|
||||
srcs = ["pattern.cpp"],
|
||||
hdrs = ["pattern.h"],
|
||||
deps = [
|
||||
":ast_node",
|
||||
":expression",
|
||||
":source_location",
|
||||
":static_scope",
|
||||
@@ -112,6 +136,7 @@ cc_library(
|
||||
srcs = ["static_scope.cpp"],
|
||||
hdrs = ["static_scope.h"],
|
||||
deps = [
|
||||
":ast_node",
|
||||
":source_location",
|
||||
"//executable_semantics/common:arena",
|
||||
"//executable_semantics/common:error",
|
||||
@@ -132,6 +157,7 @@ cc_library(
|
||||
srcs = ["statement.cpp"],
|
||||
hdrs = ["statement.h"],
|
||||
deps = [
|
||||
":ast_node",
|
||||
":expression",
|
||||
":pattern",
|
||||
":source_location",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// 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
|
||||
|
||||
#include "executable_semantics/ast/ast_node.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
AstNode::~AstNode() = default;
|
||||
|
||||
} // namespace Carbon
|
||||
@@ -0,0 +1,74 @@
|
||||
// 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_AST_NODE_H_
|
||||
#define EXECUTABLE_SEMANTICS_AST_AST_NODE_H_
|
||||
|
||||
#include "executable_semantics/ast/ast_rtti.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
// Base class for all nodes in the AST.
|
||||
//
|
||||
// Every class derived from this class must be listed in ast_rtti.txt. See
|
||||
// the documentation of gen_rtti.py for details about the format. As a result,
|
||||
// every abstract class `Foo` will have a `FooKind` enumerated type, whose
|
||||
// enumerators correspond to the subclasses of `Foo`.
|
||||
//
|
||||
// AstNode and its derived classes support LLVM-style RTTI, including
|
||||
// llvm::isa, llvm::cast, and llvm::dyn_cast. To support this, every
|
||||
// class derived from Declaration must provide a `classof` operation, with
|
||||
// the following form, where `Foo` is the name of the derived class:
|
||||
//
|
||||
// static auto classof(const AstNode* node) -> bool {
|
||||
// return InheritsFromFoo(node->kind());
|
||||
// }
|
||||
//
|
||||
// Furthermore, if the class is abstract, it must provide a `kind()` operation,
|
||||
// with the following form:
|
||||
//
|
||||
// auto kind() const -> FooKind { return static_cast<FooKind>(root_kind()); }
|
||||
//
|
||||
// The definitions of `InheritsFromFoo` and `FooKind` are generated from
|
||||
// ast_rtti.txt, and are implicitly provided by this header.
|
||||
//
|
||||
// When inheriting from this class, the inheritance must me marked `virtual`.
|
||||
//
|
||||
// TODO: To support generic traversal, add children() method, and ensure that
|
||||
// all AstNodes are reachable from a root AstNode.
|
||||
class AstNode {
|
||||
public:
|
||||
AstNode(AstNode&&) = delete;
|
||||
auto operator=(AstNode&&) -> AstNode& = delete;
|
||||
virtual ~AstNode() = 0;
|
||||
|
||||
// Returns an enumerator specifying the concrete type of this node.
|
||||
//
|
||||
// Abstract subclasses of AstNode will provide their own `kind()` method
|
||||
// which hides this one, and provides a narrower return type.
|
||||
auto kind() const -> AstNodeKind { return kind_; }
|
||||
|
||||
// The location of the code described by this node.
|
||||
auto source_loc() const -> SourceLocation { return source_loc_; }
|
||||
|
||||
protected:
|
||||
// Constructs an AstNode representing code at the given location. `kind`
|
||||
// must be the enumerator that exactly matches the concrete type being
|
||||
// constructed.
|
||||
explicit AstNode(AstNodeKind kind, SourceLocation source_loc)
|
||||
: kind_(kind), source_loc_(source_loc) {}
|
||||
|
||||
// Equivalent to kind(), but will not be hidden by `kind()` methods of
|
||||
// derived classes.
|
||||
auto root_kind() const -> AstNodeKind { return kind_; }
|
||||
|
||||
private:
|
||||
AstNodeKind kind_;
|
||||
SourceLocation source_loc_;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // EXECUTABLE_SEMANTICS_AST_AST_NODE_H_
|
||||
@@ -0,0 +1,54 @@
|
||||
# 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
|
||||
|
||||
root class AstNode;
|
||||
interface class NamedEntity : AstNode;
|
||||
abstract class Pattern : AstNode;
|
||||
class AutoPattern : Pattern;
|
||||
class BindingPattern : Pattern, NamedEntity;
|
||||
class TuplePattern : Pattern;
|
||||
class AlternativePattern : Pattern;
|
||||
class ExpressionPattern : Pattern;
|
||||
abstract class Declaration : AstNode, NamedEntity;
|
||||
class FunctionDeclaration : Declaration;
|
||||
class ClassDeclaration : Declaration;
|
||||
class ChoiceDeclaration : Declaration;
|
||||
class VariableDeclaration : Declaration;
|
||||
class GenericBinding : AstNode, NamedEntity;
|
||||
class AlternativeSignature : AstNode, NamedEntity;
|
||||
abstract class Statement : AstNode;
|
||||
class ExpressionStatement : Statement;
|
||||
class Assign : Statement;
|
||||
class VariableDefinition : Statement;
|
||||
class If : Statement;
|
||||
class Return : Statement;
|
||||
class Block : Statement;
|
||||
class While : Statement;
|
||||
class Break : Statement;
|
||||
class Continue : Statement;
|
||||
class Match : Statement;
|
||||
class Continuation : Statement, NamedEntity;
|
||||
class Run : Statement;
|
||||
class Await : Statement;
|
||||
abstract class Expression : AstNode;
|
||||
class BoolTypeLiteral : Expression;
|
||||
class BoolLiteral : Expression;
|
||||
class CallExpression : Expression;
|
||||
class FunctionTypeLiteral : Expression;
|
||||
class FieldAccessExpression : Expression;
|
||||
class IndexExpression : Expression;
|
||||
class IntTypeLiteral : Expression;
|
||||
class ContinuationTypeLiteral : Expression;
|
||||
class IntLiteral : Expression;
|
||||
class PrimitiveOperatorExpression : Expression;
|
||||
class StringLiteral : Expression;
|
||||
class StringTypeLiteral : Expression;
|
||||
class TupleLiteral : Expression;
|
||||
class StructLiteral : Expression;
|
||||
class StructTypeLiteral : Expression;
|
||||
class TypeTypeLiteral : Expression;
|
||||
class IdentifierExpression : Expression;
|
||||
class IntrinsicExpression : Expression;
|
||||
abstract class Member : AstNode;
|
||||
class FieldMember : Member, NamedEntity;
|
||||
@@ -10,13 +10,15 @@ namespace Carbon {
|
||||
|
||||
using llvm::cast;
|
||||
|
||||
Declaration::~Declaration() = default;
|
||||
|
||||
void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
switch (kind()) {
|
||||
case Kind::FunctionDeclaration:
|
||||
case DeclarationKind::FunctionDeclaration:
|
||||
cast<FunctionDeclaration>(*this).PrintDepth(-1, out);
|
||||
break;
|
||||
|
||||
case Kind::ClassDeclaration: {
|
||||
case DeclarationKind::ClassDeclaration: {
|
||||
const auto& class_decl = cast<ClassDeclaration>(*this);
|
||||
out << "class " << class_decl.name() << " {\n";
|
||||
for (Nonnull<Member*> m : class_decl.members()) {
|
||||
@@ -26,18 +28,17 @@ void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
break;
|
||||
}
|
||||
|
||||
case Kind::ChoiceDeclaration: {
|
||||
case DeclarationKind::ChoiceDeclaration: {
|
||||
const auto& choice = cast<ChoiceDeclaration>(*this);
|
||||
out << "choice " << choice.name() << " {\n";
|
||||
for (Nonnull<const ChoiceDeclaration::Alternative*> alt :
|
||||
choice.alternatives()) {
|
||||
for (Nonnull<const AlternativeSignature*> alt : choice.alternatives()) {
|
||||
out << "alt " << alt->name() << " " << alt->signature() << ";\n";
|
||||
}
|
||||
out << "}\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case Kind::VariableDeclaration: {
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
const auto& var = cast<VariableDeclaration>(*this);
|
||||
out << "var " << var.binding() << " = " << var.initializer() << "\n";
|
||||
break;
|
||||
|
||||
@@ -31,14 +31,9 @@ class StaticScope;
|
||||
// every concrete derived class must have a corresponding enumerator
|
||||
// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
|
||||
// details.
|
||||
class Declaration : public NamedEntityInterface {
|
||||
class Declaration : public virtual AstNode, public NamedEntity {
|
||||
public:
|
||||
enum class Kind {
|
||||
FunctionDeclaration,
|
||||
ClassDeclaration,
|
||||
ChoiceDeclaration,
|
||||
VariableDeclaration,
|
||||
};
|
||||
~Declaration() override = 0;
|
||||
|
||||
Declaration(const Member&) = delete;
|
||||
auto operator=(const Member&) -> Declaration& = delete;
|
||||
@@ -46,15 +41,15 @@ class Declaration : public NamedEntityInterface {
|
||||
void Print(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 named_entity_kind() const -> NamedEntityKind override {
|
||||
return NamedEntityKind::Declaration;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromDeclaration(node->kind());
|
||||
}
|
||||
|
||||
auto source_loc() const -> SourceLocation override { return source_loc_; }
|
||||
// Returns the enumerator corresponding to the most-derived type of this
|
||||
// object.
|
||||
auto kind() const -> DeclarationKind {
|
||||
return static_cast<DeclarationKind>(root_kind());
|
||||
}
|
||||
|
||||
// The static type of the declared entity. Cannot be called before
|
||||
// typechecking.
|
||||
@@ -73,33 +68,30 @@ class Declaration : public NamedEntityInterface {
|
||||
// Constructs a Declaration representing syntax at the given line number.
|
||||
// `kind` must be the enumerator corresponding to the most-derived type being
|
||||
// constructed.
|
||||
Declaration(Kind kind, SourceLocation source_loc)
|
||||
: kind_(kind), source_loc_(source_loc) {}
|
||||
Declaration() = default;
|
||||
|
||||
private:
|
||||
const Kind kind_;
|
||||
SourceLocation source_loc_;
|
||||
std::optional<Nonnull<const Value*>> static_type_;
|
||||
};
|
||||
|
||||
// TODO: expand the kinds of things that can be deduced parameters.
|
||||
// For now, only generic parameters are supported.
|
||||
struct GenericBinding : public NamedEntityInterface {
|
||||
struct GenericBinding : public virtual AstNode, public NamedEntity {
|
||||
public:
|
||||
GenericBinding(SourceLocation source_loc, std::string name,
|
||||
Nonnull<Expression*> type)
|
||||
: source_loc_(source_loc), name_(std::move(name)), type_(type) {}
|
||||
: AstNode(AstNodeKind::GenericBinding, source_loc),
|
||||
name_(std::move(name)),
|
||||
type_(type) {}
|
||||
|
||||
auto named_entity_kind() const -> NamedEntityKind override {
|
||||
return NamedEntityKind::GenericBinding;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromGenericBinding(node->kind());
|
||||
}
|
||||
|
||||
auto source_loc() const -> SourceLocation override { return source_loc_; }
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto type() const -> const Expression& { return *type_; }
|
||||
|
||||
private:
|
||||
SourceLocation source_loc_;
|
||||
std::string name_;
|
||||
Nonnull<Expression*> type_;
|
||||
};
|
||||
@@ -190,15 +182,15 @@ class FunctionDeclaration : public Declaration {
|
||||
Nonnull<TuplePattern*> param_pattern,
|
||||
ReturnTerm return_term,
|
||||
std::optional<Nonnull<Block*>> body)
|
||||
: Declaration(Kind::FunctionDeclaration, source_loc),
|
||||
: AstNode(AstNodeKind::FunctionDeclaration, source_loc),
|
||||
name_(std::move(name)),
|
||||
deduced_parameters_(std::move(deduced_params)),
|
||||
param_pattern_(param_pattern),
|
||||
return_term_(return_term),
|
||||
body_(body) {}
|
||||
|
||||
static auto classof(const Declaration* decl) -> bool {
|
||||
return decl->kind() == Kind::FunctionDeclaration;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromFunctionDeclaration(node->kind());
|
||||
}
|
||||
|
||||
void PrintDepth(int depth, llvm::raw_ostream& out) const;
|
||||
@@ -232,12 +224,12 @@ class ClassDeclaration : public Declaration {
|
||||
public:
|
||||
ClassDeclaration(SourceLocation source_loc, std::string name,
|
||||
std::vector<Nonnull<Member*>> members)
|
||||
: Declaration(Kind::ClassDeclaration, source_loc),
|
||||
: AstNode(AstNodeKind::ClassDeclaration, source_loc),
|
||||
name_(std::move(name)),
|
||||
members_(std::move(members)) {}
|
||||
|
||||
static auto classof(const Declaration* decl) -> bool {
|
||||
return decl->kind() == Kind::ClassDeclaration;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromClassDeclaration(node->kind());
|
||||
}
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
@@ -253,42 +245,41 @@ class ClassDeclaration : public Declaration {
|
||||
StaticScope static_scope_;
|
||||
};
|
||||
|
||||
class ChoiceDeclaration : public Declaration {
|
||||
class AlternativeSignature : public virtual AstNode, public NamedEntity {
|
||||
public:
|
||||
class Alternative : public NamedEntityInterface {
|
||||
public:
|
||||
Alternative(SourceLocation source_loc, std::string name,
|
||||
Nonnull<Expression*> signature)
|
||||
: source_loc_(source_loc),
|
||||
name_(std::move(name)),
|
||||
signature_(signature) {}
|
||||
|
||||
auto named_entity_kind() const -> NamedEntityKind override {
|
||||
return NamedEntityKind::ChoiceDeclarationAlternative;
|
||||
}
|
||||
|
||||
auto source_loc() const -> SourceLocation override { return source_loc_; }
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto signature() const -> const Expression& { return *signature_; }
|
||||
|
||||
private:
|
||||
SourceLocation source_loc_;
|
||||
std::string name_;
|
||||
Nonnull<Expression*> signature_;
|
||||
};
|
||||
|
||||
ChoiceDeclaration(SourceLocation source_loc, std::string name,
|
||||
std::vector<Nonnull<Alternative*>> alternatives)
|
||||
: Declaration(Kind::ChoiceDeclaration, source_loc),
|
||||
AlternativeSignature(SourceLocation source_loc, std::string name,
|
||||
Nonnull<Expression*> signature)
|
||||
: AstNode(AstNodeKind::AlternativeSignature, source_loc),
|
||||
name_(std::move(name)),
|
||||
alternatives_(std::move(alternatives)) {}
|
||||
signature_(signature) {}
|
||||
|
||||
static auto classof(const Declaration* decl) -> bool {
|
||||
return decl->kind() == Kind::ChoiceDeclaration;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromAlternativeSignature(node->kind());
|
||||
}
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto alternatives() const -> llvm::ArrayRef<Nonnull<const Alternative*>> {
|
||||
auto signature() const -> const Expression& { return *signature_; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
Nonnull<Expression*> signature_;
|
||||
};
|
||||
|
||||
class ChoiceDeclaration : public Declaration {
|
||||
public:
|
||||
ChoiceDeclaration(SourceLocation source_loc, std::string name,
|
||||
std::vector<Nonnull<AlternativeSignature*>> alternatives)
|
||||
: AstNode(AstNodeKind::ChoiceDeclaration, source_loc),
|
||||
name_(std::move(name)),
|
||||
alternatives_(std::move(alternatives)) {}
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromChoiceDeclaration(node->kind());
|
||||
}
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto alternatives() const
|
||||
-> llvm::ArrayRef<Nonnull<const AlternativeSignature*>> {
|
||||
return alternatives_;
|
||||
}
|
||||
|
||||
@@ -298,7 +289,7 @@ class ChoiceDeclaration : public Declaration {
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<Nonnull<Alternative*>> alternatives_;
|
||||
std::vector<Nonnull<AlternativeSignature*>> alternatives_;
|
||||
StaticScope static_scope_;
|
||||
};
|
||||
|
||||
@@ -308,12 +299,12 @@ class VariableDeclaration : public Declaration {
|
||||
VariableDeclaration(SourceLocation source_loc,
|
||||
Nonnull<BindingPattern*> binding,
|
||||
Nonnull<Expression*> initializer)
|
||||
: Declaration(Kind::VariableDeclaration, source_loc),
|
||||
: AstNode(AstNodeKind::VariableDeclaration, source_loc),
|
||||
binding_(binding),
|
||||
initializer_(initializer) {}
|
||||
|
||||
static auto classof(const Declaration* decl) -> bool {
|
||||
return decl->kind() == Kind::VariableDeclaration;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromVariableDeclaration(node->kind());
|
||||
}
|
||||
|
||||
auto binding() const -> const BindingPattern& { return *binding_; }
|
||||
|
||||
@@ -34,6 +34,8 @@ auto TupleExpressionFromParenContents(
|
||||
return arena->New<TupleLiteral>(source_loc, paren_contents.elements);
|
||||
}
|
||||
|
||||
Expression::~Expression() = default;
|
||||
|
||||
static void PrintOp(llvm::raw_ostream& out, Operator op) {
|
||||
switch (op) {
|
||||
case Operator::Add:
|
||||
@@ -74,17 +76,17 @@ static void PrintFields(llvm::raw_ostream& out,
|
||||
|
||||
void Expression::Print(llvm::raw_ostream& out) const {
|
||||
switch (kind()) {
|
||||
case Expression::Kind::IndexExpression: {
|
||||
case ExpressionKind::IndexExpression: {
|
||||
const auto& index = cast<IndexExpression>(*this);
|
||||
out << index.aggregate() << "[" << index.offset() << "]";
|
||||
break;
|
||||
}
|
||||
case Expression::Kind::FieldAccessExpression: {
|
||||
case ExpressionKind::FieldAccessExpression: {
|
||||
const auto& access = cast<FieldAccessExpression>(*this);
|
||||
out << access.aggregate() << "." << access.field();
|
||||
break;
|
||||
}
|
||||
case Expression::Kind::TupleLiteral: {
|
||||
case ExpressionKind::TupleLiteral: {
|
||||
out << "(";
|
||||
llvm::ListSeparator sep;
|
||||
for (Nonnull<const Expression*> field :
|
||||
@@ -94,25 +96,25 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
out << ")";
|
||||
break;
|
||||
}
|
||||
case Expression::Kind::StructLiteral:
|
||||
case ExpressionKind::StructLiteral:
|
||||
out << "{";
|
||||
PrintFields(out, cast<StructLiteral>(*this).fields(), " = ");
|
||||
out << "}";
|
||||
break;
|
||||
case Expression::Kind::StructTypeLiteral:
|
||||
case ExpressionKind::StructTypeLiteral:
|
||||
out << "{";
|
||||
PrintFields(out, cast<StructTypeLiteral>(*this).fields(), ": ");
|
||||
out << "}";
|
||||
break;
|
||||
case Expression::Kind::IntLiteral:
|
||||
case ExpressionKind::IntLiteral:
|
||||
out << cast<IntLiteral>(*this).value();
|
||||
break;
|
||||
case Expression::Kind::BoolLiteral:
|
||||
case ExpressionKind::BoolLiteral:
|
||||
out << (cast<BoolLiteral>(*this).value() ? "true" : "false");
|
||||
break;
|
||||
case Expression::Kind::PrimitiveOperatorExpression: {
|
||||
case ExpressionKind::PrimitiveOperatorExpression: {
|
||||
out << "(";
|
||||
PrimitiveOperatorExpression op = cast<PrimitiveOperatorExpression>(*this);
|
||||
const auto& op = cast<PrimitiveOperatorExpression>(*this);
|
||||
switch (op.arguments().size()) {
|
||||
case 0:
|
||||
PrintOp(out, op.op());
|
||||
@@ -132,10 +134,10 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
out << ")";
|
||||
break;
|
||||
}
|
||||
case Expression::Kind::IdentifierExpression:
|
||||
case ExpressionKind::IdentifierExpression:
|
||||
out << cast<IdentifierExpression>(*this).name();
|
||||
break;
|
||||
case Expression::Kind::CallExpression: {
|
||||
case ExpressionKind::CallExpression: {
|
||||
const auto& call = cast<CallExpression>(*this);
|
||||
out << call.function();
|
||||
if (isa<TupleLiteral>(call.argument())) {
|
||||
@@ -145,32 +147,32 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Expression::Kind::BoolTypeLiteral:
|
||||
case ExpressionKind::BoolTypeLiteral:
|
||||
out << "Bool";
|
||||
break;
|
||||
case Expression::Kind::IntTypeLiteral:
|
||||
case ExpressionKind::IntTypeLiteral:
|
||||
out << "i32";
|
||||
break;
|
||||
case Expression::Kind::StringLiteral:
|
||||
case ExpressionKind::StringLiteral:
|
||||
out << "\"";
|
||||
out.write_escaped(cast<StringLiteral>(*this).value());
|
||||
out << "\"";
|
||||
break;
|
||||
case Expression::Kind::StringTypeLiteral:
|
||||
case ExpressionKind::StringTypeLiteral:
|
||||
out << "String";
|
||||
break;
|
||||
case Expression::Kind::TypeTypeLiteral:
|
||||
case ExpressionKind::TypeTypeLiteral:
|
||||
out << "Type";
|
||||
break;
|
||||
case Expression::Kind::ContinuationTypeLiteral:
|
||||
case ExpressionKind::ContinuationTypeLiteral:
|
||||
out << "Continuation";
|
||||
break;
|
||||
case Expression::Kind::FunctionTypeLiteral: {
|
||||
case ExpressionKind::FunctionTypeLiteral: {
|
||||
const auto& fn = cast<FunctionTypeLiteral>(*this);
|
||||
out << "fn " << fn.parameter() << " -> " << fn.return_type();
|
||||
break;
|
||||
}
|
||||
case Expression::Kind::IntrinsicExpression:
|
||||
case ExpressionKind::IntrinsicExpression:
|
||||
out << "intrinsic_expression(";
|
||||
switch (cast<IntrinsicExpression>(*this).intrinsic()) {
|
||||
case IntrinsicExpression::Intrinsic::Print:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/ast_node.h"
|
||||
#include "executable_semantics/ast/paren_contents.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/common/arena.h"
|
||||
@@ -21,37 +22,22 @@ namespace Carbon {
|
||||
|
||||
class Value;
|
||||
|
||||
class Expression {
|
||||
class Expression : public virtual AstNode {
|
||||
public:
|
||||
enum class Kind {
|
||||
BoolTypeLiteral,
|
||||
BoolLiteral,
|
||||
CallExpression,
|
||||
FunctionTypeLiteral,
|
||||
FieldAccessExpression,
|
||||
IndexExpression,
|
||||
IntTypeLiteral,
|
||||
ContinuationTypeLiteral, // The type of a continuation value.
|
||||
IntLiteral,
|
||||
PrimitiveOperatorExpression,
|
||||
StringLiteral,
|
||||
StringTypeLiteral,
|
||||
TupleLiteral,
|
||||
StructLiteral,
|
||||
StructTypeLiteral,
|
||||
TypeTypeLiteral,
|
||||
IdentifierExpression,
|
||||
IntrinsicExpression,
|
||||
};
|
||||
~Expression() override = 0;
|
||||
|
||||
void Print(llvm::raw_ostream& out) const;
|
||||
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
|
||||
|
||||
static auto classof(const AstNode* node) {
|
||||
return InheritsFromExpression(node->kind());
|
||||
}
|
||||
|
||||
// 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_; }
|
||||
auto kind() const -> ExpressionKind {
|
||||
return static_cast<ExpressionKind>(root_kind());
|
||||
}
|
||||
|
||||
// The static type of this expression. Cannot be called before typechecking.
|
||||
auto static_type() const -> const Value& { return **static_type_; }
|
||||
@@ -69,13 +55,9 @@ class Expression {
|
||||
// Constructs an Expression representing syntax at the given line number.
|
||||
// `kind` must be the enumerator corresponding to the most-derived type being
|
||||
// constructed.
|
||||
Expression(Kind kind, SourceLocation source_loc)
|
||||
: kind_(kind), source_loc_(source_loc) {}
|
||||
Expression() = default;
|
||||
|
||||
private:
|
||||
const Kind kind_;
|
||||
SourceLocation source_loc_;
|
||||
|
||||
std::optional<Nonnull<const Value*>> static_type_;
|
||||
};
|
||||
|
||||
@@ -114,11 +96,11 @@ enum class Operator {
|
||||
class IdentifierExpression : public Expression {
|
||||
public:
|
||||
explicit IdentifierExpression(SourceLocation source_loc, std::string name)
|
||||
: Expression(Kind::IdentifierExpression, source_loc),
|
||||
: AstNode(AstNodeKind::IdentifierExpression, source_loc),
|
||||
name_(std::move(name)) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::IdentifierExpression;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromIdentifierExpression(node->kind());
|
||||
}
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
@@ -132,12 +114,12 @@ class FieldAccessExpression : public Expression {
|
||||
explicit FieldAccessExpression(SourceLocation source_loc,
|
||||
Nonnull<Expression*> aggregate,
|
||||
std::string field)
|
||||
: Expression(Kind::FieldAccessExpression, source_loc),
|
||||
: AstNode(AstNodeKind::FieldAccessExpression, source_loc),
|
||||
aggregate_(aggregate),
|
||||
field_(std::move(field)) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::FieldAccessExpression;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromFieldAccessExpression(node->kind());
|
||||
}
|
||||
|
||||
auto aggregate() const -> const Expression& { return *aggregate_; }
|
||||
@@ -154,12 +136,12 @@ class IndexExpression : public Expression {
|
||||
explicit IndexExpression(SourceLocation source_loc,
|
||||
Nonnull<Expression*> aggregate,
|
||||
Nonnull<Expression*> offset)
|
||||
: Expression(Kind::IndexExpression, source_loc),
|
||||
: AstNode(AstNodeKind::IndexExpression, source_loc),
|
||||
aggregate_(aggregate),
|
||||
offset_(offset) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::IndexExpression;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromIndexExpression(node->kind());
|
||||
}
|
||||
|
||||
auto aggregate() const -> const Expression& { return *aggregate_; }
|
||||
@@ -175,10 +157,10 @@ class IndexExpression : public Expression {
|
||||
class IntLiteral : public Expression {
|
||||
public:
|
||||
explicit IntLiteral(SourceLocation source_loc, int value)
|
||||
: Expression(Kind::IntLiteral, source_loc), value_(value) {}
|
||||
: AstNode(AstNodeKind::IntLiteral, source_loc), value_(value) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::IntLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromIntLiteral(node->kind());
|
||||
}
|
||||
|
||||
auto value() const -> int { return value_; }
|
||||
@@ -190,10 +172,10 @@ class IntLiteral : public Expression {
|
||||
class BoolLiteral : public Expression {
|
||||
public:
|
||||
explicit BoolLiteral(SourceLocation source_loc, bool value)
|
||||
: Expression(Kind::BoolLiteral, source_loc), value_(value) {}
|
||||
: AstNode(AstNodeKind::BoolLiteral, source_loc), value_(value) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::BoolLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromBoolLiteral(node->kind());
|
||||
}
|
||||
|
||||
auto value() const -> bool { return value_; }
|
||||
@@ -205,10 +187,11 @@ class BoolLiteral : public Expression {
|
||||
class StringLiteral : public Expression {
|
||||
public:
|
||||
explicit StringLiteral(SourceLocation source_loc, std::string value)
|
||||
: Expression(Kind::StringLiteral, source_loc), value_(std::move(value)) {}
|
||||
: AstNode(AstNodeKind::StringLiteral, source_loc),
|
||||
value_(std::move(value)) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::StringLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromStringLiteral(node->kind());
|
||||
}
|
||||
|
||||
auto value() const -> const std::string& { return value_; }
|
||||
@@ -220,10 +203,10 @@ class StringLiteral : public Expression {
|
||||
class StringTypeLiteral : public Expression {
|
||||
public:
|
||||
explicit StringTypeLiteral(SourceLocation source_loc)
|
||||
: Expression(Kind::StringTypeLiteral, source_loc) {}
|
||||
: AstNode(AstNodeKind::StringTypeLiteral, source_loc) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::StringTypeLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromStringTypeLiteral(node->kind());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -234,11 +217,11 @@ class TupleLiteral : public Expression {
|
||||
|
||||
explicit TupleLiteral(SourceLocation source_loc,
|
||||
std::vector<Nonnull<Expression*>> fields)
|
||||
: Expression(Kind::TupleLiteral, source_loc),
|
||||
: AstNode(AstNodeKind::TupleLiteral, source_loc),
|
||||
fields_(std::move(fields)) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::TupleLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromTupleLiteral(node->kind());
|
||||
}
|
||||
|
||||
auto fields() const -> llvm::ArrayRef<Nonnull<const Expression*>> {
|
||||
@@ -260,13 +243,13 @@ class StructLiteral : public Expression {
|
||||
public:
|
||||
explicit StructLiteral(SourceLocation loc,
|
||||
std::vector<FieldInitializer> fields)
|
||||
: Expression(Kind::StructLiteral, loc), fields_(std::move(fields)) {
|
||||
: AstNode(AstNodeKind::StructLiteral, loc), fields_(std::move(fields)) {
|
||||
CHECK(!fields_.empty())
|
||||
<< "`{}` is represented as a StructTypeLiteral, not a StructLiteral.";
|
||||
}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::StructLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromStructLiteral(node->kind());
|
||||
}
|
||||
|
||||
auto fields() const -> llvm::ArrayRef<FieldInitializer> { return fields_; }
|
||||
@@ -286,10 +269,11 @@ class StructTypeLiteral : public Expression {
|
||||
|
||||
explicit StructTypeLiteral(SourceLocation loc,
|
||||
std::vector<FieldInitializer> fields)
|
||||
: Expression(Kind::StructTypeLiteral, loc), fields_(std::move(fields)) {}
|
||||
: AstNode(AstNodeKind::StructTypeLiteral, loc),
|
||||
fields_(std::move(fields)) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::StructTypeLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromStructTypeLiteral(node->kind());
|
||||
}
|
||||
|
||||
auto fields() const -> llvm::ArrayRef<FieldInitializer> { return fields_; }
|
||||
@@ -304,12 +288,12 @@ class PrimitiveOperatorExpression : public Expression {
|
||||
explicit PrimitiveOperatorExpression(
|
||||
SourceLocation source_loc, Operator op,
|
||||
std::vector<Nonnull<Expression*>> arguments)
|
||||
: Expression(Kind::PrimitiveOperatorExpression, source_loc),
|
||||
: AstNode(AstNodeKind::PrimitiveOperatorExpression, source_loc),
|
||||
op_(op),
|
||||
arguments_(std::move(arguments)) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::PrimitiveOperatorExpression;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromPrimitiveOperatorExpression(node->kind());
|
||||
}
|
||||
|
||||
auto op() const -> Operator { return op_; }
|
||||
@@ -330,12 +314,12 @@ class CallExpression : public Expression {
|
||||
explicit CallExpression(SourceLocation source_loc,
|
||||
Nonnull<Expression*> function,
|
||||
Nonnull<Expression*> argument)
|
||||
: Expression(Kind::CallExpression, source_loc),
|
||||
: AstNode(AstNodeKind::CallExpression, source_loc),
|
||||
function_(function),
|
||||
argument_(argument) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::CallExpression;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromCallExpression(node->kind());
|
||||
}
|
||||
|
||||
auto function() const -> const Expression& { return *function_; }
|
||||
@@ -353,12 +337,12 @@ class FunctionTypeLiteral : public Expression {
|
||||
explicit FunctionTypeLiteral(SourceLocation source_loc,
|
||||
Nonnull<Expression*> parameter,
|
||||
Nonnull<Expression*> return_type)
|
||||
: Expression(Kind::FunctionTypeLiteral, source_loc),
|
||||
: AstNode(AstNodeKind::FunctionTypeLiteral, source_loc),
|
||||
parameter_(parameter),
|
||||
return_type_(return_type) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::FunctionTypeLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromFunctionTypeLiteral(node->kind());
|
||||
}
|
||||
|
||||
auto parameter() const -> const Expression& { return *parameter_; }
|
||||
@@ -374,40 +358,40 @@ class FunctionTypeLiteral : public Expression {
|
||||
class BoolTypeLiteral : public Expression {
|
||||
public:
|
||||
explicit BoolTypeLiteral(SourceLocation source_loc)
|
||||
: Expression(Kind::BoolTypeLiteral, source_loc) {}
|
||||
: AstNode(AstNodeKind::BoolTypeLiteral, source_loc) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::BoolTypeLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromBoolTypeLiteral(node->kind());
|
||||
}
|
||||
};
|
||||
|
||||
class IntTypeLiteral : public Expression {
|
||||
public:
|
||||
explicit IntTypeLiteral(SourceLocation source_loc)
|
||||
: Expression(Kind::IntTypeLiteral, source_loc) {}
|
||||
: AstNode(AstNodeKind::IntTypeLiteral, source_loc) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::IntTypeLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromIntTypeLiteral(node->kind());
|
||||
}
|
||||
};
|
||||
|
||||
class ContinuationTypeLiteral : public Expression {
|
||||
public:
|
||||
explicit ContinuationTypeLiteral(SourceLocation source_loc)
|
||||
: Expression(Kind::ContinuationTypeLiteral, source_loc) {}
|
||||
: AstNode(AstNodeKind::ContinuationTypeLiteral, source_loc) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::ContinuationTypeLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromContinuationTypeLiteral(node->kind());
|
||||
}
|
||||
};
|
||||
|
||||
class TypeTypeLiteral : public Expression {
|
||||
public:
|
||||
explicit TypeTypeLiteral(SourceLocation source_loc)
|
||||
: Expression(Kind::TypeTypeLiteral, source_loc) {}
|
||||
: AstNode(AstNodeKind::TypeTypeLiteral, source_loc) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::TypeTypeLiteral;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromTypeTypeLiteral(node->kind());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -418,11 +402,12 @@ class IntrinsicExpression : public Expression {
|
||||
};
|
||||
|
||||
explicit IntrinsicExpression(Intrinsic intrinsic)
|
||||
: Expression(Kind::IntrinsicExpression, SourceLocation("<intrinsic>", 0)),
|
||||
: AstNode(AstNodeKind::IntrinsicExpression,
|
||||
SourceLocation("<intrinsic>", 0)),
|
||||
intrinsic_(intrinsic) {}
|
||||
|
||||
static auto classof(const Expression* exp) -> bool {
|
||||
return exp->kind() == Kind::IntrinsicExpression;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromIntrinsicExpression(node->kind());
|
||||
}
|
||||
|
||||
auto intrinsic() const -> Intrinsic { return intrinsic_; }
|
||||
|
||||
@@ -21,7 +21,7 @@ using testing::ElementsAre;
|
||||
using testing::IsEmpty;
|
||||
|
||||
// Matches any `IntLiteral`.
|
||||
MATCHER(IntField, "") { return arg->kind() == Expression::Kind::IntLiteral; }
|
||||
MATCHER(IntField, "") { return arg->kind() == ExpressionKind::IntLiteral; }
|
||||
|
||||
static auto FakeSourceLoc(int line_num) -> SourceLocation {
|
||||
return SourceLocation("<test>", line_num);
|
||||
@@ -38,7 +38,7 @@ TEST_F(ExpressionTest, EmptyAsExpression) {
|
||||
Nonnull<const Expression*> expression =
|
||||
ExpressionFromParenContents(&arena, FakeSourceLoc(1), contents);
|
||||
EXPECT_EQ(expression->source_loc(), FakeSourceLoc(1));
|
||||
ASSERT_EQ(expression->kind(), Expression::Kind::TupleLiteral);
|
||||
ASSERT_EQ(expression->kind(), ExpressionKind::TupleLiteral);
|
||||
EXPECT_THAT(cast<TupleLiteral>(*expression).fields(), IsEmpty());
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ TEST_F(ExpressionTest, EmptyAsTuple) {
|
||||
Nonnull<const Expression*> tuple =
|
||||
TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents);
|
||||
EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1));
|
||||
ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral);
|
||||
ASSERT_EQ(tuple->kind(), ExpressionKind::TupleLiteral);
|
||||
EXPECT_THAT(cast<TupleLiteral>(*tuple).fields(), IsEmpty());
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ TEST_F(ExpressionTest, UnaryNoCommaAsExpression) {
|
||||
Nonnull<const Expression*> expression =
|
||||
ExpressionFromParenContents(&arena, FakeSourceLoc(1), contents);
|
||||
EXPECT_EQ(expression->source_loc(), FakeSourceLoc(2));
|
||||
ASSERT_EQ(expression->kind(), Expression::Kind::IntLiteral);
|
||||
ASSERT_EQ(expression->kind(), ExpressionKind::IntLiteral);
|
||||
}
|
||||
|
||||
TEST_F(ExpressionTest, UnaryNoCommaAsTuple) {
|
||||
@@ -77,7 +77,7 @@ TEST_F(ExpressionTest, UnaryNoCommaAsTuple) {
|
||||
Nonnull<const Expression*> tuple =
|
||||
TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents);
|
||||
EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1));
|
||||
ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral);
|
||||
ASSERT_EQ(tuple->kind(), ExpressionKind::TupleLiteral);
|
||||
EXPECT_THAT(cast<TupleLiteral>(*tuple).fields(), ElementsAre(IntField()));
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ TEST_F(ExpressionTest, UnaryWithCommaAsExpression) {
|
||||
Nonnull<const Expression*> expression =
|
||||
ExpressionFromParenContents(&arena, FakeSourceLoc(1), contents);
|
||||
EXPECT_EQ(expression->source_loc(), FakeSourceLoc(1));
|
||||
ASSERT_EQ(expression->kind(), Expression::Kind::TupleLiteral);
|
||||
ASSERT_EQ(expression->kind(), ExpressionKind::TupleLiteral);
|
||||
EXPECT_THAT(cast<TupleLiteral>(*expression).fields(),
|
||||
ElementsAre(IntField()));
|
||||
}
|
||||
@@ -102,7 +102,7 @@ TEST_F(ExpressionTest, UnaryWithCommaAsTuple) {
|
||||
Nonnull<const Expression*> tuple =
|
||||
TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents);
|
||||
EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1));
|
||||
ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral);
|
||||
ASSERT_EQ(tuple->kind(), ExpressionKind::TupleLiteral);
|
||||
EXPECT_THAT(cast<TupleLiteral>(*tuple).fields(), ElementsAre(IntField()));
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ TEST_F(ExpressionTest, BinaryAsExpression) {
|
||||
Nonnull<const Expression*> expression =
|
||||
ExpressionFromParenContents(&arena, FakeSourceLoc(1), contents);
|
||||
EXPECT_EQ(expression->source_loc(), FakeSourceLoc(1));
|
||||
ASSERT_EQ(expression->kind(), Expression::Kind::TupleLiteral);
|
||||
ASSERT_EQ(expression->kind(), ExpressionKind::TupleLiteral);
|
||||
EXPECT_THAT(cast<TupleLiteral>(*expression).fields(),
|
||||
ElementsAre(IntField(), IntField()));
|
||||
}
|
||||
@@ -129,7 +129,7 @@ TEST_F(ExpressionTest, BinaryAsTuple) {
|
||||
Nonnull<const Expression*> tuple =
|
||||
TupleExpressionFromParenContents(&arena, FakeSourceLoc(1), contents);
|
||||
EXPECT_EQ(tuple->source_loc(), FakeSourceLoc(1));
|
||||
ASSERT_EQ(tuple->kind(), Expression::Kind::TupleLiteral);
|
||||
ASSERT_EQ(tuple->kind(), ExpressionKind::TupleLiteral);
|
||||
EXPECT_THAT(cast<TupleLiteral>(*tuple).fields(),
|
||||
ElementsAre(IntField(), IntField()));
|
||||
}
|
||||
|
||||
@@ -11,9 +11,11 @@ namespace Carbon {
|
||||
|
||||
using llvm::cast;
|
||||
|
||||
Member::~Member() = default;
|
||||
|
||||
void Member::Print(llvm::raw_ostream& out) const {
|
||||
switch (kind()) {
|
||||
case Kind::FieldMember:
|
||||
case MemberKind::FieldMember:
|
||||
const auto& field = cast<FieldMember>(*this);
|
||||
out << "var " << field.binding() << ";\n";
|
||||
break;
|
||||
|
||||
@@ -23,9 +23,9 @@ namespace Carbon {
|
||||
// every concrete derived class must have a corresponding enumerator
|
||||
// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
|
||||
// details.
|
||||
class Member : public NamedEntityInterface {
|
||||
class Member : public virtual AstNode, public NamedEntity {
|
||||
public:
|
||||
enum class Kind { FieldMember };
|
||||
~Member() override = 0;
|
||||
|
||||
Member(const Member&) = delete;
|
||||
auto operator=(const Member&) -> Member& = delete;
|
||||
@@ -33,35 +33,27 @@ class Member : public NamedEntityInterface {
|
||||
void Print(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 named_entity_kind() const -> NamedEntityKind override {
|
||||
return NamedEntityKind::Member;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromMember(node->kind());
|
||||
}
|
||||
|
||||
auto source_loc() const -> SourceLocation override { return source_loc_; }
|
||||
// Returns the enumerator corresponding to the most-derived type of this
|
||||
// object.
|
||||
auto kind() const -> MemberKind {
|
||||
return static_cast<MemberKind>(root_kind());
|
||||
}
|
||||
|
||||
protected:
|
||||
// Constructs a Member representing syntax at the given line number.
|
||||
// `kind` must be the enumerator corresponding to the most-derived type being
|
||||
// constructed.
|
||||
Member(Kind kind, SourceLocation source_loc)
|
||||
: kind_(kind), source_loc_(source_loc) {}
|
||||
|
||||
private:
|
||||
const Kind kind_;
|
||||
SourceLocation source_loc_;
|
||||
Member() = default;
|
||||
};
|
||||
|
||||
class FieldMember : public Member {
|
||||
public:
|
||||
FieldMember(SourceLocation source_loc, Nonnull<const BindingPattern*> binding)
|
||||
: Member(Kind::FieldMember, source_loc), binding_(binding) {}
|
||||
: AstNode(AstNodeKind::FieldMember, source_loc), binding_(binding) {}
|
||||
|
||||
static auto classof(const Member* member) -> bool {
|
||||
return member->kind() == Kind::FieldMember;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromFieldMember(node->kind());
|
||||
}
|
||||
|
||||
auto binding() const -> const BindingPattern& { return *binding_; }
|
||||
|
||||
@@ -17,12 +17,14 @@ namespace Carbon {
|
||||
|
||||
using llvm::cast;
|
||||
|
||||
Pattern::~Pattern() = default;
|
||||
|
||||
void Pattern::Print(llvm::raw_ostream& out) const {
|
||||
switch (kind()) {
|
||||
case Kind::AutoPattern:
|
||||
case PatternKind::AutoPattern:
|
||||
out << "auto";
|
||||
break;
|
||||
case Kind::BindingPattern: {
|
||||
case PatternKind::BindingPattern: {
|
||||
const auto& binding = cast<BindingPattern>(*this);
|
||||
if (binding.name().has_value()) {
|
||||
out << *binding.name();
|
||||
@@ -32,7 +34,7 @@ void Pattern::Print(llvm::raw_ostream& out) const {
|
||||
out << ": " << binding.type();
|
||||
break;
|
||||
}
|
||||
case Kind::TuplePattern: {
|
||||
case PatternKind::TuplePattern: {
|
||||
const auto& tuple = cast<TuplePattern>(*this);
|
||||
out << "(";
|
||||
llvm::ListSeparator sep;
|
||||
@@ -42,13 +44,13 @@ void Pattern::Print(llvm::raw_ostream& out) const {
|
||||
out << ")";
|
||||
break;
|
||||
}
|
||||
case Kind::AlternativePattern: {
|
||||
case PatternKind::AlternativePattern: {
|
||||
const auto& alternative = cast<AlternativePattern>(*this);
|
||||
out << alternative.choice_type() << "." << alternative.alternative_name()
|
||||
<< alternative.arguments();
|
||||
break;
|
||||
}
|
||||
case Kind::ExpressionPattern:
|
||||
case PatternKind::ExpressionPattern:
|
||||
out << cast<ExpressionPattern>(*this).expression();
|
||||
break;
|
||||
}
|
||||
@@ -77,7 +79,7 @@ auto TuplePatternFromParenContents(Nonnull<Arena*> arena,
|
||||
// apply.
|
||||
static auto RequireFieldAccess(Nonnull<Expression*> alternative)
|
||||
-> FieldAccessExpression& {
|
||||
if (alternative->kind() != Expression::Kind::FieldAccessExpression) {
|
||||
if (alternative->kind() != ExpressionKind::FieldAccessExpression) {
|
||||
FATAL_PROGRAM_ERROR(alternative->source_loc())
|
||||
<< "Alternative pattern must have the form of a field access.";
|
||||
}
|
||||
@@ -87,7 +89,7 @@ static auto RequireFieldAccess(Nonnull<Expression*> alternative)
|
||||
AlternativePattern::AlternativePattern(SourceLocation source_loc,
|
||||
Nonnull<Expression*> alternative,
|
||||
Nonnull<TuplePattern*> arguments)
|
||||
: Pattern(Kind::AlternativePattern, source_loc),
|
||||
: AstNode(AstNodeKind::AlternativePattern, source_loc),
|
||||
choice_type_(&RequireFieldAccess(alternative).aggregate()),
|
||||
alternative_name_(RequireFieldAccess(alternative).field()),
|
||||
arguments_(arguments) {}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/ast_node.h"
|
||||
#include "executable_semantics/ast/ast_rtti.h"
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/ast/static_scope.h"
|
||||
@@ -27,27 +29,25 @@ class Value;
|
||||
// every concrete derived class must have a corresponding enumerator
|
||||
// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
|
||||
// details.
|
||||
class Pattern {
|
||||
class Pattern : public virtual AstNode {
|
||||
public:
|
||||
enum class Kind {
|
||||
AutoPattern,
|
||||
BindingPattern,
|
||||
TuplePattern,
|
||||
AlternativePattern,
|
||||
ExpressionPattern,
|
||||
};
|
||||
|
||||
Pattern(const Pattern&) = delete;
|
||||
auto operator=(const Pattern&) -> Pattern& = delete;
|
||||
|
||||
~Pattern() override = 0;
|
||||
|
||||
void Print(llvm::raw_ostream& out) const;
|
||||
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromPattern(node->kind());
|
||||
}
|
||||
|
||||
// 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_; }
|
||||
auto kind() const -> PatternKind {
|
||||
return static_cast<PatternKind>(root_kind());
|
||||
}
|
||||
|
||||
// The static type of this pattern. Cannot be called before typechecking.
|
||||
auto static_type() const -> const Value& { return **static_type_; }
|
||||
@@ -77,13 +77,9 @@ class Pattern {
|
||||
// Constructs a Pattern representing syntax at the given line number.
|
||||
// `kind` must be the enumerator corresponding to the most-derived type being
|
||||
// constructed.
|
||||
Pattern(Kind kind, SourceLocation source_loc)
|
||||
: kind_(kind), source_loc_(source_loc) {}
|
||||
Pattern() = default;
|
||||
|
||||
private:
|
||||
const Kind kind_;
|
||||
SourceLocation source_loc_;
|
||||
|
||||
std::optional<Nonnull<const Value*>> static_type_;
|
||||
std::optional<Nonnull<const Value*>> value_;
|
||||
};
|
||||
@@ -92,33 +88,25 @@ class Pattern {
|
||||
class AutoPattern : public Pattern {
|
||||
public:
|
||||
explicit AutoPattern(SourceLocation source_loc)
|
||||
: Pattern(Kind::AutoPattern, source_loc) {}
|
||||
: AstNode(AstNodeKind::AutoPattern, source_loc) {}
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->kind() == Kind::AutoPattern;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromAutoPattern(node->kind());
|
||||
}
|
||||
};
|
||||
|
||||
// A pattern that matches a value of a specified type, and optionally binds
|
||||
// a name to it.
|
||||
class BindingPattern : public Pattern, public NamedEntityInterface {
|
||||
class BindingPattern : public Pattern, public NamedEntity {
|
||||
public:
|
||||
BindingPattern(SourceLocation source_loc, std::optional<std::string> name,
|
||||
Nonnull<Pattern*> type)
|
||||
: Pattern(Kind::BindingPattern, source_loc),
|
||||
: AstNode(AstNodeKind::BindingPattern, source_loc),
|
||||
name_(std::move(name)),
|
||||
type_(type) {}
|
||||
|
||||
auto named_entity_kind() const -> NamedEntityKind override {
|
||||
return NamedEntityKind::BindingPattern;
|
||||
}
|
||||
|
||||
auto source_loc() const -> SourceLocation override {
|
||||
return Pattern::source_loc();
|
||||
}
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->kind() == Kind::BindingPattern;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromBindingPattern(node->kind());
|
||||
}
|
||||
|
||||
// The name this pattern binds, if any.
|
||||
@@ -137,10 +125,11 @@ class BindingPattern : public Pattern, public NamedEntityInterface {
|
||||
class TuplePattern : public Pattern {
|
||||
public:
|
||||
TuplePattern(SourceLocation source_loc, std::vector<Nonnull<Pattern*>> fields)
|
||||
: Pattern(Kind::TuplePattern, source_loc), fields_(std::move(fields)) {}
|
||||
: AstNode(AstNodeKind::TuplePattern, source_loc),
|
||||
fields_(std::move(fields)) {}
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->kind() == Kind::TuplePattern;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromTuplePattern(node->kind());
|
||||
}
|
||||
|
||||
auto fields() const -> llvm::ArrayRef<Nonnull<const Pattern*>> {
|
||||
@@ -182,7 +171,7 @@ class AlternativePattern : public Pattern {
|
||||
Nonnull<Expression*> choice_type,
|
||||
std::string alternative_name,
|
||||
Nonnull<TuplePattern*> arguments)
|
||||
: Pattern(Kind::AlternativePattern, source_loc),
|
||||
: AstNode(AstNodeKind::AlternativePattern, source_loc),
|
||||
choice_type_(choice_type),
|
||||
alternative_name_(std::move(alternative_name)),
|
||||
arguments_(arguments) {}
|
||||
@@ -193,8 +182,8 @@ class AlternativePattern : public Pattern {
|
||||
Nonnull<Expression*> alternative,
|
||||
Nonnull<TuplePattern*> arguments);
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->kind() == Kind::AlternativePattern;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromAlternativePattern(node->kind());
|
||||
}
|
||||
|
||||
auto choice_type() const -> const Expression& { return *choice_type_; }
|
||||
@@ -216,11 +205,11 @@ class AlternativePattern : public Pattern {
|
||||
class ExpressionPattern : public Pattern {
|
||||
public:
|
||||
explicit ExpressionPattern(Nonnull<Expression*> expression)
|
||||
: Pattern(Kind::ExpressionPattern, expression->source_loc()),
|
||||
: AstNode(AstNodeKind::ExpressionPattern, expression->source_loc()),
|
||||
expression_(expression) {}
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->kind() == Kind::ExpressionPattern;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromExpressionPattern(node->kind());
|
||||
}
|
||||
|
||||
auto expression() const -> const Expression& { return *expression_; }
|
||||
|
||||
@@ -12,13 +12,15 @@ namespace Carbon {
|
||||
|
||||
using llvm::cast;
|
||||
|
||||
Statement::~Statement() = default;
|
||||
|
||||
void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
if (depth == 0) {
|
||||
out << " ... ";
|
||||
return;
|
||||
}
|
||||
switch (kind()) {
|
||||
case Kind::Match: {
|
||||
case StatementKind::Match: {
|
||||
const auto& match = cast<Match>(*this);
|
||||
out << "match (" << match.expression() << ") {";
|
||||
if (depth < 0 || depth > 1) {
|
||||
@@ -34,32 +36,32 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
out << "}";
|
||||
break;
|
||||
}
|
||||
case Kind::While: {
|
||||
case StatementKind::While: {
|
||||
const auto& while_stmt = cast<While>(*this);
|
||||
out << "while (" << while_stmt.condition() << ")\n";
|
||||
while_stmt.body().PrintDepth(depth - 1, out);
|
||||
break;
|
||||
}
|
||||
case Kind::Break:
|
||||
case StatementKind::Break:
|
||||
out << "break;";
|
||||
break;
|
||||
case Kind::Continue:
|
||||
case StatementKind::Continue:
|
||||
out << "continue;";
|
||||
break;
|
||||
case Kind::VariableDefinition: {
|
||||
case StatementKind::VariableDefinition: {
|
||||
const auto& var = cast<VariableDefinition>(*this);
|
||||
out << "var " << var.pattern() << " = " << var.init() << ";";
|
||||
break;
|
||||
}
|
||||
case Kind::ExpressionStatement:
|
||||
case StatementKind::ExpressionStatement:
|
||||
out << cast<ExpressionStatement>(*this).expression() << ";";
|
||||
break;
|
||||
case Kind::Assign: {
|
||||
case StatementKind::Assign: {
|
||||
const auto& assign = cast<Assign>(*this);
|
||||
out << assign.lhs() << " = " << assign.rhs() << ";";
|
||||
break;
|
||||
}
|
||||
case Kind::If: {
|
||||
case StatementKind::If: {
|
||||
const auto& if_stmt = cast<If>(*this);
|
||||
out << "if (" << if_stmt.condition() << ")\n";
|
||||
if_stmt.then_block().PrintDepth(depth - 1, out);
|
||||
@@ -69,7 +71,7 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Kind::Return: {
|
||||
case StatementKind::Return: {
|
||||
const auto& ret = cast<Return>(*this);
|
||||
if (ret.is_omitted_expression()) {
|
||||
out << "return;";
|
||||
@@ -78,7 +80,7 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Kind::Block: {
|
||||
case StatementKind::Block: {
|
||||
const auto& block = cast<Block>(*this);
|
||||
out << "{";
|
||||
if (depth < 0 || depth > 1) {
|
||||
@@ -96,7 +98,7 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Kind::Continuation: {
|
||||
case StatementKind::Continuation: {
|
||||
const auto& cont = cast<Continuation>(*this);
|
||||
out << "continuation " << cont.continuation_variable() << " ";
|
||||
if (depth < 0 || depth > 1) {
|
||||
@@ -108,10 +110,10 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Kind::Run:
|
||||
case StatementKind::Run:
|
||||
out << "run " << cast<Run>(*this).argument() << ";";
|
||||
break;
|
||||
case Kind::Await:
|
||||
case StatementKind::Await:
|
||||
out << "await;";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -21,53 +21,35 @@ namespace Carbon {
|
||||
class FunctionDeclaration;
|
||||
class StaticScope;
|
||||
|
||||
class Statement {
|
||||
class Statement : public virtual AstNode {
|
||||
public:
|
||||
enum class Kind {
|
||||
ExpressionStatement,
|
||||
Assign,
|
||||
VariableDefinition,
|
||||
If,
|
||||
Return,
|
||||
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.
|
||||
};
|
||||
~Statement() override = 0;
|
||||
|
||||
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()); }
|
||||
|
||||
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 -> Kind { return kind_; }
|
||||
|
||||
auto source_loc() const -> SourceLocation { return source_loc_; }
|
||||
auto kind() const -> StatementKind {
|
||||
return static_cast<StatementKind>(root_kind());
|
||||
}
|
||||
|
||||
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_;
|
||||
Statement() = default;
|
||||
};
|
||||
|
||||
class Block : public Statement {
|
||||
public:
|
||||
Block(SourceLocation source_loc, std::vector<Nonnull<Statement*>> statements)
|
||||
: Statement(Kind::Block, source_loc), statements_(statements) {}
|
||||
: AstNode(AstNodeKind::Block, source_loc), statements_(statements) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::Block;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromBlock(node->kind());
|
||||
}
|
||||
|
||||
auto statements() const -> llvm::ArrayRef<Nonnull<const Statement*>> {
|
||||
@@ -89,11 +71,11 @@ class ExpressionStatement : public Statement {
|
||||
public:
|
||||
ExpressionStatement(SourceLocation source_loc,
|
||||
Nonnull<Expression*> expression)
|
||||
: Statement(Kind::ExpressionStatement, source_loc),
|
||||
: AstNode(AstNodeKind::ExpressionStatement, source_loc),
|
||||
expression_(expression) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::ExpressionStatement;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromExpressionStatement(node->kind());
|
||||
}
|
||||
|
||||
auto expression() const -> const Expression& { return *expression_; }
|
||||
@@ -107,10 +89,10 @@ class Assign : public Statement {
|
||||
public:
|
||||
Assign(SourceLocation source_loc, Nonnull<Expression*> lhs,
|
||||
Nonnull<Expression*> rhs)
|
||||
: Statement(Kind::Assign, source_loc), lhs_(lhs), rhs_(rhs) {}
|
||||
: AstNode(AstNodeKind::Assign, source_loc), lhs_(lhs), rhs_(rhs) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::Assign;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromAssign(node->kind());
|
||||
}
|
||||
|
||||
auto lhs() const -> const Expression& { return *lhs_; }
|
||||
@@ -127,12 +109,12 @@ class VariableDefinition : public Statement {
|
||||
public:
|
||||
VariableDefinition(SourceLocation source_loc, Nonnull<Pattern*> pattern,
|
||||
Nonnull<Expression*> init)
|
||||
: Statement(Kind::VariableDefinition, source_loc),
|
||||
: AstNode(AstNodeKind::VariableDefinition, source_loc),
|
||||
pattern_(pattern),
|
||||
init_(init) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::VariableDefinition;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromVariableDefinition(node->kind());
|
||||
}
|
||||
|
||||
auto pattern() const -> const Pattern& { return *pattern_; }
|
||||
@@ -149,13 +131,13 @@ class If : public Statement {
|
||||
public:
|
||||
If(SourceLocation source_loc, Nonnull<Expression*> condition,
|
||||
Nonnull<Block*> then_block, std::optional<Nonnull<Block*>> else_block)
|
||||
: Statement(Kind::If, source_loc),
|
||||
: AstNode(AstNodeKind::If, source_loc),
|
||||
condition_(condition),
|
||||
then_block_(then_block),
|
||||
else_block_(else_block) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::If;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromIf(node->kind());
|
||||
}
|
||||
|
||||
auto condition() const -> const Expression& { return *condition_; }
|
||||
@@ -179,12 +161,12 @@ class Return : public Statement {
|
||||
: Return(source_loc, arena->New<TupleLiteral>(source_loc), true) {}
|
||||
Return(SourceLocation source_loc, Nonnull<Expression*> expression,
|
||||
bool is_omitted_expression)
|
||||
: Statement(Kind::Return, source_loc),
|
||||
: AstNode(AstNodeKind::Return, source_loc),
|
||||
expression_(expression),
|
||||
is_omitted_expression_(is_omitted_expression) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::Return;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromReturn(node->kind());
|
||||
}
|
||||
|
||||
auto expression() const -> const Expression& { return *expression_; }
|
||||
@@ -216,12 +198,12 @@ class While : public Statement {
|
||||
public:
|
||||
While(SourceLocation source_loc, Nonnull<Expression*> condition,
|
||||
Nonnull<Block*> body)
|
||||
: Statement(Kind::While, source_loc),
|
||||
: AstNode(AstNodeKind::While, source_loc),
|
||||
condition_(condition),
|
||||
body_(body) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::While;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromWhile(node->kind());
|
||||
}
|
||||
|
||||
auto condition() const -> const Expression& { return *condition_; }
|
||||
@@ -237,10 +219,10 @@ class While : public Statement {
|
||||
class Break : public Statement {
|
||||
public:
|
||||
explicit Break(SourceLocation source_loc)
|
||||
: Statement(Kind::Break, source_loc) {}
|
||||
: AstNode(AstNodeKind::Break, source_loc) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::Break;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromBreak(node->kind());
|
||||
}
|
||||
|
||||
// The AST node representing the loop this statement breaks out of.
|
||||
@@ -264,10 +246,10 @@ class Break : public Statement {
|
||||
class Continue : public Statement {
|
||||
public:
|
||||
explicit Continue(SourceLocation source_loc)
|
||||
: Statement(Kind::Continue, source_loc) {}
|
||||
: AstNode(AstNodeKind::Continue, source_loc) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::Continue;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromContinue(node->kind());
|
||||
}
|
||||
|
||||
// The AST node representing the loop this statement continues.
|
||||
@@ -313,12 +295,12 @@ class Match : public Statement {
|
||||
|
||||
Match(SourceLocation source_loc, Nonnull<Expression*> expression,
|
||||
std::vector<Clause> clauses)
|
||||
: Statement(Kind::Match, source_loc),
|
||||
: AstNode(AstNodeKind::Match, source_loc),
|
||||
expression_(expression),
|
||||
clauses_(std::move(clauses)) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::Match;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromMatch(node->kind());
|
||||
}
|
||||
|
||||
auto expression() const -> const Expression& { return *expression_; }
|
||||
@@ -336,24 +318,16 @@ class Match : public Statement {
|
||||
// __continuation <continuation_variable> {
|
||||
// <body>
|
||||
// }
|
||||
class Continuation : public Statement, public NamedEntityInterface {
|
||||
class Continuation : public Statement, public NamedEntity {
|
||||
public:
|
||||
Continuation(SourceLocation source_loc, std::string continuation_variable,
|
||||
Nonnull<Block*> body)
|
||||
: Statement(Kind::Continuation, source_loc),
|
||||
: AstNode(AstNodeKind::Continuation, source_loc),
|
||||
continuation_variable_(std::move(continuation_variable)),
|
||||
body_(body) {}
|
||||
|
||||
auto named_entity_kind() const -> NamedEntityKind override {
|
||||
return NamedEntityKind::Continuation;
|
||||
}
|
||||
|
||||
auto source_loc() const -> SourceLocation override {
|
||||
return Statement::source_loc();
|
||||
}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::Continuation;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromContinuation(node->kind());
|
||||
}
|
||||
|
||||
auto continuation_variable() const -> const std::string& {
|
||||
@@ -373,10 +347,10 @@ class Continuation : public Statement, public NamedEntityInterface {
|
||||
class Run : public Statement {
|
||||
public:
|
||||
Run(SourceLocation source_loc, Nonnull<Expression*> argument)
|
||||
: Statement(Kind::Run, source_loc), argument_(argument) {}
|
||||
: AstNode(AstNodeKind::Run, source_loc), argument_(argument) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::Run;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromRun(node->kind());
|
||||
}
|
||||
|
||||
auto argument() const -> const Expression& { return *argument_; }
|
||||
@@ -392,10 +366,10 @@ class Run : public Statement {
|
||||
class Await : public Statement {
|
||||
public:
|
||||
explicit Await(SourceLocation source_loc)
|
||||
: Statement(Kind::Await, source_loc) {}
|
||||
: AstNode(AstNodeKind::Await, source_loc) {}
|
||||
|
||||
static auto classof(const Statement* stmt) -> bool {
|
||||
return stmt->kind() == Kind::Await;
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromAwait(node->kind());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
void StaticScope::Add(std::string name,
|
||||
Nonnull<const NamedEntityInterface*> entity) {
|
||||
NamedEntity::~NamedEntity() = default;
|
||||
|
||||
void StaticScope::Add(std::string name, Nonnull<const NamedEntity*> entity) {
|
||||
if (!declared_names_.insert({name, entity}).second) {
|
||||
FATAL_COMPILATION_ERROR(entity->source_loc())
|
||||
<< "Duplicate name `" << name << "` also found at "
|
||||
|
||||
@@ -10,50 +10,33 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "executable_semantics/ast/ast_node.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/common/nonnull.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
class NamedEntityInterface {
|
||||
class NamedEntity : public virtual AstNode {
|
||||
public:
|
||||
enum class NamedEntityKind {
|
||||
// Includes variable definitions and matching contexts.
|
||||
BindingPattern,
|
||||
// Used by entries in choices.
|
||||
ChoiceDeclarationAlternative,
|
||||
// Used by continuations.
|
||||
Continuation,
|
||||
// Includes choices, classes, and functions. Variables are handled through
|
||||
// BindingPattern.
|
||||
Declaration,
|
||||
// Used by functions.
|
||||
GenericBinding,
|
||||
// Used by entries in classes.
|
||||
Member,
|
||||
};
|
||||
virtual ~NamedEntity() = 0;
|
||||
|
||||
NamedEntityInterface() = default;
|
||||
virtual ~NamedEntityInterface() = default;
|
||||
|
||||
NamedEntityInterface(NamedEntityInterface&&) = delete;
|
||||
auto operator=(NamedEntityInterface&&) -> NamedEntityInterface& = delete;
|
||||
NamedEntity() = default;
|
||||
|
||||
// TODO: This is unused, but is intended for casts after lookup.
|
||||
virtual auto named_entity_kind() const -> NamedEntityKind = 0;
|
||||
virtual auto source_loc() const -> SourceLocation = 0;
|
||||
auto kind() const -> NamedEntityKind {
|
||||
return static_cast<NamedEntityKind>(root_kind());
|
||||
}
|
||||
};
|
||||
|
||||
// The set of declared names in a scope. This is not aware of child scopes, but
|
||||
// does include directions to parent or related scopes for lookup purposes.
|
||||
class StaticScope {
|
||||
public:
|
||||
void Add(std::string name, Nonnull<const NamedEntityInterface*> entity);
|
||||
void Add(std::string name, Nonnull<const NamedEntity*> entity);
|
||||
|
||||
private:
|
||||
// Maps locally declared names to their entities.
|
||||
std::unordered_map<std::string, Nonnull<const NamedEntityInterface*>>
|
||||
declared_names_;
|
||||
std::unordered_map<std::string, Nonnull<const NamedEntity*>> declared_names_;
|
||||
|
||||
// A list of scopes used for name lookup within this scope.
|
||||
// TODO: This is unused, but is intended for name lookup cross-scope.
|
||||
|
||||
Reference in New Issue
Block a user