Define a base class for all AST nodes. (#947)

Also implement code-generation to manage the resulting boilerplate.
This commit is contained in:
Geoff Romer
2021-11-16 11:54:47 -08:00
committed by GitHub
parent d854fb93cb
commit 7a5b8434c8
24 changed files with 965 additions and 543 deletions
+26
View File
@@ -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",
+11
View File
@@ -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
+74
View File
@@ -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_
+54
View File
@@ -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;
+7 -6
View File
@@ -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;
+55 -64
View File
@@ -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_; }
+21 -19
View File
@@ -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:
+68 -83
View File
@@ -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_; }
+9 -9
View File
@@ -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()));
}
+3 -1
View File
@@ -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;
+13 -21
View File
@@ -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_; }
+9 -7
View File
@@ -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) {}
+30 -41
View File
@@ -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_; }
+15 -13
View File
@@ -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;
}
+50 -76
View File
@@ -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());
}
};
+3 -2
View File
@@ -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 "
+9 -26
View File
@@ -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.