From 7a5b8434c846fed2257c29a127a08bc14f1a66af Mon Sep 17 00:00:00 2001 From: Geoff Romer Date: Tue, 16 Nov 2021 11:54:47 -0800 Subject: [PATCH] Define a base class for all AST nodes. (#947) Also implement code-generation to manage the resulting boilerplate. --- executable_semantics/BUILD | 5 + executable_semantics/ast/BUILD | 26 ++ executable_semantics/ast/ast_node.cpp | 11 + executable_semantics/ast/ast_node.h | 74 ++++ executable_semantics/ast/ast_rtti.txt | 54 +++ executable_semantics/ast/declaration.cpp | 13 +- executable_semantics/ast/declaration.h | 119 +++---- executable_semantics/ast/expression.cpp | 40 ++- executable_semantics/ast/expression.h | 151 ++++---- executable_semantics/ast/expression_test.cpp | 18 +- executable_semantics/ast/member.cpp | 4 +- executable_semantics/ast/member.h | 34 +- executable_semantics/ast/pattern.cpp | 16 +- executable_semantics/ast/pattern.h | 71 ++-- executable_semantics/ast/statement.cpp | 28 +- executable_semantics/ast/statement.h | 126 +++---- executable_semantics/ast/static_scope.cpp | 5 +- executable_semantics/ast/static_scope.h | 35 +- executable_semantics/gen_rtti.py | 332 ++++++++++++++++++ .../interpreter/interpreter.cpp | 120 +++---- .../interpreter/resolve_control_flow.cpp | 28 +- .../interpreter/resolve_names.cpp | 57 ++- .../interpreter/type_checker.cpp | 128 +++---- executable_semantics/syntax/parser.ypp | 13 +- 24 files changed, 965 insertions(+), 543 deletions(-) create mode 100644 executable_semantics/ast/ast_node.cpp create mode 100644 executable_semantics/ast/ast_node.h create mode 100644 executable_semantics/ast/ast_rtti.txt create mode 100755 executable_semantics/gen_rtti.py diff --git a/executable_semantics/BUILD b/executable_semantics/BUILD index 295486a3c7d9..4f70ce871944 100644 --- a/executable_semantics/BUILD +++ b/executable_semantics/BUILD @@ -24,3 +24,8 @@ lit_test( test_dir = "testdata", tools = [":executable_semantics"], ) + +py_binary( + name = "gen_rtti", + srcs = ["gen_rtti.py"], +) diff --git a/executable_semantics/ast/BUILD b/executable_semantics/ast/BUILD index 996196024d9a..de7bda688978 100644 --- a/executable_semantics/ast/BUILD +++ b/executable_semantics/ast/BUILD @@ -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", diff --git a/executable_semantics/ast/ast_node.cpp b/executable_semantics/ast/ast_node.cpp new file mode 100644 index 000000000000..2c0554d2a036 --- /dev/null +++ b/executable_semantics/ast/ast_node.cpp @@ -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 diff --git a/executable_semantics/ast/ast_node.h b/executable_semantics/ast/ast_node.h new file mode 100644 index 000000000000..4f45970e9188 --- /dev/null +++ b/executable_semantics/ast/ast_node.h @@ -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(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_ diff --git a/executable_semantics/ast/ast_rtti.txt b/executable_semantics/ast/ast_rtti.txt new file mode 100644 index 000000000000..f532bb19e9cc --- /dev/null +++ b/executable_semantics/ast/ast_rtti.txt @@ -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; diff --git a/executable_semantics/ast/declaration.cpp b/executable_semantics/ast/declaration.cpp index 8d5f14f851fa..9d949f4f161d 100644 --- a/executable_semantics/ast/declaration.cpp +++ b/executable_semantics/ast/declaration.cpp @@ -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(*this).PrintDepth(-1, out); break; - case Kind::ClassDeclaration: { + case DeclarationKind::ClassDeclaration: { const auto& class_decl = cast(*this); out << "class " << class_decl.name() << " {\n"; for (Nonnull 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(*this); out << "choice " << choice.name() << " {\n"; - for (Nonnull alt : - choice.alternatives()) { + for (Nonnull alt : choice.alternatives()) { out << "alt " << alt->name() << " " << alt->signature() << ";\n"; } out << "}\n"; break; } - case Kind::VariableDeclaration: { + case DeclarationKind::VariableDeclaration: { const auto& var = cast(*this); out << "var " << var.binding() << " = " << var.initializer() << "\n"; break; diff --git a/executable_semantics/ast/declaration.h b/executable_semantics/ast/declaration.h index f1e8eea93093..f099e0221efc 100644 --- a/executable_semantics/ast/declaration.h +++ b/executable_semantics/ast/declaration.h @@ -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(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> 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 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 type_; }; @@ -190,15 +182,15 @@ class FunctionDeclaration : public Declaration { Nonnull param_pattern, ReturnTerm return_term, std::optional> 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> 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 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 signature_; - }; - - ChoiceDeclaration(SourceLocation source_loc, std::string name, - std::vector> alternatives) - : Declaration(Kind::ChoiceDeclaration, source_loc), + AlternativeSignature(SourceLocation source_loc, std::string name, + Nonnull 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> { + auto signature() const -> const Expression& { return *signature_; } + + private: + std::string name_; + Nonnull signature_; +}; + +class ChoiceDeclaration : public Declaration { + public: + ChoiceDeclaration(SourceLocation source_loc, std::string name, + std::vector> 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> { return alternatives_; } @@ -298,7 +289,7 @@ class ChoiceDeclaration : public Declaration { private: std::string name_; - std::vector> alternatives_; + std::vector> alternatives_; StaticScope static_scope_; }; @@ -308,12 +299,12 @@ class VariableDeclaration : public Declaration { VariableDeclaration(SourceLocation source_loc, Nonnull binding, Nonnull 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_; } diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index 26233bd19972..581233fab503 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -34,6 +34,8 @@ auto TupleExpressionFromParenContents( return arena->New(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(*this); out << index.aggregate() << "[" << index.offset() << "]"; break; } - case Expression::Kind::FieldAccessExpression: { + case ExpressionKind::FieldAccessExpression: { const auto& access = cast(*this); out << access.aggregate() << "." << access.field(); break; } - case Expression::Kind::TupleLiteral: { + case ExpressionKind::TupleLiteral: { out << "("; llvm::ListSeparator sep; for (Nonnull 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(*this).fields(), " = "); out << "}"; break; - case Expression::Kind::StructTypeLiteral: + case ExpressionKind::StructTypeLiteral: out << "{"; PrintFields(out, cast(*this).fields(), ": "); out << "}"; break; - case Expression::Kind::IntLiteral: + case ExpressionKind::IntLiteral: out << cast(*this).value(); break; - case Expression::Kind::BoolLiteral: + case ExpressionKind::BoolLiteral: out << (cast(*this).value() ? "true" : "false"); break; - case Expression::Kind::PrimitiveOperatorExpression: { + case ExpressionKind::PrimitiveOperatorExpression: { out << "("; - PrimitiveOperatorExpression op = cast(*this); + const auto& op = cast(*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(*this).name(); break; - case Expression::Kind::CallExpression: { + case ExpressionKind::CallExpression: { const auto& call = cast(*this); out << call.function(); if (isa(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(*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(*this); out << "fn " << fn.parameter() << " -> " << fn.return_type(); break; } - case Expression::Kind::IntrinsicExpression: + case ExpressionKind::IntrinsicExpression: out << "intrinsic_expression("; switch (cast(*this).intrinsic()) { case IntrinsicExpression::Intrinsic::Print: diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index 4d93cededb80..a4eb23f9ab5d 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -11,6 +11,7 @@ #include #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(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> 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 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 aggregate, Nonnull 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> 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> { @@ -260,13 +243,13 @@ class StructLiteral : public Expression { public: explicit StructLiteral(SourceLocation loc, std::vector 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 { return fields_; } @@ -286,10 +269,11 @@ class StructTypeLiteral : public Expression { explicit StructTypeLiteral(SourceLocation loc, std::vector 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 { return fields_; } @@ -304,12 +288,12 @@ class PrimitiveOperatorExpression : public Expression { explicit PrimitiveOperatorExpression( SourceLocation source_loc, Operator op, std::vector> 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 function, Nonnull 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 parameter, Nonnull 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("", 0)), + : AstNode(AstNodeKind::IntrinsicExpression, + SourceLocation("", 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_; } diff --git a/executable_semantics/ast/expression_test.cpp b/executable_semantics/ast/expression_test.cpp index 95ca49323020..a4d8ed9939bb 100644 --- a/executable_semantics/ast/expression_test.cpp +++ b/executable_semantics/ast/expression_test.cpp @@ -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("", line_num); @@ -38,7 +38,7 @@ TEST_F(ExpressionTest, EmptyAsExpression) { Nonnull 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(*expression).fields(), IsEmpty()); } @@ -48,7 +48,7 @@ TEST_F(ExpressionTest, EmptyAsTuple) { Nonnull 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(*tuple).fields(), IsEmpty()); } @@ -66,7 +66,7 @@ TEST_F(ExpressionTest, UnaryNoCommaAsExpression) { Nonnull 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 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(*tuple).fields(), ElementsAre(IntField())); } @@ -89,7 +89,7 @@ TEST_F(ExpressionTest, UnaryWithCommaAsExpression) { Nonnull 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(*expression).fields(), ElementsAre(IntField())); } @@ -102,7 +102,7 @@ TEST_F(ExpressionTest, UnaryWithCommaAsTuple) { Nonnull 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(*tuple).fields(), ElementsAre(IntField())); } @@ -115,7 +115,7 @@ TEST_F(ExpressionTest, BinaryAsExpression) { Nonnull 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(*expression).fields(), ElementsAre(IntField(), IntField())); } @@ -129,7 +129,7 @@ TEST_F(ExpressionTest, BinaryAsTuple) { Nonnull 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(*tuple).fields(), ElementsAre(IntField(), IntField())); } diff --git a/executable_semantics/ast/member.cpp b/executable_semantics/ast/member.cpp index 0e7fd7f7d575..d9fd75f92363 100644 --- a/executable_semantics/ast/member.cpp +++ b/executable_semantics/ast/member.cpp @@ -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(*this); out << "var " << field.binding() << ";\n"; break; diff --git a/executable_semantics/ast/member.h b/executable_semantics/ast/member.h index b52a0daec442..090e5c2af0e6 100644 --- a/executable_semantics/ast/member.h +++ b/executable_semantics/ast/member.h @@ -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(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 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_; } diff --git a/executable_semantics/ast/pattern.cpp b/executable_semantics/ast/pattern.cpp index 4a444b871002..6e5495443efe 100644 --- a/executable_semantics/ast/pattern.cpp +++ b/executable_semantics/ast/pattern.cpp @@ -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(*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(*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(*this); out << alternative.choice_type() << "." << alternative.alternative_name() << alternative.arguments(); break; } - case Kind::ExpressionPattern: + case PatternKind::ExpressionPattern: out << cast(*this).expression(); break; } @@ -77,7 +79,7 @@ auto TuplePatternFromParenContents(Nonnull arena, // apply. static auto RequireFieldAccess(Nonnull 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 alternative) AlternativePattern::AlternativePattern(SourceLocation source_loc, Nonnull alternative, Nonnull arguments) - : Pattern(Kind::AlternativePattern, source_loc), + : AstNode(AstNodeKind::AlternativePattern, source_loc), choice_type_(&RequireFieldAccess(alternative).aggregate()), alternative_name_(RequireFieldAccess(alternative).field()), arguments_(arguments) {} diff --git a/executable_semantics/ast/pattern.h b/executable_semantics/ast/pattern.h index 7cb02b079513..b841baa1d9b6 100644 --- a/executable_semantics/ast/pattern.h +++ b/executable_semantics/ast/pattern.h @@ -10,6 +10,8 @@ #include #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(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> static_type_; std::optional> 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 name, Nonnull 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> 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> { @@ -182,7 +171,7 @@ class AlternativePattern : public Pattern { Nonnull choice_type, std::string alternative_name, Nonnull 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 alternative, Nonnull 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) - : 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_; } diff --git a/executable_semantics/ast/statement.cpp b/executable_semantics/ast/statement.cpp index 5d4e4d69cf47..82e741cb3ff6 100644 --- a/executable_semantics/ast/statement.cpp +++ b/executable_semantics/ast/statement.cpp @@ -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(*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(*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(*this); out << "var " << var.pattern() << " = " << var.init() << ";"; break; } - case Kind::ExpressionStatement: + case StatementKind::ExpressionStatement: out << cast(*this).expression() << ";"; break; - case Kind::Assign: { + case StatementKind::Assign: { const auto& assign = cast(*this); out << assign.lhs() << " = " << assign.rhs() << ";"; break; } - case Kind::If: { + case StatementKind::If: { const auto& if_stmt = cast(*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(*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(*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(*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(*this).argument() << ";"; break; - case Kind::Await: + case StatementKind::Await: out << "await;"; break; } diff --git a/executable_semantics/ast/statement.h b/executable_semantics/ast/statement.h index 95d4b09ae547..96d06d5e3fe9 100644 --- a/executable_semantics/ast/statement.h +++ b/executable_semantics/ast/statement.h @@ -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(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> 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> { @@ -89,11 +71,11 @@ class ExpressionStatement : public Statement { public: ExpressionStatement(SourceLocation source_loc, Nonnull 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 lhs, Nonnull 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, Nonnull 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 condition, Nonnull then_block, std::optional> 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(source_loc), true) {} Return(SourceLocation source_loc, Nonnull 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 condition, Nonnull 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, std::vector 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 { // // } -class Continuation : public Statement, public NamedEntityInterface { +class Continuation : public Statement, public NamedEntity { public: Continuation(SourceLocation source_loc, std::string continuation_variable, Nonnull 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 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()); } }; diff --git a/executable_semantics/ast/static_scope.cpp b/executable_semantics/ast/static_scope.cpp index 78e62121dd8c..bea0949dc075 100644 --- a/executable_semantics/ast/static_scope.cpp +++ b/executable_semantics/ast/static_scope.cpp @@ -8,8 +8,9 @@ namespace Carbon { -void StaticScope::Add(std::string name, - Nonnull entity) { +NamedEntity::~NamedEntity() = default; + +void StaticScope::Add(std::string name, Nonnull entity) { if (!declared_names_.insert({name, entity}).second) { FATAL_COMPILATION_ERROR(entity->source_loc()) << "Duplicate name `" << name << "` also found at " diff --git a/executable_semantics/ast/static_scope.h b/executable_semantics/ast/static_scope.h index 90061c9764b5..f68c91a8b7e8 100644 --- a/executable_semantics/ast/static_scope.h +++ b/executable_semantics/ast/static_scope.h @@ -10,50 +10,33 @@ #include #include +#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(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 entity); + void Add(std::string name, Nonnull entity); private: // Maps locally declared names to their entities. - std::unordered_map> - declared_names_; + std::unordered_map> 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. diff --git a/executable_semantics/gen_rtti.py b/executable_semantics/gen_rtti.py new file mode 100755 index 000000000000..c88986a7de14 --- /dev/null +++ b/executable_semantics/gen_rtti.py @@ -0,0 +1,332 @@ +#!/usr/bin/env python3 + +"""Generates C++ header to support LLVM-style RTTI for a class hierarchy. + +Takes as input a file describing the class hierarchy which can consist of +four different kinds of classes: a *root* class is the base of a class +hierarchy, meaning that it doesn't inherit from any other class. *Abstract* and +*interface* classes are non-root classes that cannot be instantiated, and +*concrete* classes are classes that can be instantiated. + +A non-root class C must inherit from exactly one parent, which can be a root or +abstract class, and can also inherit from any number of interfaces, but each +interface's parent must be an ancestor of C. + +The input file consists of comment lines starting with `#`, whitespace lines, +and one `;`-terminated line for each class. The core of a line is `class` +followed by the class name. `class` can be prefixed with `root`, `abstract`, +or `interface` to specify the corresponding kind of class; if there is no +prefix, the class is concrete. If the class is not a root class, the name is +followed by `:` and then a comma-separated list of the names of the classes +it inherits from. The first entry in the list is the parent, and the others +are interfaces. A class cannot inherit from classes defined later in the file. +For example: + +root class R; +abstract class A : R; +interface class I : R; +abstract class B : R, I; +class C : A; +class D : B; +class E : A, I; + +For each non-concrete class `Foo`, the generated header file will contain +`enum class FooKind`, which has an enumerator for each concrete class derived +from `Foo`, with a name that matches the concrete class name. + +For each non-root class `Foo` whose root class is `Root`, the generated header +file will also contain a function `bool InheritsFromFoo(RootKind kind)`, +which returns true if the value of `kind` corresponds to a class that is +derived from `Foo`. This function can be used to implement `Foo::classof`. + +All enumerators that represent the same concrete class will have the same +numeric value, so you can use `static_cast` to convert between the enum types +for different classes that have a common root, so long as the enumerator value +is present in both types. As a result, `InheritsFromFoo` can be used to +determine whether casting to `FooKind` is safe. +""" + +__copyright__ = """ +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 +""" + +import enum +import re +import sys + + +class Class: + """Metadata about a class from the input file. + + This consists of information + + Attributes set at construction: + name: The class name. + kind: The class kind (root, abstract, interface, or concrete) + ancestors: A list of Class objects representing the class's ancestors, + starting with the root and ending with the current class's parent. + interfaces: A list of Class objects representing the interfaces the class + inherits from. + _children: A list of Class objects representing the classes that are + derived directly from this one. + + Attributes set by Finalize(): + id (CONCRETE only): The class's numeric ID, which will become its + enumerator value in the generated C++ code. + id_range (ROOT and ABSTRACT only): A pair such that a Class + object `c` represents a concrete class derived from `self` if and only + if c.id >= self.id_range[0] and c.id < self.id_range[1]. + leaf_ids (INTERFACE only): A set containing the IDs of all concrete + classes derived from this interface. + leaves (ROOT only): A list of all concrete classes derived from this one, + indexed by their IDs. + """ + + Kind = enum.Enum("Kind", "ROOT ABSTRACT INTERFACE CONCRETE") + + def __init__(self, name, kind, parent, interfaces): + self.name = name + self.kind = kind + self.interfaces = interfaces + + assert (parent is None) == (kind == Class.Kind.ROOT) + if parent is None: + self.ancestors = [] + else: + self.ancestors = parent.ancestors + [parent] + + if self.kind == Class.Kind.ROOT: + self.leaves = [] + self.id_range = None + elif self.kind == Class.Kind.ABSTRACT: + self.id_range = None + elif self.kind == Class.Kind.INTERFACE: + self.leaf_ids = set() + else: + self.id = None + + if self.kind != Class.Kind.CONCRETE: + self._children = [] + + if parent: + parent._children.append(self) + + for interface in self.interfaces: + interface._children.append(self) + + def Parent(self): + """Returns this Class's parent.""" + return self.ancestors[-1] + + def Root(self): + """Returns the root Class of this hierarchy.""" + if self.kind == Class.Kind.ROOT: + return self + else: + return self.ancestors[0] + + def _RegisterLeaf(self, leaf): + """Records that `leaf` is derived from self. + + Also recursively updates the parent and interfaces of self. leaf.id must + already be populated, and leaves must be registered in order of ID. This + operation is idempotent.""" + already_visited = False + if self.kind == Class.Kind.ROOT: + if leaf.id == len(self.leaves): + self.leaves.append(leaf) + else: + assert leaf.id + 1 == len(self.leaves) + assert self.leaves[leaf.id] == leaf + already_visited = True + if self.kind in [Class.Kind.ROOT, Class.Kind.ABSTRACT]: + if self not in leaf.ancestors: + sys.exit( + f"{leaf.name} derived from {self.name}, but has a" + + " different root" + ) + if not self.id_range: + self.id_range = (leaf.id, leaf.id + 1) + elif self.id_range[1] == leaf.id: + self.id_range = (self.id_range[0], self.id_range[1] + 1) + else: + assert self.id_range[1] == leaf.id + 1 + already_visited = True + + elif self.kind == Class.Kind.INTERFACE: + if leaf.id in self.leaf_ids: + already_visited = True + else: + self.leaf_ids.add(leaf.id) + + if not already_visited: + if self.kind != Class.Kind.ROOT: + self.Parent()._RegisterLeaf(leaf) + for interface in self.interfaces: + interface._RegisterLeaf(leaf) + + def Finalize(self): + """Populates additional attributes for `self` and derived Classes. + + Each Class can only be finalized once, after which no additional Classes + can be derived from it. + """ + if self.kind == Class.Kind.CONCRETE: + self.id = len(self.Root().leaves) + self._RegisterLeaf(self) + elif self.kind in [Class.Kind.ROOT, Class.Kind.ABSTRACT]: + for child in self._children: + child.Finalize() + + +_LINE_PATTERN = r"""(?P \w*) \s* + class \s+ + (?P \w+) + (?: \s*:\s* (?P \w+) + (?: , (?P .*) )? + )? + ;$""" + + +def main(): + input_filename = sys.argv[1] + with open(input_filename) as file: + lines = file.readlines() + + classes = dict() + for line_num, line in enumerate(lines, 1): + if line.startswith("#") or line.strip() == "": + continue + match_result = re.match(_LINE_PATTERN, line.strip(), re.VERBOSE) + if not match_result: + sys.exit(f"Invalid format on line {line_num}") + + prefix = match_result.group("prefix") + if prefix == "": + kind = Class.Kind.CONCRETE + elif prefix == "root": + kind = Class.Kind.ROOT + elif prefix == "abstract": + kind = Class.Kind.ABSTRACT + elif prefix == "interface": + kind = Class.Kind.INTERFACE + else: + sys.exit(f"Unrecognized class prefix '{prefix}' on line {line_num}") + + parent = None + if match_result.group("parent"): + if kind == Class.Kind.ROOT: + sys.exit(f"Root class cannot have parent on line {line_num}") + parent_name = match_result.group("parent") + parent = classes[parent_name] + if not parent: + sys.exit(f"Unknown class '{parent_name}' on line {line_num}") + if parent.kind == Class.Kind.CONCRETE: + sys.exit(f"{parent.name} cannot be a parent on line {line_num}") + elif parent.kind == Class.Kind.INTERFACE: + if kind != Class.Kind.INTERFACE: + sys.exit( + "Interface cannot be parent of non-interface on" + + f" line {line_num}" + ) + else: + if kind != Class.Kind.ROOT: + sys.exit( + f"Non-root class must have a parent on line {line_num}" + ) + + interfaces = [] + if match_result.group("interfaces"): + for unstripped_name in match_result.group("interfaces").split(","): + interface_name = unstripped_name.strip() + interface = classes[interface_name] + if not interface: + sys.exit( + f"Unknown class '{interface_name}' on line {line_num}" + ) + if interface.kind != Class.Kind.INTERFACE: + sys.exit( + f"'{interface_name}' used as interface on" + + f" line {line_num}" + ) + interfaces.append(interface) + + classes[match_result.group("name")] = Class( + match_result.group("name"), kind, parent, interfaces + ) + + for node in classes.values(): + if node.kind == Class.Kind.ROOT: + node.Finalize() + + print( + f"// Generated from {input_filename} by" + + " executable_semantics/gen_rtti.py\n" + ) + guard_macro = ( + input_filename.upper().translate(str.maketrans({"/": "_", ".": "_"})) + + "_" + ) + print(f"#ifndef {guard_macro}") + print(f"#define {guard_macro}") + print("\nnamespace Carbon {\n") + + for node in classes.values(): + if node.kind != Class.Kind.CONCRETE: + if node.kind == Class.Kind.INTERFACE: + ids = sorted(node.leaf_ids) + else: + ids = range(node.id_range[0], node.id_range[1]) + print(f"enum class {node.name}Kind {{") + for id in ids: + print(f" {node.Root().leaves[id].name} = {id},") + print("};\n") + + if node.kind != Class.Kind.ROOT: + print( + f"inline bool InheritsFrom{node.name}({node.Root().name}Kind" + + " kind) {" + ) + if node.kind == Class.Kind.ABSTRACT: + if node.id_range[0] == node.id_range[1]: + print(" return false;") + else: + range_begin = node.Root().leaves[node.id_range[0]].name + print( + f" return kind >= {node.Root().name}Kind" + + f"::{range_begin}" + ) + if node.id_range[1] < len(node.Root().leaves): + range_end = node.Root().leaves[node.id_range[1]].name + print( + f" && kind < {node.Root().name}Kind" + + f"::{range_end}" + ) + print(" ;") + elif node.kind == Class.Kind.INTERFACE: + print(" switch(kind) {") + is_empty = True + for id in sorted(node.leaf_ids): + print( + f" case {node.Root().name}Kind::" + + f"{node.Root().leaves[id].name}:" + ) + is_empty = False + if not is_empty: + print(" return true;") + print(" default:") + print(" return false;\n }") + elif node.kind == Class.Kind.CONCRETE: + print( + f" return kind == {node.Root().name}Kind::{node.name};" + ) + print("}\n") + + print("} // namespace Carbon\n") + print(f"#endif // {guard_macro}") + + +if __name__ == "__main__": + main() diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index c6933abc951c..a2c9e0dcfd3e 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -111,7 +111,7 @@ auto Interpreter::EvalPrim(Operator op, void Interpreter::InitEnv(const Declaration& d, Env* env) { switch (d.kind()) { - case Declaration::Kind::FunctionDeclaration: { + case DeclarationKind::FunctionDeclaration: { const auto& func_def = cast(d); Env new_env = *env; // Bring the deduced parameters into scope. @@ -127,13 +127,13 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) { break; } - case Declaration::Kind::ClassDeclaration: { + case DeclarationKind::ClassDeclaration: { const auto& class_decl = cast(d); std::vector fields; std::vector methods; for (Nonnull m : class_decl.members()) { switch (m->kind()) { - case Member::Kind::FieldMember: { + case MemberKind::FieldMember: { const BindingPattern& binding = cast(*m).binding(); const Expression& type_expression = cast(binding.type()).expression(); @@ -150,10 +150,10 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) { break; } - case Declaration::Kind::ChoiceDeclaration: { + case DeclarationKind::ChoiceDeclaration: { const auto& choice = cast(d); std::vector alts; - for (Nonnull alternative : + for (Nonnull alternative : choice.alternatives()) { auto t = InterpExp(Env(arena_), &alternative->signature()); alts.push_back({.name = alternative->name(), .value = t}); @@ -164,7 +164,7 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) { break; } - case Declaration::Kind::VariableDeclaration: { + case DeclarationKind::VariableDeclaration: { const auto& var = cast(d); // Adds an entry in `globals` mapping the variable's name to the // result of evaluating the initializer. @@ -363,7 +363,7 @@ auto Interpreter::StepLvalue() -> Transition { << ") --->\n"; } switch (exp.kind()) { - case Expression::Kind::IdentifierExpression: { + case ExpressionKind::IdentifierExpression: { // { {x :: C, E, F} :: S, H} // -> { {E(x) :: C, E, F} :: S, H} Address pointer = @@ -371,7 +371,7 @@ auto Interpreter::StepLvalue() -> Transition { Nonnull v = arena_->New(pointer); return Done{v}; } - case Expression::Kind::FieldAccessExpression: { + case ExpressionKind::FieldAccessExpression: { if (act.pos() == 0) { // { {e.f :: C, E, F} :: S, H} // -> { e :: [].f :: C, E, F} :: S, H} @@ -386,7 +386,7 @@ auto Interpreter::StepLvalue() -> Transition { return Done{arena_->New(field)}; } } - case Expression::Kind::IndexExpression: { + case ExpressionKind::IndexExpression: { if (act.pos() == 0) { // { {e[i] :: C, E, F} :: S, H} // -> { e :: [][i] :: C, E, F} :: S, H} @@ -406,7 +406,7 @@ auto Interpreter::StepLvalue() -> Transition { return Done{arena_->New(field)}; } } - case Expression::Kind::TupleLiteral: { + case ExpressionKind::TupleLiteral: { if (act.pos() < static_cast(cast(exp).fields().size())) { // { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S, @@ -419,20 +419,20 @@ auto Interpreter::StepLvalue() -> Transition { return Done{arena_->New(act.results())}; } } - case Expression::Kind::StructLiteral: - case Expression::Kind::StructTypeLiteral: - case Expression::Kind::IntLiteral: - case Expression::Kind::BoolLiteral: - case Expression::Kind::CallExpression: - case Expression::Kind::PrimitiveOperatorExpression: - case Expression::Kind::IntTypeLiteral: - case Expression::Kind::BoolTypeLiteral: - case Expression::Kind::TypeTypeLiteral: - case Expression::Kind::FunctionTypeLiteral: - case Expression::Kind::ContinuationTypeLiteral: - case Expression::Kind::StringLiteral: - case Expression::Kind::StringTypeLiteral: - case Expression::Kind::IntrinsicExpression: + case ExpressionKind::StructLiteral: + case ExpressionKind::StructTypeLiteral: + case ExpressionKind::IntLiteral: + case ExpressionKind::BoolLiteral: + case ExpressionKind::CallExpression: + case ExpressionKind::PrimitiveOperatorExpression: + case ExpressionKind::IntTypeLiteral: + case ExpressionKind::BoolTypeLiteral: + case ExpressionKind::TypeTypeLiteral: + case ExpressionKind::FunctionTypeLiteral: + case ExpressionKind::ContinuationTypeLiteral: + case ExpressionKind::StringLiteral: + case ExpressionKind::StringTypeLiteral: + case ExpressionKind::IntrinsicExpression: FATAL_RUNTIME_ERROR_NO_LINE() << "Can't treat expression as lvalue: " << exp; } @@ -513,7 +513,7 @@ auto Interpreter::StepExp() -> Transition { << ") --->\n"; } switch (exp.kind()) { - case Expression::Kind::IndexExpression: { + case ExpressionKind::IndexExpression: { if (act.pos() == 0) { // { { e[i] :: C, E, F} :: S, H} // -> { { e :: [][i] :: C, E, F} :: S, H} @@ -534,7 +534,7 @@ auto Interpreter::StepExp() -> Transition { return Done{tuple.elements()[i]}; } } - case Expression::Kind::TupleLiteral: { + case ExpressionKind::TupleLiteral: { if (act.pos() < static_cast(cast(exp).fields().size())) { // { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S, @@ -547,7 +547,7 @@ auto Interpreter::StepExp() -> Transition { return Done{arena_->New(act.results())}; } } - case Expression::Kind::StructLiteral: { + case ExpressionKind::StructLiteral: { const auto& literal = cast(exp); if (act.pos() < static_cast(literal.fields().size())) { return Spawn{std::make_unique( @@ -556,7 +556,7 @@ auto Interpreter::StepExp() -> Transition { return Done{CreateStruct(literal.fields(), act.results())}; } } - case Expression::Kind::StructTypeLiteral: { + case ExpressionKind::StructTypeLiteral: { const auto& struct_type = cast(exp); if (act.pos() < static_cast(struct_type.fields().size())) { return Spawn{std::make_unique( @@ -569,7 +569,7 @@ auto Interpreter::StepExp() -> Transition { return Done{arena_->New(std::move(fields))}; } } - case Expression::Kind::FieldAccessExpression: { + case ExpressionKind::FieldAccessExpression: { const auto& access = cast(exp); if (act.pos() == 0) { // { { e.f :: C, E, F} :: S, H} @@ -582,22 +582,22 @@ auto Interpreter::StepExp() -> Transition { arena_, FieldPath(access.field()), exp.source_loc())}; } } - case Expression::Kind::IdentifierExpression: { + case ExpressionKind::IdentifierExpression: { CHECK(act.pos() == 0); const auto& ident = cast(exp); // { {x :: C, E, F} :: S, H} -> { {H(E(x)) :: C, E, F} :: S, H} Address pointer = GetFromEnv(exp.source_loc(), ident.name()); return Done{heap_.Read(pointer, exp.source_loc())}; } - case Expression::Kind::IntLiteral: + case ExpressionKind::IntLiteral: CHECK(act.pos() == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} return Done{arena_->New(cast(exp).value())}; - case Expression::Kind::BoolLiteral: + case ExpressionKind::BoolLiteral: CHECK(act.pos() == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} return Done{arena_->New(cast(exp).value())}; - case Expression::Kind::PrimitiveOperatorExpression: { + case ExpressionKind::PrimitiveOperatorExpression: { const auto& op = cast(exp); if (act.pos() != static_cast(op.arguments().size())) { // { {v :: op(vs,[],e,es) :: C, E, F} :: S, H} @@ -610,7 +610,7 @@ auto Interpreter::StepExp() -> Transition { return Done{EvalPrim(op.op(), act.results(), exp.source_loc())}; } } - case Expression::Kind::CallExpression: + case ExpressionKind::CallExpression: if (act.pos() == 0) { // { {e1(e2) :: C, E, F} :: S, H} // -> { {e1 :: [](e2) :: C, E, F} :: S, H} @@ -651,7 +651,7 @@ auto Interpreter::StepExp() -> Transition { } else { FATAL() << "in handle_value with Call pos " << act.pos(); } - case Expression::Kind::IntrinsicExpression: + case ExpressionKind::IntrinsicExpression: CHECK(act.pos() == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} switch (cast(exp).intrinsic()) { @@ -664,19 +664,19 @@ auto Interpreter::StepExp() -> Transition { return Done{TupleValue::Empty()}; } - case Expression::Kind::IntTypeLiteral: { + case ExpressionKind::IntTypeLiteral: { CHECK(act.pos() == 0); return Done{arena_->New()}; } - case Expression::Kind::BoolTypeLiteral: { + case ExpressionKind::BoolTypeLiteral: { CHECK(act.pos() == 0); return Done{arena_->New()}; } - case Expression::Kind::TypeTypeLiteral: { + case ExpressionKind::TypeTypeLiteral: { CHECK(act.pos() == 0); return Done{arena_->New()}; } - case Expression::Kind::FunctionTypeLiteral: { + case ExpressionKind::FunctionTypeLiteral: { if (act.pos() == 0) { return Spawn{std::make_unique( &cast(exp).parameter())}; @@ -693,15 +693,15 @@ auto Interpreter::StepExp() -> Transition { act.results()[1])}; } } - case Expression::Kind::ContinuationTypeLiteral: { + case ExpressionKind::ContinuationTypeLiteral: { CHECK(act.pos() == 0); return Done{arena_->New()}; } - case Expression::Kind::StringLiteral: + case ExpressionKind::StringLiteral: CHECK(act.pos() == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} return Done{arena_->New(cast(exp).value())}; - case Expression::Kind::StringTypeLiteral: { + case ExpressionKind::StringTypeLiteral: { CHECK(act.pos() == 0); return Done{arena_->New()}; } @@ -716,11 +716,11 @@ auto Interpreter::StepPattern() -> Transition { << pattern.source_loc() << ") --->\n"; } switch (pattern.kind()) { - case Pattern::Kind::AutoPattern: { + case PatternKind::AutoPattern: { CHECK(act.pos() == 0); return Done{arena_->New()}; } - case Pattern::Kind::BindingPattern: { + case PatternKind::BindingPattern: { const auto& binding = cast(pattern); if (act.pos() == 0) { return Spawn{std::make_unique(&binding.type())}; @@ -729,7 +729,7 @@ auto Interpreter::StepPattern() -> Transition { act.results()[0])}; } } - case Pattern::Kind::TuplePattern: { + case PatternKind::TuplePattern: { const auto& tuple = cast(pattern); if (act.pos() < static_cast(tuple.fields().size())) { // { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S, @@ -742,7 +742,7 @@ auto Interpreter::StepPattern() -> Transition { return Done{arena_->New(act.results())}; } } - case Pattern::Kind::AlternativePattern: { + case PatternKind::AlternativePattern: { const auto& alternative = cast(pattern); if (act.pos() == 0) { return Spawn{ @@ -757,7 +757,7 @@ auto Interpreter::StepPattern() -> Transition { act.results()[1])}; } } - case Pattern::Kind::ExpressionPattern: + case PatternKind::ExpressionPattern: return Delegate{std::make_unique( &cast(pattern).expression())}; } @@ -777,7 +777,7 @@ auto Interpreter::StepStmt() -> Transition { llvm::outs() << " (" << stmt.source_loc() << ") --->\n"; } switch (stmt.kind()) { - case Statement::Kind::Match: { + case StatementKind::Match: { const auto& match_stmt = cast(stmt); if (act.pos() == 0) { // { { (match (e) ...) :: C, E, F} :: S, H} @@ -808,7 +808,7 @@ auto Interpreter::StepStmt() -> Transition { } } } - case Statement::Kind::While: + case StatementKind::While: if (act.pos() % 2 == 0) { // { { (while (e) s) :: C, E, F} :: S, H} // -> { { e :: (while ([]) s) :: C, E, F} :: S, H} @@ -829,19 +829,19 @@ auto Interpreter::StepStmt() -> Transition { return Done{}; } } - case Statement::Kind::Break: { + case StatementKind::Break: { CHECK(act.pos() == 0); // { { break; :: ... :: (while (e) s) :: C, E, F} :: S, H} // -> { { C, E', F} :: S, H} return UnwindPast{.ast_node = &cast(stmt).loop()}; } - case Statement::Kind::Continue: { + case StatementKind::Continue: { CHECK(act.pos() == 0); // { { continue; :: ... :: (while (e) s) :: C, E, F} :: S, H} // -> { { (while (e) s) :: C, E', F} :: S, H} return UnwindTo{.ast_node = &cast(stmt).loop()}; } - case Statement::Kind::Block: { + case StatementKind::Block: { const auto& block = cast(stmt); if (act.pos() >= static_cast(block.statements().size())) { // If the position is past the end of the block, end processing. Note @@ -857,7 +857,7 @@ auto Interpreter::StepStmt() -> Transition { return Spawn{ std::make_unique(block.statements()[act.pos()])}; } - case Statement::Kind::VariableDefinition: { + case StatementKind::VariableDefinition: { const auto& definition = cast(stmt); if (act.pos() == 0) { // { {(var x = e) :: C, E, F} :: S, H} @@ -882,7 +882,7 @@ auto Interpreter::StepStmt() -> Transition { return Done{}; } } - case Statement::Kind::ExpressionStatement: + case StatementKind::ExpressionStatement: if (act.pos() == 0) { // { {e :: C, E, F} :: S, H} // -> { {e :: C, E, F} :: S, H} @@ -891,7 +891,7 @@ auto Interpreter::StepStmt() -> Transition { } else { return Done{}; } - case Statement::Kind::Assign: { + case StatementKind::Assign: { const auto& assign = cast(stmt); if (act.pos() == 0) { // { {(lv = e) :: C, E, F} :: S, H} @@ -910,7 +910,7 @@ auto Interpreter::StepStmt() -> Transition { return Done{}; } } - case Statement::Kind::If: + case StatementKind::If: if (act.pos() == 0) { // { {(if (e) then_stmt else else_stmt) :: C, E, F} :: S, H} // -> { { e :: (if ([]) then_stmt else else_stmt) :: C, E, F} :: S, H} @@ -935,7 +935,7 @@ auto Interpreter::StepStmt() -> Transition { return Done{}; } } - case Statement::Kind::Return: + case StatementKind::Return: if (act.pos() == 0) { // { {return e :: C, E, F} :: S, H} // -> { {e :: return [] :: C, E, F} :: S, H} @@ -950,7 +950,7 @@ auto Interpreter::StepStmt() -> Transition { .result = Convert(act.results()[0], &function.return_term().static_type())}; } - case Statement::Kind::Continuation: { + case StatementKind::Continuation: { CHECK(act.pos() == 0); // Create a continuation object by creating a frame similar the // way one is created in a function call. @@ -969,7 +969,7 @@ auto Interpreter::StepStmt() -> Transition { continuation_address); return Done{}; } - case Statement::Kind::Run: { + case StatementKind::Run: { auto& run = cast(stmt); if (act.pos() == 0) { // Evaluate the argument of the run statement. @@ -985,7 +985,7 @@ auto Interpreter::StepStmt() -> Transition { return Done{}; } } - case Statement::Kind::Await: + case StatementKind::Await: CHECK(act.pos() == 0); // Pause the current continuation todo_.Pop(); diff --git a/executable_semantics/interpreter/resolve_control_flow.cpp b/executable_semantics/interpreter/resolve_control_flow.cpp index 313c9a156835..4939094929ea 100644 --- a/executable_semantics/interpreter/resolve_control_flow.cpp +++ b/executable_semantics/interpreter/resolve_control_flow.cpp @@ -34,7 +34,7 @@ static void ResolveControlFlow(Nonnull statement, std::optional> loop, std::optional> function) { switch (statement->kind()) { - case Statement::Kind::Return: { + case StatementKind::Return: { if (!function.has_value()) { FATAL_COMPILATION_ERROR(statement->source_loc()) << "return is not within a function body"; @@ -58,21 +58,21 @@ static void ResolveControlFlow(Nonnull statement, } return; } - case Statement::Kind::Break: + case StatementKind::Break: if (!loop.has_value()) { FATAL_COMPILATION_ERROR(statement->source_loc()) << "break is not within a loop body"; } cast(*statement).set_loop(*loop); return; - case Statement::Kind::Continue: + case StatementKind::Continue: if (!loop.has_value()) { FATAL_COMPILATION_ERROR(statement->source_loc()) << "continue is not within a loop body"; } cast(*statement).set_loop(*loop); return; - case Statement::Kind::If: { + case StatementKind::If: { auto& if_stmt = cast(*statement); ResolveControlFlow(&if_stmt.then_block(), loop, function); if (if_stmt.else_block().has_value()) { @@ -80,39 +80,39 @@ static void ResolveControlFlow(Nonnull statement, } return; } - case Statement::Kind::Block: { + case StatementKind::Block: { auto& block = cast(*statement); for (auto* block_statement : block.statements()) { ResolveControlFlow(block_statement, loop, function); } return; } - case Statement::Kind::While: + case StatementKind::While: ResolveControlFlow(&cast(*statement).body(), statement, function); return; - case Statement::Kind::Match: { + case StatementKind::Match: { auto& match = cast(*statement); for (Match::Clause& clause : match.clauses()) { ResolveControlFlow(&clause.statement(), loop, function); } return; } - case Statement::Kind::Continuation: + case StatementKind::Continuation: ResolveControlFlow(&cast(*statement).body(), std::nullopt, std::nullopt); return; - case Statement::Kind::ExpressionStatement: - case Statement::Kind::Assign: - case Statement::Kind::VariableDefinition: - case Statement::Kind::Run: - case Statement::Kind::Await: + case StatementKind::ExpressionStatement: + case StatementKind::Assign: + case StatementKind::VariableDefinition: + case StatementKind::Run: + case StatementKind::Await: return; } } void ResolveControlFlow(AST& ast) { for (auto declaration : ast.declarations) { - if (declaration->kind() != Declaration::Kind::FunctionDeclaration) { + if (declaration->kind() != DeclarationKind::FunctionDeclaration) { continue; } auto& function = cast(*declaration); diff --git a/executable_semantics/interpreter/resolve_names.cpp b/executable_semantics/interpreter/resolve_names.cpp index 604849a2ec02..d0636c995983 100644 --- a/executable_semantics/interpreter/resolve_names.cpp +++ b/executable_semantics/interpreter/resolve_names.cpp @@ -17,27 +17,27 @@ namespace { // flow. void PopulateNamesInPattern(const Pattern& pattern, StaticScope& static_scope) { switch (pattern.kind()) { - case Pattern::Kind::AlternativePattern: { + case PatternKind::AlternativePattern: { const auto& alt = cast(pattern); PopulateNamesInPattern(alt.arguments(), static_scope); break; } - case Pattern::Kind::BindingPattern: { + case PatternKind::BindingPattern: { const auto& binding = cast(pattern); if (binding.name().has_value()) { static_scope.Add(*binding.name(), &binding); } break; } - case Pattern::Kind::TuplePattern: { + case PatternKind::TuplePattern: { const auto& tuple = cast(pattern); for (auto* field : tuple.fields()) { PopulateNamesInPattern(*field, static_scope); } break; } - case Pattern::Kind::AutoPattern: - case Pattern::Kind::ExpressionPattern: + case PatternKind::AutoPattern: + case PatternKind::ExpressionPattern: // These don't add names. break; } @@ -53,7 +53,7 @@ void PopulateNamesInStatement(Arena* arena, } Statement& statement = **opt_statement; switch (statement.kind()) { - case Statement::Kind::Block: { + case StatementKind::Block: { // Defines a new scope for names. auto& block = cast(statement); for (const auto& statement : block.statements()) { @@ -61,33 +61,33 @@ void PopulateNamesInStatement(Arena* arena, } break; } - case Statement::Kind::Continuation: { + case StatementKind::Continuation: { // Defines a new name and contains a block. auto& cont = cast(statement); static_scope.Add(cont.continuation_variable(), &cont); PopulateNamesInStatement(arena, &cont.body(), static_scope); break; } - case Statement::Kind::VariableDefinition: { + case StatementKind::VariableDefinition: { // Defines a new name. const auto& var = cast(statement); PopulateNamesInPattern(var.pattern(), static_scope); break; } - case Statement::Kind::If: { + case StatementKind::If: { // Contains blocks. auto& if_stmt = cast(statement); PopulateNamesInStatement(arena, &if_stmt.then_block(), static_scope); PopulateNamesInStatement(arena, if_stmt.else_block(), static_scope); break; } - case Statement::Kind::While: { + case StatementKind::While: { // Contains a block. auto& while_stmt = cast(statement); PopulateNamesInStatement(arena, &while_stmt.body(), static_scope); break; } - case Statement::Kind::Match: { + case StatementKind::Match: { // Contains blocks. auto& match = cast(statement); for (auto& clause : match.clauses()) { @@ -97,13 +97,13 @@ void PopulateNamesInStatement(Arena* arena, } break; } - case Statement::Kind::Assign: - case Statement::Kind::Await: - case Statement::Kind::Break: - case Statement::Kind::Continue: - case Statement::Kind::ExpressionStatement: - case Statement::Kind::Return: - case Statement::Kind::Run: + case StatementKind::Assign: + case StatementKind::Await: + case StatementKind::Break: + case StatementKind::Continue: + case StatementKind::ExpressionStatement: + case StatementKind::Return: + case StatementKind::Run: // Neither contains names nor a scope. break; } @@ -114,7 +114,7 @@ void PopulateNamesInStatement(Arena* arena, void PopulateNamesInMember(Arena* arena, const Member& member, StaticScope& static_scope) { switch (member.kind()) { - case Member::Kind::FieldMember: { + case MemberKind::FieldMember: { const auto& field = cast(member); if (field.binding().name().has_value()) { static_scope.Add(*field.binding().name(), &member); @@ -130,7 +130,7 @@ void PopulateNamesInMember(Arena* arena, const Member& member, void PopulateNamesInDeclaration(Arena* arena, Declaration& declaration, StaticScope& static_scope) { switch (declaration.kind()) { - case Declaration::Kind::FunctionDeclaration: { + case DeclarationKind::FunctionDeclaration: { auto& func = cast(declaration); static_scope.Add(func.name(), &declaration); for (Nonnull param : func.deduced_parameters()) { @@ -140,7 +140,7 @@ void PopulateNamesInDeclaration(Arena* arena, Declaration& declaration, PopulateNamesInStatement(arena, func.body(), static_scope); break; } - case Declaration::Kind::ClassDeclaration: { + case DeclarationKind::ClassDeclaration: { auto& class_decl = cast(declaration); static_scope.Add(class_decl.name(), &declaration); for (auto* member : class_decl.members()) { @@ -148,11 +148,10 @@ void PopulateNamesInDeclaration(Arena* arena, Declaration& declaration, } break; } - case Declaration::Kind::ChoiceDeclaration: { + case DeclarationKind::ChoiceDeclaration: { auto& choice = cast(declaration); static_scope.Add(choice.name(), &declaration); - for (Nonnull alt : - choice.alternatives()) { + for (Nonnull alt : choice.alternatives()) { choice.static_scope().Add(alt->name(), alt); } // Populate name into declared_names. @@ -160,7 +159,7 @@ void PopulateNamesInDeclaration(Arena* arena, Declaration& declaration, // alternatives. break; } - case Declaration::Kind::VariableDeclaration: + case DeclarationKind::VariableDeclaration: auto& var = cast(declaration); if (var.binding().name().has_value()) { static_scope.Add(*(var.binding().name()), &var.binding()); @@ -177,10 +176,10 @@ void PopulateNamesInDeclaration(Arena* arena, Declaration& declaration, void ResolveNamesInDeclaration(Declaration& declaration, const StaticScope& static_scope) { switch (declaration.kind()) { - case Declaration::Kind::FunctionDeclaration: - case Declaration::Kind::ClassDeclaration: - case Declaration::Kind::ChoiceDeclaration: - case Declaration::Kind::VariableDeclaration: + case DeclarationKind::FunctionDeclaration: + case DeclarationKind::ClassDeclaration: + case DeclarationKind::ChoiceDeclaration: + case DeclarationKind::VariableDeclaration: break; } } diff --git a/executable_semantics/interpreter/type_checker.cpp b/executable_semantics/interpreter/type_checker.cpp index b813741aee9f..72b4b5b82d11 100644 --- a/executable_semantics/interpreter/type_checker.cpp +++ b/executable_semantics/interpreter/type_checker.cpp @@ -434,7 +434,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, llvm::outs() << "\n"; } switch (e->kind()) { - case Expression::Kind::IndexExpression: { + case ExpressionKind::IndexExpression: { auto& index = cast(*e); auto res = TypeCheckExp(&index.aggregate(), types, values); const Value& aggregate_type = index.aggregate().static_type(); @@ -455,7 +455,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, FATAL_COMPILATION_ERROR(e->source_loc()) << "expected a tuple"; } } - case Expression::Kind::TupleLiteral: { + case ExpressionKind::TupleLiteral: { std::vector> arg_types; auto new_types = types; for (auto& arg : cast(*e).fields()) { @@ -466,7 +466,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, SetStaticType(e, arena_->New(std::move(arg_types))); return TCResult(new_types); } - case Expression::Kind::StructLiteral: { + case ExpressionKind::StructLiteral: { std::vector new_args; std::vector arg_types; auto new_types = types; @@ -479,7 +479,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, SetStaticType(e, arena_->New(std::move(arg_types))); return TCResult(new_types); } - case Expression::Kind::StructTypeLiteral: { + case ExpressionKind::StructTypeLiteral: { auto& struct_type = cast(*e); std::vector new_args; auto new_types = types; @@ -501,7 +501,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, } return TCResult(new_types); } - case Expression::Kind::FieldAccessExpression: { + case ExpressionKind::FieldAccessExpression: { auto& access = cast(*e); auto res = TypeCheckExp(&access.aggregate(), types, values); const Value& aggregate_type = access.aggregate().static_type(); @@ -559,7 +559,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, << *e; } } - case Expression::Kind::IdentifierExpression: { + case ExpressionKind::IdentifierExpression: { auto& ident = cast(*e); std::optional> type = types.Get(ident.name()); if (type) { @@ -570,13 +570,13 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, << "could not find `" << ident.name() << "`"; } } - case Expression::Kind::IntLiteral: + case ExpressionKind::IntLiteral: SetStaticType(e, arena_->New()); return TCResult(types); - case Expression::Kind::BoolLiteral: + case ExpressionKind::BoolLiteral: SetStaticType(e, arena_->New()); return TCResult(types); - case Expression::Kind::PrimitiveOperatorExpression: { + case ExpressionKind::PrimitiveOperatorExpression: { auto& op = cast(*e); std::vector> es; std::vector> ts; @@ -647,7 +647,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, } break; } - case Expression::Kind::CallExpression: { + case ExpressionKind::CallExpression: { auto& call = cast(*e); auto fun_res = TypeCheckExp(&call.function(), types, values); switch (call.function().static_type().kind()) { @@ -687,7 +687,7 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, } break; } - case Expression::Kind::FunctionTypeLiteral: { + case ExpressionKind::FunctionTypeLiteral: { auto& fn = cast(*e); ExpectIsConcreteType(fn.parameter().source_loc(), interpreter_.InterpExp(values, &fn.parameter())); @@ -696,20 +696,20 @@ auto TypeChecker::TypeCheckExp(Nonnull e, TypeEnv types, SetStaticType(&fn, arena_->New()); return TCResult(types); } - case Expression::Kind::StringLiteral: + case ExpressionKind::StringLiteral: SetStaticType(e, arena_->New()); return TCResult(types); - case Expression::Kind::IntrinsicExpression: + case ExpressionKind::IntrinsicExpression: switch (cast(*e).intrinsic()) { case IntrinsicExpression::Intrinsic::Print: SetStaticType(e, TupleValue::Empty()); return TCResult(types); } - case Expression::Kind::IntTypeLiteral: - case Expression::Kind::BoolTypeLiteral: - case Expression::Kind::StringTypeLiteral: - case Expression::Kind::TypeTypeLiteral: - case Expression::Kind::ContinuationTypeLiteral: + case ExpressionKind::IntTypeLiteral: + case ExpressionKind::BoolTypeLiteral: + case ExpressionKind::StringTypeLiteral: + case ExpressionKind::TypeTypeLiteral: + case ExpressionKind::ContinuationTypeLiteral: SetStaticType(e, arena_->New()); return TCResult(types); } @@ -730,11 +730,11 @@ auto TypeChecker::TypeCheckPattern( llvm::outs() << "\n"; } switch (p->kind()) { - case Pattern::Kind::AutoPattern: { + case PatternKind::AutoPattern: { SetStaticType(p, arena_->New()); return TCResult(types); } - case Pattern::Kind::BindingPattern: { + case PatternKind::BindingPattern: { auto& binding = cast(*p); TypeCheckPattern(&binding.type(), types, values, std::nullopt); Nonnull type = @@ -763,7 +763,7 @@ auto TypeChecker::TypeCheckPattern( SetValue(&binding, interpreter_.InterpPattern(values, &binding)); return TCResult(types); } - case Pattern::Kind::TuplePattern: { + case PatternKind::TuplePattern: { auto& tuple = cast(*p); std::vector> field_types; auto new_types = types; @@ -790,7 +790,7 @@ auto TypeChecker::TypeCheckPattern( SetValue(&tuple, interpreter_.InterpPattern(values, &tuple)); return TCResult(new_types); } - case Pattern::Kind::AlternativePattern: { + case PatternKind::AlternativePattern: { auto& alternative = cast(*p); Nonnull choice_type = interpreter_.InterpExp(values, &alternative.choice_type()); @@ -816,7 +816,7 @@ auto TypeChecker::TypeCheckPattern( SetValue(&alternative, interpreter_.InterpPattern(values, &alternative)); return TCResult(arg_results.types); } - case Pattern::Kind::ExpressionPattern: { + case PatternKind::ExpressionPattern: { auto& expression = cast(*p).expression(); TCResult result = TypeCheckExp(&expression, types, values); SetStaticType(p, &expression.static_type()); @@ -837,7 +837,7 @@ auto TypeChecker::TypeCheckCase(Nonnull expected, auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, Env values) -> TCResult { switch (s->kind()) { - case Statement::Kind::Match: { + case StatementKind::Match: { auto& match = cast(*s); TypeCheckExp(&match.expression(), types, values); std::vector new_clauses; @@ -848,7 +848,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, } return TCResult(types); } - case Statement::Kind::While: { + case StatementKind::While: { auto& while_stmt = cast(*s); TypeCheckExp(&while_stmt.condition(), types, values); ExpectType(s->source_loc(), "condition of `while`", @@ -857,10 +857,10 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, TypeCheckStmt(&while_stmt.body(), types, values); return TCResult(types); } - case Statement::Kind::Break: - case Statement::Kind::Continue: + case StatementKind::Break: + case StatementKind::Continue: return TCResult(types); - case Statement::Kind::Block: { + case StatementKind::Block: { auto& block = cast(*s); for (auto* block_statement : block.statements()) { auto result = TypeCheckStmt(block_statement, types, values); @@ -868,14 +868,14 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, } return TCResult(types); } - case Statement::Kind::VariableDefinition: { + case StatementKind::VariableDefinition: { auto& var = cast(*s); TypeCheckExp(&var.init(), types, values); const Value& rhs_ty = var.init().static_type(); auto lhs_res = TypeCheckPattern(&var.pattern(), types, values, &rhs_ty); return TCResult(lhs_res.types); } - case Statement::Kind::Assign: { + case StatementKind::Assign: { auto& assign = cast(*s); TypeCheckExp(&assign.rhs(), types, values); auto lhs_res = TypeCheckExp(&assign.lhs(), types, values); @@ -883,11 +883,11 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, &assign.rhs().static_type()); return TCResult(lhs_res.types); } - case Statement::Kind::ExpressionStatement: { + case StatementKind::ExpressionStatement: { TypeCheckExp(&cast(*s).expression(), types, values); return TCResult(types); } - case Statement::Kind::If: { + case StatementKind::If: { auto& if_stmt = cast(*s); TypeCheckExp(&if_stmt.condition(), types, values); ExpectType(s->source_loc(), "condition of `if`", arena_->New(), @@ -898,7 +898,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, } return TCResult(types); } - case Statement::Kind::Return: { + case StatementKind::Return: { auto& ret = cast(*s); TypeCheckExp(&ret.expression(), types, values); ReturnTerm& return_term = ret.function().return_term(); @@ -910,13 +910,13 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, } return TCResult(types); } - case Statement::Kind::Continuation: { + case StatementKind::Continuation: { auto& cont = cast(*s); TypeCheckStmt(&cont.body(), types, values); types.Set(cont.continuation_variable(), arena_->New()); return TCResult(types); } - case Statement::Kind::Run: { + case StatementKind::Run: { auto& run = cast(*s); TypeCheckExp(&run.argument(), types, values); ExpectType(s->source_loc(), "argument of `run`", @@ -924,7 +924,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, &run.argument().static_type()); return TCResult(types); } - case Statement::Kind::Await: { + case StatementKind::Await: { // nothing to do here return TCResult(types); } @@ -939,7 +939,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull s, TypeEnv types, static auto IsExhaustive(const Match& match) -> bool { for (const Match::Clause& clause : match.clauses()) { // A pattern consisting of a single variable binding is guaranteed to match. - if (clause.pattern().kind() == Pattern::Kind::BindingPattern) { + if (clause.pattern().kind() == PatternKind::BindingPattern) { return true; } } @@ -955,7 +955,7 @@ void TypeChecker::ExpectReturnOnAllPaths( } Nonnull stmt = *opt_stmt; switch (stmt->kind()) { - case Statement::Kind::Match: { + case StatementKind::Match: { auto& match = cast(*stmt); if (!IsExhaustive(match)) { FATAL_COMPILATION_ERROR(source_loc) @@ -968,7 +968,7 @@ void TypeChecker::ExpectReturnOnAllPaths( } return; } - case Statement::Kind::Block: { + case StatementKind::Block: { auto& block = cast(*stmt); if (block.statements().empty()) { FATAL_COMPILATION_ERROR(stmt->source_loc()) @@ -979,24 +979,24 @@ void TypeChecker::ExpectReturnOnAllPaths( block.source_loc()); return; } - case Statement::Kind::If: { + case StatementKind::If: { auto& if_stmt = cast(*stmt); ExpectReturnOnAllPaths(&if_stmt.then_block(), stmt->source_loc()); ExpectReturnOnAllPaths(if_stmt.else_block(), stmt->source_loc()); return; } - case Statement::Kind::Return: + case StatementKind::Return: return; - case Statement::Kind::Continuation: - case Statement::Kind::Run: - case Statement::Kind::Await: + case StatementKind::Continuation: + case StatementKind::Run: + case StatementKind::Await: return; - case Statement::Kind::Assign: - case Statement::Kind::ExpressionStatement: - case Statement::Kind::While: - case Statement::Kind::Break: - case Statement::Kind::Continue: - case Statement::Kind::VariableDefinition: + case StatementKind::Assign: + case StatementKind::ExpressionStatement: + case StatementKind::While: + case StatementKind::Break: + case StatementKind::Continue: + case StatementKind::VariableDefinition: FATAL_COMPILATION_ERROR(stmt->source_loc()) << "control-flow reaches end of function that provides a `->` " "return type without reaching a return statement"; @@ -1069,7 +1069,7 @@ auto TypeChecker::TypeOfClassDecl(const ClassDeclaration& class_decl, std::vector methods; for (Nonnull m : class_decl.members()) { switch (m->kind()) { - case Member::Kind::FieldMember: { + case MemberKind::FieldMember: { const BindingPattern& binding = cast(*m).binding(); if (!binding.name().has_value()) { FATAL_COMPILATION_ERROR(binding.source_loc()) @@ -1092,13 +1092,13 @@ auto TypeChecker::TypeOfClassDecl(const ClassDeclaration& class_decl, static auto GetName(const Declaration& d) -> const std::string& { switch (d.kind()) { - case Declaration::Kind::FunctionDeclaration: + case DeclarationKind::FunctionDeclaration: return cast(d).name(); - case Declaration::Kind::ClassDeclaration: + case DeclarationKind::ClassDeclaration: return cast(d).name(); - case Declaration::Kind::ChoiceDeclaration: + case DeclarationKind::ChoiceDeclaration: return cast(d).name(); - case Declaration::Kind::VariableDeclaration: { + case DeclarationKind::VariableDeclaration: { const BindingPattern& binding = cast(d).binding(); if (!binding.name().has_value()) { FATAL_COMPILATION_ERROR(binding.source_loc()) @@ -1122,19 +1122,19 @@ void TypeChecker::TypeCheckDeclaration(Nonnull d, const TypeEnv& types, const Env& values) { switch (d->kind()) { - case Declaration::Kind::FunctionDeclaration: + case DeclarationKind::FunctionDeclaration: TypeCheckFunctionDeclaration(&cast(*d), types, values, /*check_body=*/true); return; - case Declaration::Kind::ClassDeclaration: + case DeclarationKind::ClassDeclaration: // TODO return; - case Declaration::Kind::ChoiceDeclaration: + case DeclarationKind::ChoiceDeclaration: // TODO return; - case Declaration::Kind::VariableDeclaration: { + case DeclarationKind::VariableDeclaration: { auto& var = cast(*d); // Signals a type error if the initializing expression does not have // the declared type of the variable, otherwise returns this @@ -1159,7 +1159,7 @@ void TypeChecker::TypeCheckDeclaration(Nonnull d, void TypeChecker::TopLevel(Nonnull d, TypeCheckContext* tops) { switch (d->kind()) { - case Declaration::Kind::FunctionDeclaration: { + case DeclarationKind::FunctionDeclaration: { auto& func_def = cast(*d); TypeCheckFunctionDeclaration(&func_def, tops->types, tops->values, /*check_body=*/false); @@ -1168,7 +1168,7 @@ void TypeChecker::TopLevel(Nonnull d, TypeCheckContext* tops) { break; } - case Declaration::Kind::ClassDeclaration: { + case DeclarationKind::ClassDeclaration: { const auto& class_decl = cast(*d); auto st = TypeOfClassDecl(class_decl, tops->types, tops->values); AllocationId a = interpreter_.AllocateValue(st); @@ -1177,10 +1177,10 @@ void TypeChecker::TopLevel(Nonnull d, TypeCheckContext* tops) { break; } - case Declaration::Kind::ChoiceDeclaration: { + case DeclarationKind::ChoiceDeclaration: { const auto& choice = cast(*d); std::vector alts; - for (Nonnull alternative : + for (Nonnull alternative : choice.alternatives()) { auto t = interpreter_.InterpExp(tops->values, &alternative->signature()); @@ -1193,7 +1193,7 @@ void TypeChecker::TopLevel(Nonnull d, TypeCheckContext* tops) { break; } - case Declaration::Kind::VariableDeclaration: { + case DeclarationKind::VariableDeclaration: { auto& var = cast(*d); // Associate the variable name with it's declared type in the // compile-time symbol table. diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index c5fda37bc4fa..a8b51d0a51f1 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -131,9 +131,9 @@ %type > maybe_empty_tuple_pattern %type > paren_pattern_base %type > paren_pattern_contents -%type > alternative -%type >> alternative_list -%type >> alternative_list_contents +%type > alternative +%type >> alternative_list +%type >> alternative_list_contents %type > clause %type > clause_list @@ -683,13 +683,10 @@ member_list: ; alternative: identifier tuple - { - $$ = arena->New(context.source_loc(), $1, - $2); - } + { $$ = arena->New(context.source_loc(), $1, $2); } | identifier { - $$ = arena->New( + $$ = arena->New( context.source_loc(), $1, arena->New(context.source_loc())); }